gbemu/lib/audio.c

128 lines
3.7 KiB
C

#include <audio.h>
#include <math.h>
#include <portaudio.h>
#define SAMPLE_RATE 44100
#define FRAMES_PER_BUFFER 64
#define TABLE_SIZE 44100
#define M_PI 3.14159265
static float sine[TABLE_SIZE];
static unsigned long ind = 0;
static unsigned long ind2 = 0;
static int sq1_on_time;
static int sq1_off_time;
static float sq1 = 1;
static int sq1_timer = 0;
static int sq2_on_time;
static int sq2_off_time;
static float sq2 = 1;
static int sq2_timer = 0;
static audio_context ctx;
static int audio_callback(const void* input_uffer, void *output_buffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *time_info,
PaStreamCallbackFlags status_flags,
void *userData ) {
//printf("Audio Callback!\n");
audio_context *ctx = (audio_context *) userData;
float *out = (float *)output_buffer;
PaTime time = time_info->currentTime;
sq1_on_time = 1/(ctx->sq1_freq/(float)SAMPLE_RATE) * ctx->sq1_duty;
sq1_off_time = 1/(ctx->sq1_freq/(float)SAMPLE_RATE) * (1 - ctx->sq1_duty);
sq2_on_time = 1/(ctx->sq2_freq/(float)SAMPLE_RATE) * ctx->sq2_duty;
sq2_off_time = 1/(ctx->sq2_freq/(float)SAMPLE_RATE) * (1 - ctx->sq2_duty);
for(int i = 0; i < framesPerBuffer; i++) {
float val = 0;
//handle audio channels
//val += 0.2 * sine[ind];
//ind += 500;
if((sq1_timer >= sq1_on_time && sq1 == 1)) {
sq1 = 0;
sq1_timer = 0;
} else if((sq1_timer >= sq1_off_time && sq1 == 0)){
sq1 = 1;
sq1_timer = 0;
}
sq1_timer++;
val += ctx->sq1_amp * sq1;
if((sq2_timer >= sq2_on_time && sq2 == 1)) {
sq2 = 0;
sq2_timer = 0;
} else if((sq2_timer >= sq2_off_time && sq2 == 0)){
sq2 = 1;
sq2_timer = 0;
}
sq2_timer++;
val += ctx->sq2_amp * sq2;
//val += 0.2 * sine[ind2];
//ind2 += 200;
if(ind >= TABLE_SIZE) ind -= TABLE_SIZE;
if(ind2 >= TABLE_SIZE) ind2 -= TABLE_SIZE;
*out++ = val;
}
return paContinue;
}
void audio_init(){
PaStreamParameters output_parameters;
PaStream *stream;
PaError err;
ctx.sq1_amp = 0.2;
ctx.sq1_duty = 0.5;
ctx.sq1_freq = 200;
ctx.sq2_amp = 0;
ctx.sq2_duty = 0.5;
ctx.sq2_freq = 400;
for(int i = 0; i < TABLE_SIZE; i++) {
sine[i] = (float) sin(((double)i/(double)TABLE_SIZE) * M_PI * 2.);
}
err = Pa_Initialize();
if (err != paNoError) goto error;
output_parameters.device = Pa_GetDefaultOutputDevice();
if(output_parameters.device == paNoDevice) {
fprintf(stderr, "No default audio device!\n");
goto error;
}
output_parameters.channelCount = 1;
output_parameters.sampleFormat = paFloat32;
output_parameters.suggestedLatency = Pa_GetDeviceInfo(output_parameters.device)->defaultLowOutputLatency;
output_parameters.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream(&stream,
NULL,
&output_parameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
NULL,
audio_callback,
&ctx);
if(err != paNoError) goto error;
err = Pa_StartStream(stream);
if(err != paNoError) goto error;
return;
error:
Pa_Terminate();
fprintf(stderr, "portaudio stream error\n\tError Number: %d\n\tError Message: %s\n", err, Pa_GetErrorText(err));
}
static int change = 1;
void audio_tick(){
ctx.sq1_freq += change;
if(ctx.sq1_freq >= 600 || ctx.sq1_freq <= 200) {
change = -change;
}
}