119 lines
3.5 KiB
C
119 lines
3.5 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;
|
|
ctx.sq1_duty = 0;
|
|
ctx.sq1_freq = 0;
|
|
|
|
ctx.sq2_amp = 0;
|
|
ctx.sq2_duty = 0;
|
|
ctx.sq2_freq = 0;
|
|
|
|
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));
|
|
} |