Show More
Commit Description:
Tweak UI appearance.
Commit Description:
Tweak UI appearance.
References:
File last commit:
Show/Diff file:
Action:
FNA/lib/FAudio/utils/testreverb/audio_faudio.cpp
261 lines | 6.4 KiB | text/x-c | CppLexer
261 lines | 6.4 KiB | text/x-c | CppLexer
r0 | #include "audio.h" | |||
#include <FAudio.h> | ||||
#include <FAudioFX.h> | ||||
#include <SDL.h> | ||||
struct AudioContext | ||||
{ | ||||
FAudio *faudio; | ||||
bool output_5p1; | ||||
AudioVoiceType effect_on_voice; | ||||
FAudioMasteringVoice *mastering_voice; | ||||
FAudioSubmixVoice *submix_voice; | ||||
FAudioSourceVoice *source_voice; | ||||
FAudioVoice *voices[3]; | ||||
unsigned int wav_channels; | ||||
unsigned int wav_samplerate; | ||||
drwav_uint64 wav_sample_count; | ||||
float * wav_samples; | ||||
FAudioBuffer buffer; | ||||
FAudioEffectDescriptor reverb_effect; | ||||
FAudioEffectChain effect_chain; | ||||
ReverbParameters reverb_params; | ||||
bool reverb_enabled; | ||||
}; | ||||
void faudio_destroy_context(AudioContext *context) | ||||
{ | ||||
if (context != NULL) | ||||
{ | ||||
FAudioVoice_DestroyVoice(context->source_voice); | ||||
FAudioVoice_DestroyVoice(context->submix_voice); | ||||
FAudioVoice_DestroyVoice(context->mastering_voice); | ||||
FAudio_Release(context->faudio); | ||||
delete context; | ||||
} | ||||
} | ||||
void faudio_create_voice(AudioContext *context, float *buffer, size_t buffer_size, int sample_rate, int num_channels) | ||||
{ | ||||
// create reverb effect | ||||
FAPO *fapo = NULL; | ||||
uint32_t hr = FAudioCreateReverb(&fapo, 0); | ||||
if (hr != 0) | ||||
{ | ||||
return; | ||||
} | ||||
// create effect chain | ||||
context->reverb_effect.InitialState = context->reverb_enabled; | ||||
context->reverb_effect.OutputChannels = (context->output_5p1) ? 6 : context->wav_channels; | ||||
context->reverb_effect.pEffect = fapo; | ||||
context->effect_chain.EffectCount = 1; | ||||
context->effect_chain.pEffectDescriptors = &context->reverb_effect; | ||||
FAudioEffectChain *voice_effect[3] = {NULL, NULL, NULL}; | ||||
voice_effect[context->effect_on_voice] = &context->effect_chain; | ||||
// create a mastering voice | ||||
uint32_t inChannels = context->wav_channels; | ||||
if (context->output_5p1 && context->effect_on_voice != AudioVoiceType_Master) | ||||
{ | ||||
inChannels = 6; | ||||
} | ||||
hr = FAudio_CreateMasteringVoice( | ||||
context->faudio, | ||||
&context->mastering_voice, | ||||
inChannels, | ||||
FAUDIO_DEFAULT_SAMPLERATE, | ||||
0, | ||||
0, | ||||
voice_effect[AudioVoiceType_Master] | ||||
); | ||||
if (hr != 0) | ||||
{ | ||||
return; | ||||
} | ||||
context->voices[AudioVoiceType_Master] = context->mastering_voice; | ||||
// create a submix voice | ||||
inChannels = context->wav_channels; | ||||
if (context->output_5p1 && context->effect_on_voice == AudioVoiceType_Source) | ||||
{ | ||||
inChannels = 6; | ||||
} | ||||
hr = FAudio_CreateSubmixVoice( | ||||
context->faudio, | ||||
&context->submix_voice, | ||||
inChannels, | ||||
SAMPLERATE, | ||||
0, | ||||
0, | ||||
NULL, | ||||
voice_effect[AudioVoiceType_Submix] | ||||
); | ||||
context->voices[AudioVoiceType_Submix] = context->submix_voice; | ||||
FAudioVoice_SetVolume(context->submix_voice, 1.0f, FAUDIO_COMMIT_NOW); | ||||
// create a source voice | ||||
FAudioSendDescriptor desc = {0, context->submix_voice}; | ||||
FAudioVoiceSends sends = {1, &desc}; | ||||
FAudioWaveFormatEx waveFormat; | ||||
waveFormat.wFormatTag = 3; | ||||
waveFormat.nChannels = num_channels; | ||||
waveFormat.nSamplesPerSec = sample_rate; | ||||
waveFormat.nAvgBytesPerSec = sample_rate * 4; | ||||
waveFormat.nBlockAlign = num_channels * 4; | ||||
waveFormat.wBitsPerSample = 32; | ||||
waveFormat.cbSize = 0; | ||||
hr = FAudio_CreateSourceVoice( | ||||
context->faudio, | ||||
&context->source_voice, | ||||
&waveFormat, | ||||
0, | ||||
FAUDIO_DEFAULT_FREQ_RATIO, | ||||
NULL, | ||||
&sends, | ||||
voice_effect[AudioVoiceType_Source] | ||||
); | ||||
if (hr != 0) | ||||
{ | ||||
return; | ||||
} | ||||
context->voices[AudioVoiceType_Source] = context->source_voice; | ||||
FAudioVoice_SetVolume(context->source_voice, 1.0f, FAUDIO_COMMIT_NOW); | ||||
// submit the array | ||||
SDL_zero(context->buffer); | ||||
context->buffer.AudioBytes = 4 * buffer_size * num_channels; | ||||
context->buffer.pAudioData = (uint8_t *)buffer; | ||||
context->buffer.Flags = FAUDIO_END_OF_STREAM; | ||||
context->buffer.PlayBegin = 0; | ||||
context->buffer.PlayLength = buffer_size; | ||||
context->buffer.LoopBegin = 0; | ||||
context->buffer.LoopLength = 0; | ||||
context->buffer.LoopCount = 0; | ||||
} | ||||
void faudio_reverb_set_params(AudioContext *context) | ||||
{ | ||||
FAudioVoice_SetEffectParameters( | ||||
context->voices[context->effect_on_voice], | ||||
0, | ||||
&context->reverb_params, | ||||
sizeof(context->reverb_params), | ||||
FAUDIO_COMMIT_NOW | ||||
); | ||||
} | ||||
void faudio_wave_load(AudioContext *context, AudioSampleWave sample, bool stereo) | ||||
{ | ||||
if (context->source_voice) | ||||
{ | ||||
FAudioVoice_DestroyVoice(context->source_voice); | ||||
FAudioVoice_DestroyVoice(context->submix_voice); | ||||
FAudioVoice_DestroyVoice(context->mastering_voice); | ||||
} | ||||
context->wav_samples = WAVS_Open( | ||||
sample, | ||||
stereo, | ||||
&context->wav_channels, | ||||
&context->wav_samplerate, | ||||
&context->wav_sample_count | ||||
); | ||||
context->wav_sample_count /= context->wav_channels; | ||||
audio_create_voice(context, context->wav_samples, context->wav_sample_count, context->wav_samplerate, context->wav_channels); | ||||
faudio_reverb_set_params(context); | ||||
} | ||||
void faudio_wave_play(AudioContext *context) | ||||
{ | ||||
FAudioSourceVoice_Stop(context->source_voice, 0, FAUDIO_COMMIT_NOW); | ||||
FAudioSourceVoice_FlushSourceBuffers(context->source_voice); | ||||
FAudioSourceVoice_SubmitSourceBuffer(context->source_voice, &context->buffer, NULL); | ||||
FAudioSourceVoice_Start(context->source_voice, 0, FAUDIO_COMMIT_NOW); | ||||
} | ||||
void faudio_wave_stop(AudioContext *context) | ||||
{ | ||||
FAudioSourceVoice_Stop(context->source_voice, FAUDIO_PLAY_TAILS, FAUDIO_COMMIT_NOW); | ||||
} | ||||
void faudio_effect_change(AudioContext *context, bool enabled, ReverbParameters *params) | ||||
{ | ||||
if (context->reverb_enabled && !enabled) | ||||
{ | ||||
FAudioVoice_DisableEffect( | ||||
context->voices[context->effect_on_voice], | ||||
0, | ||||
FAUDIO_COMMIT_NOW | ||||
); | ||||
context->reverb_enabled = enabled; | ||||
} | ||||
else if (!context->reverb_enabled && enabled) | ||||
{ | ||||
FAudioVoice_EnableEffect( | ||||
context->voices[context->effect_on_voice], | ||||
0, | ||||
FAUDIO_COMMIT_NOW | ||||
); | ||||
context->reverb_enabled = enabled; | ||||
} | ||||
context->reverb_params = *params; | ||||
faudio_reverb_set_params(context); | ||||
} | ||||
AudioContext *faudio_create_context(bool output_5p1, AudioVoiceType effect_on_voice) | ||||
{ | ||||
// setup function pointers | ||||
audio_destroy_context = faudio_destroy_context; | ||||
audio_create_voice = faudio_create_voice; | ||||
audio_wave_load = faudio_wave_load; | ||||
audio_wave_play = faudio_wave_play; | ||||
audio_wave_stop = faudio_wave_stop; | ||||
audio_effect_change = faudio_effect_change; | ||||
// create Faudio object | ||||
FAudio *faudio; | ||||
uint32_t hr = FAudioCreate(&faudio, 0, FAUDIO_DEFAULT_PROCESSOR); | ||||
if (hr != 0) | ||||
{ | ||||
return NULL; | ||||
} | ||||
// return a context object | ||||
AudioContext *context = new AudioContext(); | ||||
context->faudio = faudio; | ||||
context->output_5p1 = output_5p1; | ||||
context->effect_on_voice = effect_on_voice; | ||||
context->source_voice = NULL; | ||||
context->submix_voice = NULL; | ||||
context->mastering_voice = NULL; | ||||
context->wav_samples = NULL; | ||||
SDL_zero(context->reverb_params); | ||||
context->reverb_enabled = false; | ||||
// load the first wave | ||||
audio_wave_load(context, (AudioSampleWave) 0, false); | ||||
return context; | ||||
} | ||||