cen64/ai/context.c
Tyler J. Stachecki 384f06d369 OpenAL: Try to dynamically adjust frequency.
Most carts only seem to use one frequency. Add a dirty
hack to change the frequency on the fly so things sound
less horrendous.
2016-01-25 03:36:11 -05:00

124 lines
3.3 KiB
C

//
// ai/context.c: Sound card context management.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "common.h"
#include "ai/context.h"
#include <AL/al.h>
#include <AL/alc.h>
// Creates and initializes an audio context.
int ai_context_create(struct cen64_ai_context *context) {
uint8_t buf[8];
unsigned i;
context->cur_frequency = 31985;
if ((context->dev = alcOpenDevice(NULL)) == NULL) {
printf("Failed to open the OpenAL device.\n");
return 1;
}
if ((context->ctx = alcCreateContext(context->dev, NULL)) == NULL) {
printf("Failed to create an OpenAL context.\n");
alcCloseDevice(context->dev);
return 1;
}
alcMakeContextCurrent(context->ctx);
// Context/device is setup, create some buffers and a source.
alGenBuffers(sizeof(context->buffers) / sizeof(*context->buffers),
context->buffers);
if (alGetError() != AL_NO_ERROR) {
alcMakeContextCurrent(NULL);
alcDestroyContext(context->ctx);
alcCloseDevice(context->dev);
}
alGenSources(1, &context->source);
if (alGetError() != AL_NO_ERROR) {
alDeleteBuffers(sizeof(context->buffers) / sizeof(*context->buffers),
context->buffers);
alcMakeContextCurrent(NULL);
alcDestroyContext(context->ctx);
alcCloseDevice(context->dev);
}
// Queue/prime buffers, clear them to prevent pops.
// Playing a little test also allows us to verify
// that we (probably) won't get weird OpenAL errors
// later on if things work now.
memset(buf, 0x0, sizeof(buf));
for (i = 0; i < sizeof(context->buffers) / sizeof(*context->buffers); i++)
alBufferData(context->buffers[i], AL_FORMAT_STEREO16,
buf, sizeof(buf), context->cur_frequency);
alSourceQueueBuffers(context->source,
sizeof(context->buffers) / sizeof(*context->buffers),
context->buffers);
alSourcePlay(context->source);
if (alGetError() != AL_NO_ERROR) {
ai_context_destroy(context);
return 1;
}
// Now wait for them to drain.
while (1) {
ALint val;
alGetSourcei(context->source, AL_BUFFERS_PROCESSED, &val);
if (val == (sizeof(context->buffers) / sizeof(*context->buffers)))
break;
}
if (alGetError() != AL_NO_ERROR) {
ai_context_destroy(context);
return 1;
}
context->unqueued_buffers = 0;
return 0;
}
// Destroys audio contexts made with ai_context_create.
void ai_context_destroy(struct cen64_ai_context *context) {
alDeleteSources(1, &context->source);
alDeleteBuffers(sizeof(context->buffers) / sizeof(*context->buffers),
context->buffers);
alcMakeContextCurrent(NULL);
alcDestroyContext(context->ctx);
alcCloseDevice(context->dev);
}
// Generate buffers for some given frequency.
int ai_switch_frequency(struct cen64_ai_context *context, ALint frequency) {
alDeleteSources(1, &context->source);
alDeleteBuffers(sizeof(context->buffers) / sizeof(*context->buffers),
context->buffers);
alGenBuffers(sizeof(context->buffers) / sizeof(*context->buffers),
context->buffers);
alGenSources(1, &context->source);
context->cur_frequency = frequency;
context->unqueued_buffers = sizeof(context->buffers) /
sizeof(*context->buffers);
return 0;
}