GBA Audio: Audio buffer sizes are now correct sizes for both sample rates

This commit is contained in:
Jeffrey Pfau 2014-12-21 21:30:59 -08:00
parent 892a5e5d5e
commit c91c46ce97
9 changed files with 35 additions and 13 deletions

View File

@ -22,6 +22,7 @@ Bugfixes:
- GBA Memory: Properly initialize 1 Mb flash, and add debug logging - GBA Memory: Properly initialize 1 Mb flash, and add debug logging
- Qt: Properly set default video recording settings - Qt: Properly set default video recording settings
- GBA Audio: Make larger buffer sizes than 2048 actually work properly - GBA Audio: Make larger buffer sizes than 2048 actually work properly
- GBA Audio: Audio buffer sizes are now correct sizes for both sample rates
Misc: Misc:
- Qt: Disable sync to video by default - Qt: Disable sync to video by default
- GBA: Exit cleanly on FATAL if the port supports it - GBA: Exit cleanly on FATAL if the port supports it

View File

@ -861,6 +861,6 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState
audio->nextSample = state->audio.nextSample; audio->nextSample = state->audio.nextSample;
} }
float GBAAudioCalculateRatio(struct GBAAudio* audio, float desiredFPS, float desiredSampleRate) { float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRate) {
return desiredSampleRate * GBA_ARM7TDMI_FREQUENCY / (VIDEO_TOTAL_LENGTH * desiredFPS * audio->sampleRate); return desiredSampleRate * GBA_ARM7TDMI_FREQUENCY / (VIDEO_TOTAL_LENGTH * desiredFPS * inputSampleRate);
} }

View File

@ -263,6 +263,6 @@ struct GBASerializedState;
void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state); void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state);
void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state); void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state);
float GBAAudioCalculateRatio(struct GBAAudio* audio, float desiredFPS, float desiredSampleRatio); float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRatio);
#endif #endif

View File

@ -10,11 +10,11 @@
#include <libavresample/avresample.h> #include <libavresample/avresample.h>
#include <libavutil/opt.h> #include <libavutil/opt.h>
struct AVAudioResampleContext* GBAAudioOpenLAVR(struct GBAAudio* audio, unsigned outputRate) { struct AVAudioResampleContext* GBAAudioOpenLAVR(unsigned inputRate, unsigned outputRate) {
AVAudioResampleContext *avr = avresample_alloc_context(); AVAudioResampleContext *avr = avresample_alloc_context();
av_opt_set_int(avr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0); av_opt_set_int(avr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(avr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); av_opt_set_int(avr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(avr, "in_sample_rate", audio->sampleRate, 0); av_opt_set_int(avr, "in_sample_rate", inputRate, 0);
av_opt_set_int(avr, "out_sample_rate", outputRate, 0); av_opt_set_int(avr, "out_sample_rate", outputRate, 0);
av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16P, 0); av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16P, 0);
av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
@ -25,6 +25,17 @@ struct AVAudioResampleContext* GBAAudioOpenLAVR(struct GBAAudio* audio, unsigned
return avr; return avr;
} }
struct AVAudioResampleContext* GBAAudioReopenLAVR(struct AVAudioResampleContext* avr, unsigned inputRate, unsigned outputRate) {
avresample_close(avr);
av_opt_set_int(avr, "in_sample_rate", inputRate, 0);
av_opt_set_int(avr, "out_sample_rate", outputRate, 0);
if (avresample_open(avr)) {
avresample_free(&avr);
return 0;
}
return avr;
}
unsigned GBAAudioResampleLAVR(struct GBAAudio* audio, struct AVAudioResampleContext* avr, struct GBAStereoSample* output, unsigned nSamples) { unsigned GBAAudioResampleLAVR(struct GBAAudio* audio, struct AVAudioResampleContext* avr, struct GBAStereoSample* output, unsigned nSamples) {
int16_t left[GBA_AUDIO_SAMPLES]; int16_t left[GBA_AUDIO_SAMPLES];
int16_t right[GBA_AUDIO_SAMPLES]; int16_t right[GBA_AUDIO_SAMPLES];

View File

@ -10,7 +10,8 @@ struct AVAudioResampleContext;
struct GBAAudio; struct GBAAudio;
struct GBAStereoSample; struct GBAStereoSample;
struct AVAudioResampleContext* GBAAudioOpenLAVR(struct GBAAudio* audio, unsigned outputRate); struct AVAudioResampleContext* GBAAudioOpenLAVR(unsigned inputRate, unsigned outputRate);
struct AVAudioResampleContext* GBAAudioReopenLAVR(struct AVAudioResampleContext* avr, unsigned inputRate, unsigned outputRate);
unsigned GBAAudioResampleLAVR(struct GBAAudio* audio, struct AVAudioResampleContext* avr, struct GBAStereoSample* output, unsigned nSamples); unsigned GBAAudioResampleLAVR(struct GBAAudio* audio, struct AVAudioResampleContext* avr, struct GBAStereoSample* output, unsigned nSamples);
#endif #endif

View File

@ -26,7 +26,7 @@ void AudioDevice::setFormat(const QAudioFormat& format) {
return; return;
} }
GBAThreadInterrupt(m_context); GBAThreadInterrupt(m_context);
m_ratio = GBAAudioCalculateRatio(&m_context->gba->audio, m_context->fpsTarget, format.sampleRate()); m_ratio = GBAAudioCalculateRatio(m_context->gba->audio.sampleRate, m_context->fpsTarget, format.sampleRate());
GBAThreadContinue(m_context); GBAThreadContinue(m_context);
} }

View File

@ -278,11 +278,13 @@ void GameController::keyReleased(int key) {
void GameController::setAudioBufferSamples(int samples) { void GameController::setAudioBufferSamples(int samples) {
if (m_gameOpen) { if (m_gameOpen) {
threadInterrupt(); threadInterrupt();
m_threadContext.audioBuffers = samples; float ratio = GBAAudioCalculateRatio(m_threadContext.gba->audio.sampleRate, m_threadContext.fpsTarget, 44100);
GBAAudioResizeBuffer(&m_threadContext.gba->audio, samples); m_threadContext.audioBuffers = samples / ratio;
GBAAudioResizeBuffer(&m_threadContext.gba->audio, samples / ratio);
threadContinue(); threadContinue();
} else { } else {
m_threadContext.audioBuffers = samples; float ratio = GBAAudioCalculateRatio(0x8000, m_threadContext.fpsTarget, 44100);
m_threadContext.audioBuffers = samples / ratio;
} }
QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples)); QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples));

View File

@ -38,6 +38,8 @@ bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContex
} }
context->thread = threadContext; context->thread = threadContext;
context->samples = context->obtainedSpec.samples; context->samples = context->obtainedSpec.samples;
float ratio = GBAAudioCalculateRatio(0x8000, threadContext->fpsTarget, 44100);
threadContext->audioBuffers = context->samples / ratio;
if (context->samples > threadContext->audioBuffers) { if (context->samples > threadContext->audioBuffers) {
threadContext->audioBuffers = context->samples * 2; threadContext->audioBuffers = context->samples * 2;
} }
@ -77,7 +79,7 @@ static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
return; return;
} }
#ifndef USE_FFMPEG #ifndef USE_FFMPEG
audioContext->ratio = GBAAudioCalculateRatio(&audioContext->thread->gba->audio, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq); audioContext->ratio = GBAAudioCalculateRatio(audioContext->thread->gba->audio.sampleRate, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq);
if (audioContext->ratio == INFINITY) { if (audioContext->ratio == INFINITY) {
memset(data, 0, len); memset(data, 0, len);
return; return;
@ -88,12 +90,17 @@ static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
GBAAudioResampleNN(&audioContext->thread->gba->audio, audioContext->ratio, &audioContext->drift, ssamples, len); GBAAudioResampleNN(&audioContext->thread->gba->audio, audioContext->ratio, &audioContext->drift, ssamples, len);
} }
#else #else
float ratio = GBAAudioCalculateRatio(audioContext->thread->gba->audio.sampleRate, audioContext->thread->fpsTarget, audioContext->thread->gba->audio.sampleRate);
if (!audioContext->avr) { if (!audioContext->avr) {
if (!audioContext->thread->gba->audio.sampleRate) { if (!audioContext->thread->gba->audio.sampleRate) {
memset(data, 0, len); memset(data, 0, len);
return; return;
} }
audioContext->avr = GBAAudioOpenLAVR(&audioContext->thread->gba->audio, audioContext->obtainedSpec.freq); audioContext->ratio = ratio;
audioContext->avr = GBAAudioOpenLAVR(audioContext->thread->gba->audio.sampleRate / ratio, audioContext->obtainedSpec.freq);
} else if (ratio != audioContext->ratio) {
audioContext->ratio = ratio;
audioContext->avr = GBAAudioReopenLAVR(audioContext->avr, audioContext->thread->gba->audio.sampleRate / ratio, audioContext->obtainedSpec.freq);
} }
struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data; struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data;
len /= 2 * audioContext->obtainedSpec.channels; len /= 2 * audioContext->obtainedSpec.channels;

View File

@ -17,9 +17,9 @@ struct GBASDLAudio {
// State // State
SDL_AudioSpec desiredSpec; SDL_AudioSpec desiredSpec;
SDL_AudioSpec obtainedSpec; SDL_AudioSpec obtainedSpec;
float ratio;
#ifndef USE_FFMPEG #ifndef USE_FFMPEG
float drift; float drift;
float ratio;
#else #else
struct AVAudioResampleContext* avr; struct AVAudioResampleContext* avr;
#endif #endif