void AliveRenderAudio(float * AudioStream, int StreamLength) { static float tick = 0; static int note = 0; AliveAudioSoundbank * currentSoundbank = AliveAudio::m_CurrentSoundbank; AliveAudio::voiceListMutex.lock(); int voiceCount = AliveAudio::m_Voices.size(); AliveAudioVoice ** rawPointer = AliveAudio::m_Voices.data(); // Real nice speed boost here. for (int i = 0; i < StreamLength; i += 2) { for (int v = 0; v < voiceCount; v++) { AliveAudioVoice * voice = rawPointer[v]; // Raw pointer skips all that vector bottleneck crap voice->f_TrackDelay--; if (voice->m_UsesNoteOffDelay) voice->f_NoteOffDelay--; if (voice->m_UsesNoteOffDelay && voice->f_NoteOffDelay <= 0 && voice->b_NoteOn == true) { voice->b_NoteOn = false; //printf("off"); } if (voice->b_Dead || voice->f_TrackDelay > 0) continue; float centerPan = voice->m_Tone->f_Pan; float leftPan = 1.0f; float rightPan = 1.0f; if (centerPan > 0) { leftPan = 1.0f - abs(centerPan); } if (centerPan < 0) { rightPan = 1.0f - abs(centerPan); } float s = voice->GetSample(); float leftSample = s * leftPan; float rightSample = s * rightPan; SDL_MixAudioFormat((Uint8 *)(AudioStream + i), (const Uint8*)&leftSample, AUDIO_F32, sizeof(float), 37); // Left Channel SDL_MixAudioFormat((Uint8 *)(AudioStream + i + 1), (const Uint8*)&rightSample, AUDIO_F32, sizeof(float), 37); // Right Channel } AliveAudio::currentSampleIndex++; } AliveAudio::voiceListMutex.unlock(); CleanVoices(); }
static void AUD_Callback(void* data, Uint8* stream, int len) { AUD_Sound* sound = data; if (sound->curlen <= 0) { return; } int real_len = (sound->curlen > len ? len : sound->curlen); memset(stream, 0, len); SDL_MixAudioFormat(stream, sound->cur, sound->spec.format, real_len, sound->volume); if (real_len == len) { sound->cur += real_len; sound->curlen -= real_len; } else { stream += real_len; len -= real_len; if (sound->loop) { sound->cur = sound->buf; sound->curlen = sound->buflen; SDL_MixAudioFormat(stream, sound->cur, sound->spec.format, len, sound->volume); sound->cur += len; sound->curlen -= len; } else sound->curlen = 0; } }
/* Play some of a stream previously started with OGG_play() */ int OGG_playAudio(OGG_music *music, Uint8 *snd, int len) { int mixable; while((len > 0) && music->playing) { if(!music->len_available) OGG_getsome(music); mixable = len; if(mixable > music->len_available) mixable = music->len_available; if(music->volume == MIX_MAX_VOLUME) SDL_memcpy(snd, music->snd_available, (size_t)mixable); else { SDL_MixAudioFormat(snd, music->snd_available, mixer.format, (Uint32)mixable, music->volume); } music->len_available -= mixable; music->snd_available += mixable; len -= mixable; snd += mixable; } return len; }
/* Play some of a stream previously started with GME_play() */ int GME_playAudio(struct MUSIC_GME *music, Uint8 *stream, int len) { if(music==NULL) return 1; if(music->game_emu==NULL) return 1; if(music->playing==-1) return 1; if( len<0 ) return 0; int srgArraySize = len/music->cvt.len_ratio; short buf[srgArraySize]; int srcLen = (int)((double)(len/2)/music->cvt.len_ratio); char *err = (char*)gme_play( music->game_emu, srcLen, buf ); if( err != NULL) { Mix_SetError("GAME-EMU: %s", err); return 0; } int dest_len = srcLen*2; if( music->cvt.needed ) { music->cvt.len = dest_len; music->cvt.buf = (Uint8*)buf; SDL_ConvertAudio(&music->cvt); dest_len = music->cvt.len_cvt; } if ( music->volume == MIX_MAX_VOLUME ) { SDL_memcpy(stream, (Uint8*)buf, dest_len); } else { SDL_MixAudioFormat(stream, (Uint8*)buf, mixer.format, dest_len, music->volume); } return len-dest_len; }
static void Audio_mixer (void* udata, Uint8* buf, int size) { (void)udata; Zero(buf, size, Uint8); if (!_audio.buf) { _audio.buf = New(size, Uint8); _audio.spec.samples = size; } MusicResource* music = _audio.music; SmackerResource* smacker = SDL_AtomicGetPtr((void**)&_audio.smacker); if (music) { MusicResource_play(music, _audio.buf, size); SDL_MixAudioFormat(buf, _audio.buf, AUDIO_S16LSB, size, _audio.volume); } if (smacker) { SmackerResource_play_audio(smacker, _audio.buf, size); SDL_MixAudioFormat(buf, _audio.buf, AUDIO_S16LSB, size, _audio.volume); } }
/* callback for SDL audio - calls all our other callbacks and mixes them */ static void channel_mixer_cb(void *extra, Uint8 *stream, int len) { extern SDL_AudioFormat deviceFormat; // TODO: get this Uint8 mix[len]; memset(stream, 0, len); /* fill base with silence */ /* mix in every channel */ for (i = 0; i < channel_count; i++) { int volume = channel_volume[i] * SDL_MIX_MAXVOLUME; if (volume <= 0) continue; channel_callback[i](extra, mix, len); SDL_MixAudioFormat(stream, mix, deviceFormat, len, volume); } }
void sdl_audio_callback (void *userdata, Uint8 * stream, int len) { int i; int copy_amt; SDL_memset(stream, mixer.outputSpec.silence, len); /* initialize buffer to silence */ /* for each channel, mix in whatever is playing on that channel */ for (i = 0; i < NumChannels; i++) { if (mixer.channels[i].position == NULL) { /* if no sound is playing on this channel */ continue; /* nothing to do for this channel */ } /* copy len bytes to the buffer, unless we have fewer than len bytes remaining */ copy_amt = mixer.channels[i].remaining < len ? mixer.channels[i].remaining : len; /* mix this sound effect with the output */ SDL_MixAudioFormat(stream, mixer.channels[i].position, mixer.outputSpec.format, copy_amt, sfx_volume * mixer.channels[i].volume); /* update buffer position in sound effect and the number of bytes left */ mixer.channels[i].position += copy_amt; mixer.channels[i].remaining -= copy_amt; /* did we finish playing the sound effect ? */ if (mixer.channels[i].remaining == 0) { if (mixer.channels[i].loops != 0) { mixer.channels[i].position = mixer.channels[i].s->buffer.get(); mixer.channels[i].remaining = mixer.channels[i].s->length; if (mixer.channels[i].loops != -1) mixer.channels[i].loops--; } else { sdl_stop_channel(i); } } } }
/* Called from SDL's audio system. Supplies sound input with data by mixing together all currently playing sound effects. */ void audioCallback(void *userdata, Uint8 * stream, int len) { int i; int copy_amt; SDL_memset(stream, mixer.outputSpec.silence, len); /* initialize buffer to silence */ /* for each channel, mix in whatever is playing on that channel */ for (i = 0; i < NUM_CHANNELS; i++) { if (mixer.channels[i].position == NULL) { /* if no sound is playing on this channel */ continue; /* nothing to do for this channel */ } /* copy len bytes to the buffer, unless we have fewer than len bytes remaining */ copy_amt = mixer.channels[i].remaining < len ? mixer.channels[i].remaining : len; /* mix this sound effect with the output */ SDL_MixAudioFormat(stream, mixer.channels[i].position, mixer.outputSpec.format, copy_amt, 150); /* update buffer position in sound effect and the number of bytes left */ mixer.channels[i].position += copy_amt; mixer.channels[i].remaining -= copy_amt; /* did we finish playing the sound effect ? */ if (mixer.channels[i].remaining == 0) { mixer.channels[i].position = NULL; /* indicates no sound playing on channel anymore */ mixer.numSoundsPlaying--; if (mixer.numSoundsPlaying == 0) { /* if no sounds left playing, pause audio callback */ SDL_PauseAudio(1); } } } }
void Mixer::MixChannel(Channel& channel, uint8* data, int length) { // Do not mix channel if channel is a sound and sound is disabled if (channel.group == MIXER_GROUP_SOUND && !gConfigSound.sound_enabled) { return; } if (channel.source && channel.source->Length() > 0 && !channel.done) { AudioFormat streamformat = channel.source->Format(); int loaded = 0; SDL_AudioCVT cvt; cvt.len_ratio = 1; do { int samplesize = format.channels * format.BytesPerSample(); int samples = length / samplesize; int samplesloaded = loaded / samplesize; double rate = 1; if (format.format == AUDIO_S16SYS) { rate = channel.rate; } int samplestoread = (int)((samples - samplesloaded) * rate); int lengthloaded = 0; if (channel.offset < channel.source->Length()) { bool mustconvert = false; if (MustConvert(*channel.source)) { if (SDL_BuildAudioCVT(&cvt, streamformat.format, streamformat.channels, streamformat.freq, Mixer::format.format, Mixer::format.channels, Mixer::format.freq) == -1) { break; } mustconvert = true; } const uint8* datastream = 0; int toread = (int)(samplestoread / cvt.len_ratio) * samplesize; int readfromstream = (channel.source->GetSome(channel.offset, &datastream, toread)); if (readfromstream == 0) { break; } uint8* dataconverted = 0; const uint8* tomix = 0; if (mustconvert) { // tofix: there seems to be an issue with converting audio using SDL_ConvertAudio in the callback vs preconverted, can cause pops and static depending on sample rate and channels if (Convert(cvt, datastream, readfromstream, &dataconverted)) { tomix = dataconverted; lengthloaded = cvt.len_cvt; } else { break; } } else { tomix = datastream; lengthloaded = readfromstream; } bool effectbufferloaded = false; if (rate != 1 && format.format == AUDIO_S16SYS) { int in_len = (int)((double)lengthloaded / samplesize); int out_len = samples; if (!channel.resampler) { channel.resampler = speex_resampler_init(format.channels, format.freq, format.freq, 0, 0); } if (readfromstream == toread) { // use buffer lengths for conversion ratio so that it fits exactly speex_resampler_set_rate(channel.resampler, in_len, samples - samplesloaded); } else { // reached end of stream so we cant use buffer length as resampling ratio speex_resampler_set_rate(channel.resampler, format.freq, (int)(format.freq * (1 / rate))); } speex_resampler_process_interleaved_int(channel.resampler, (const spx_int16_t*)tomix, (spx_uint32_t*)&in_len, (spx_int16_t*)effectbuffer, (spx_uint32_t*)&out_len); effectbufferloaded = true; tomix = effectbuffer; lengthloaded = (out_len * samplesize); } if (channel.pan != 0.5f && format.channels == 2) { if (!effectbufferloaded) { memcpy(effectbuffer, tomix, lengthloaded); effectbufferloaded = true; tomix = effectbuffer; } switch (format.format) { case AUDIO_S16SYS: EffectPanS16(channel, (sint16*)effectbuffer, lengthloaded / samplesize); break; case AUDIO_U8: EffectPanU8(channel, (uint8*)effectbuffer, lengthloaded / samplesize); break; } } int mixlength = lengthloaded; if (loaded + mixlength > length) { mixlength = length - loaded; } float volumeadjust = volume; volumeadjust *= (gConfigSound.master_volume / 100.0f); switch (channel.group) { case MIXER_GROUP_SOUND: volumeadjust *= (gConfigSound.sound_volume / 100.0f); // Cap sound volume on title screen so music is more audible if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) { volumeadjust = Math::Min(volumeadjust, 0.75f); } break; case MIXER_GROUP_RIDE_MUSIC: volumeadjust *= (gConfigSound.ride_music_volume / 100.0f); break; } int startvolume = (int)(channel.oldvolume * volumeadjust); int endvolume = (int)(channel.volume * volumeadjust); if (channel.stopping) { endvolume = 0; } int mixvolume = (int)(channel.volume * volumeadjust); if (startvolume != endvolume) { // fade between volume levels to smooth out sound and minimize clicks from sudden volume changes if (!effectbufferloaded) { memcpy(effectbuffer, tomix, lengthloaded); effectbufferloaded = true; tomix = effectbuffer; } mixvolume = SDL_MIX_MAXVOLUME; // set to max since we are adjusting the volume ourselves int fadelength = mixlength / format.BytesPerSample(); switch (format.format) { case AUDIO_S16SYS: EffectFadeS16((sint16*)effectbuffer, fadelength, startvolume, endvolume); break; case AUDIO_U8: EffectFadeU8((uint8*)effectbuffer, fadelength, startvolume, endvolume); break; } } SDL_MixAudioFormat(&data[loaded], tomix, format.format, mixlength, mixvolume); if (dataconverted) { delete[] dataconverted; } channel.offset += readfromstream; } loaded += lengthloaded; if (channel.loop != 0 && channel.offset >= channel.source->Length()) { if (channel.loop != -1) { channel.loop--; } channel.offset = 0; } } while(loaded < length && channel.loop != 0 && !channel.stopping); channel.oldvolume = channel.volume; channel.oldvolume_l = channel.volume_l; channel.oldvolume_r = channel.volume_r; if (channel.loop == 0 && channel.offset >= channel.source->Length()) { channel.done = true; } } }
/* Mixing function */ static void mix_channels(void *udata, Uint8 *stream, int len) { Uint8 *mix_input; int i, mixable, volume = SDL_MIX_MAXVOLUME; Uint32 sdl_ticks; #if SDL_VERSION_ATLEAST(1, 3, 0) /* Need to initialize the stream in SDL 1.3+ */ SDL_memset(stream, mixer.silence, len); #endif /* Mix the music (must be done before the channels are added) */ if ( music_active || (mix_music != music_mixer) ) { mix_music(music_data, stream, len); } /* Mix any playing channels... */ sdl_ticks = SDL_GetTicks(); for ( i=0; i<num_channels; ++i ) { if ( !mix_channel[i].paused ) { if ( mix_channel[i].expire > 0 && mix_channel[i].expire < sdl_ticks ) { /* Expiration delay for that channel is reached */ mix_channel[i].playing = 0; mix_channel[i].looping = 0; mix_channel[i].fading = MIX_NO_FADING; mix_channel[i].expire = 0; _Mix_channel_done_playing(i); } else if ( mix_channel[i].fading != MIX_NO_FADING ) { Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade; if ( ticks >= mix_channel[i].fade_length ) { Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */ if( mix_channel[i].fading == MIX_FADING_OUT ) { mix_channel[i].playing = 0; mix_channel[i].looping = 0; mix_channel[i].expire = 0; _Mix_channel_done_playing(i); } mix_channel[i].fading = MIX_NO_FADING; } else { if ( mix_channel[i].fading == MIX_FADING_OUT ) { Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks)) / mix_channel[i].fade_length ); } else { Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length ); } } } if ( mix_channel[i].playing > 0 ) { int index = 0; int remaining = len; while (mix_channel[i].playing > 0 && index < len) { remaining = len - index; volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME; mixable = mix_channel[i].playing; if ( mixable > remaining ) { mixable = remaining; } mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable); SDL_MixAudioFormat(stream+index,mix_input,mixer.format,mixable,volume); if (mix_input != mix_channel[i].samples) SDL_free(mix_input); mix_channel[i].samples += mixable; mix_channel[i].playing -= mixable; index += mixable; /* rcg06072001 Alert app if channel is done playing. */ if (!mix_channel[i].playing && !mix_channel[i].looping) { _Mix_channel_done_playing(i); } } /* If looping the sample and we are at its end, make sure we will still return a full buffer */ while ( mix_channel[i].looping && index < len ) { int alen = mix_channel[i].chunk->alen; remaining = len - index; if (remaining > alen) { remaining = alen; } mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining); SDL_MixAudioFormat(stream+index, mix_input, mixer.format, remaining, volume); if (mix_input != mix_channel[i].chunk->abuf) SDL_free(mix_input); if (mix_channel[i].looping > 0) { --mix_channel[i].looping; } mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining; mix_channel[i].playing = mix_channel[i].chunk->alen - remaining; index += remaining; } if ( ! mix_channel[i].playing && mix_channel[i].looping ) { if (mix_channel[i].looping > 0) { --mix_channel[i].looping; } mix_channel[i].samples = mix_channel[i].chunk->abuf; mix_channel[i].playing = mix_channel[i].chunk->alen; } } } } /* rcg06122001 run posteffects... */ Mix_DoEffects(MIX_CHANNEL_POST, stream, len); if ( mix_postmix ) { mix_postmix(mix_postmix_data, stream, len); } }
void Audio::load_wav(const char* filename) { if (sound_enabled) { clear_wav(); // Load Wav File SDL_AudioSpec wave; uint8_t *data; uint32_t length; pause_audio(); if( SDL_LoadWAV(filename, &wave, &data, &length) == NULL) { wavfile.loaded = 0; resume_audio(); std::cout << "Could not load wav: " << filename << std::endl; return; } SDL_LockAudio(); // Halve Volume Of Wav File uint8_t* data_vol = new uint8_t[length]; SDL_MixAudioFormat(data_vol, data, wave.format, length, SDL_MIX_MAXVOLUME / 2); // WAV File Needs Conversion To Target Format if (wave.format != AUDIO_S16 || wave.channels != 2 || wave.freq != FREQ) { SDL_AudioCVT cvt; SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq, AUDIO_S16, CHANNELS, FREQ); cvt.buf = (uint8_t*) malloc(length*cvt.len_mult); memcpy(cvt.buf, data_vol, length); cvt.len = length; SDL_ConvertAudio(&cvt); SDL_FreeWAV(data); delete[] data_vol; wavfile.data = (int16_t*) cvt.buf; wavfile.length = cvt.len_cvt / 2; wavfile.pos = 0; wavfile.loaded = 1; } // No Conversion Needed else { SDL_FreeWAV(data); wavfile.data = (int16_t*) data_vol; wavfile.length = length / 2; wavfile.pos = 0; wavfile.loaded = 2; } resume_audio(); SDL_UnlockAudio(); } }
void Mixer::MixChannel(Channel& channel, uint8* data, int length) { if (channel.stream) { if (!channel.resampler) { channel.resampler = speex_resampler_init(format.channels, format.freq, format.freq, 0, 0); } AudioFormat channelformat = *channel.stream->Format(); int loaded = 0; SDL_AudioCVT cvt; cvt.len_ratio = 1; do { int samplesize = format.channels * format.BytesPerSample(); int samples = length / samplesize; int samplesloaded = loaded / samplesize; int samplestoread = (int)ceil((samples - samplesloaded) * channel.rate); int lengthloaded = 0; if (channel.offset < channel.stream->Length()) { bool mustconvert = false; if (MustConvert(*channel.stream)) { if (SDL_BuildAudioCVT(&cvt, channelformat.format, channelformat.channels, channelformat.freq, Mixer::format.format, Mixer::format.channels, Mixer::format.freq) == -1) { break; } mustconvert = true; } const uint8* datastream = 0; int readfromstream = (channel.stream->GetSome(channel.offset, &datastream, (int)(((samplestoread) * samplesize) / cvt.len_ratio)) / channelformat.BytesPerSample()) * channelformat.BytesPerSample(); if (readfromstream == 0) { break; } int volume = channel.volume; uint8* dataconverted = 0; const uint8* tomix = 0; if (mustconvert) { if (Convert(cvt, datastream, readfromstream, &dataconverted)) { tomix = dataconverted; lengthloaded = (cvt.len_cvt / samplesize) * samplesize; } else { break; } } else { tomix = datastream; lengthloaded = readfromstream; } bool effectbufferloaded = false; if (channel.rate != 1 && format.format == AUDIO_S16SYS) { int in_len = (int)(ceil((double)lengthloaded / samplesize)); int out_len = samples + 20; // needs some extra, otherwise resampler sometimes doesn't process all the input samples speex_resampler_set_rate(channel.resampler, format.freq, (int)(format.freq * (1 / channel.rate))); speex_resampler_process_interleaved_int(channel.resampler, (const spx_int16_t*)tomix, (spx_uint32_t*)&in_len, (spx_int16_t*)effectbuffer, (spx_uint32_t*)&out_len); effectbufferloaded = true; tomix = effectbuffer; lengthloaded = (out_len * samplesize); } if (channel.pan != 0.5f && format.channels == 2) { if (!effectbufferloaded) { memcpy(effectbuffer, tomix, lengthloaded); effectbufferloaded = true; tomix = effectbuffer; } switch (format.format) { case AUDIO_S16SYS: EffectPanS16(channel, (sint16*)effectbuffer, lengthloaded / samplesize); break; case AUDIO_U8: EffectPanU8(channel, (uint8*)effectbuffer, lengthloaded / samplesize); break; } } int mixlength = lengthloaded; if (loaded + mixlength > length) { mixlength = length - loaded; } SDL_MixAudioFormat(&data[loaded], tomix, format.format, mixlength, volume); if (dataconverted) { delete[] dataconverted; } channel.offset += readfromstream; } loaded += lengthloaded; if (channel.loop != 0 && channel.offset >= channel.stream->Length()) { if (channel.loop != -1) { channel.loop--; } channel.offset = 0; } } while(loaded < length && channel.loop != 0); } }