GBA Audio: Change internal audio sample buffer from 32-bit to 16-bit samples

This commit is contained in:
Jeffrey Pfau 2014-12-21 01:14:30 -08:00
parent 2fb098cb01
commit 660ac6a6be
4 changed files with 84 additions and 25 deletions

View File

@ -18,6 +18,7 @@ Misc:
- Qt: Disable sync to video by default
- GBA: Exit cleanly on FATAL if the port supports it
- Qt: Handle a game crash without crashing
- GBA Audio: Change internal audio sample buffer from 32-bit to 16-bit samples
0.1.0: (2014-12-13)
- Initial release

View File

@ -27,8 +27,8 @@ static int _applyBias(struct GBAAudio* audio, int sample);
static void _sample(struct GBAAudio* audio);
void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
CircleBufferInit(&audio->left, samples * sizeof(int32_t));
CircleBufferInit(&audio->right, samples * sizeof(int32_t));
CircleBufferInit(&audio->left, samples * sizeof(int16_t));
CircleBufferInit(&audio->right, samples * sizeof(int16_t));
CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
}
@ -96,28 +96,28 @@ void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) {
}
GBASyncLockAudio(audio->p->sync);
int32_t buffer[GBA_AUDIO_SAMPLES];
int32_t dummy;
int16_t buffer[GBA_AUDIO_SAMPLES];
int16_t dummy;
size_t read;
size_t i;
read = CircleBufferDump(&audio->left, buffer, sizeof(buffer));
CircleBufferDeinit(&audio->left);
CircleBufferInit(&audio->left, samples * sizeof(int32_t));
for (i = 0; i * sizeof(int32_t) < read; ++i) {
if (!CircleBufferWrite32(&audio->left, buffer[i])) {
CircleBufferRead32(&audio->left, &dummy);
CircleBufferWrite32(&audio->left, buffer[i]);
CircleBufferInit(&audio->left, samples * sizeof(int16_t));
for (i = 0; i * sizeof(int16_t) < read; ++i) {
if (!CircleBufferWrite16(&audio->left, buffer[i])) {
CircleBufferRead16(&audio->left, &dummy);
CircleBufferWrite16(&audio->left, buffer[i]);
}
}
read = CircleBufferDump(&audio->right, buffer, sizeof(buffer));
CircleBufferDeinit(&audio->right);
CircleBufferInit(&audio->right, samples * sizeof(int32_t));
for (i = 0; i * sizeof(int32_t) < read; ++i) {
if (!CircleBufferWrite32(&audio->right, buffer[i])) {
CircleBufferRead32(&audio->right, &dummy);
CircleBufferWrite32(&audio->right, buffer[i]);
CircleBufferInit(&audio->right, samples * sizeof(int16_t));
for (i = 0; i * sizeof(int16_t) < read; ++i) {
if (!CircleBufferWrite16(&audio->right, buffer[i])) {
CircleBufferRead16(&audio->right, &dummy);
CircleBufferWrite16(&audio->right, buffer[i]);
}
}
@ -476,16 +476,16 @@ unsigned GBAAudioCopy(struct GBAAudio* audio, void* left, void* right, unsigned
GBASyncLockAudio(audio->p->sync);
unsigned read = 0;
if (left) {
unsigned readL = CircleBufferRead(&audio->left, left, nSamples * sizeof(int32_t)) >> 2;
unsigned readL = CircleBufferRead(&audio->left, left, nSamples * sizeof(int16_t)) >> 1;
if (readL < nSamples) {
memset((int32_t*) left + readL, 0, nSamples - readL);
memset((int16_t*) left + readL, 0, nSamples - readL);
}
read = readL;
}
if (right) {
unsigned readR = CircleBufferRead(&audio->right, right, nSamples * sizeof(int32_t)) >> 2;
unsigned readR = CircleBufferRead(&audio->right, right, nSamples * sizeof(int16_t)) >> 1;
if (readR < nSamples) {
memset((int32_t*) right + readR, 0, nSamples - readR);
memset((int16_t*) right + readR, 0, nSamples - readR);
}
read = read >= readR ? read : readR;
}
@ -494,8 +494,8 @@ unsigned GBAAudioCopy(struct GBAAudio* audio, void* left, void* right, unsigned
}
unsigned GBAAudioResampleNN(struct GBAAudio* audio, float ratio, float* drift, struct GBAStereoSample* output, unsigned nSamples) {
int32_t left[GBA_AUDIO_SAMPLES];
int32_t right[GBA_AUDIO_SAMPLES];
int16_t left[GBA_AUDIO_SAMPLES];
int16_t right[GBA_AUDIO_SAMPLES];
// toRead is in GBA samples
// TODO: Do this with fixed-point math
@ -685,12 +685,12 @@ static int _applyBias(struct GBAAudio* audio, int sample) {
} else if (sample < 0) {
sample = 0;
}
return (sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) << 6;
return (sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) << 5;
}
static void _sample(struct GBAAudio* audio) {
int32_t sampleLeft = 0;
int32_t sampleRight = 0;
int16_t sampleLeft = 0;
int16_t sampleRight = 0;
int psgShift = 6 - audio->volume;
if (audio->ch1Left) {
@ -748,8 +748,8 @@ static void _sample(struct GBAAudio* audio) {
sampleRight = _applyBias(audio, sampleRight);
GBASyncLockAudio(audio->p->sync);
CircleBufferWrite32(&audio->left, sampleLeft);
CircleBufferWrite32(&audio->right, sampleRight);
CircleBufferWrite16(&audio->left, sampleLeft);
CircleBufferWrite16(&audio->right, sampleRight);
unsigned produced = CircleBufferSize(&audio->left);
struct GBAThread* thread = GBAThreadGetContext();
if (thread && thread->stream) {

View File

@ -97,6 +97,34 @@ int CircleBufferWrite32(struct CircleBuffer* buffer, int32_t value) {
return 4;
}
int CircleBufferWrite16(struct CircleBuffer* buffer, int16_t value) {
int16_t* data = buffer->writePtr;
if (buffer->size + sizeof(int16_t) > buffer->capacity) {
return 0;
}
if ((intptr_t) data & 0x3) {
int written = 0;
written += CircleBufferWrite8(buffer, ((int8_t*) &value)[0]);
written += CircleBufferWrite8(buffer, ((int8_t*) &value)[1]);
return written;
}
*data = value;
++data;
size_t size = (int8_t*) data - (int8_t*) buffer->data;
if (size < buffer->capacity) {
buffer->writePtr = data;
} else {
buffer->writePtr = buffer->data;
}
buffer->size += sizeof(int16_t);
#ifndef NDEBUG
if (!_checkIntegrity(buffer)) {
abort();
}
#endif
return 2;
}
int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value) {
int8_t* data = buffer->readPtr;
if (buffer->size < sizeof(int8_t)) {
@ -119,6 +147,34 @@ int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value) {
return 1;
}
int CircleBufferRead16(struct CircleBuffer* buffer, int16_t* value) {
int16_t* data = buffer->readPtr;
if (buffer->size < sizeof(int16_t)) {
return 0;
}
if ((intptr_t) data & 0x3) {
int read = 0;
read += CircleBufferRead8(buffer, &((int8_t*) value)[0]);
read += CircleBufferRead8(buffer, &((int8_t*) value)[1]);
return read;
}
*value = *data;
++data;
size_t size = (int8_t*) data - (int8_t*) buffer->data;
if (size < buffer->capacity) {
buffer->readPtr = data;
} else {
buffer->readPtr = buffer->data;
}
buffer->size -= sizeof(int16_t);
#ifndef NDEBUG
if (!_checkIntegrity(buffer)) {
abort();
}
#endif
return 2;
}
int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value) {
int32_t* data = buffer->readPtr;
if (buffer->size < sizeof(int32_t)) {

View File

@ -22,8 +22,10 @@ size_t CircleBufferSize(const struct CircleBuffer* buffer);
size_t CircleBufferCapacity(const struct CircleBuffer* buffer);
void CircleBufferClear(struct CircleBuffer* buffer);
int CircleBufferWrite8(struct CircleBuffer* buffer, int8_t value);
int CircleBufferWrite16(struct CircleBuffer* buffer, int16_t value);
int CircleBufferWrite32(struct CircleBuffer* buffer, int32_t value);
int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value);
int CircleBufferRead16(struct CircleBuffer* buffer, int16_t* value);
int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value);
size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length);
size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length);