Fixed audio buffer popping
This commit is contained in:
parent
8e5c3234ef
commit
a094e5123b
@ -134,6 +134,7 @@ void audio_init();
|
|||||||
void audio_tick();
|
void audio_tick();
|
||||||
void audio_period_tick();
|
void audio_period_tick();
|
||||||
void lfsr_tick();
|
void lfsr_tick();
|
||||||
|
void audio_sample_tick();
|
||||||
|
|
||||||
u8 audio_read(u16 address);
|
u8 audio_read(u16 address);
|
||||||
void audio_write(u16 address, u8 value);
|
void audio_write(u16 address, u8 value);
|
||||||
|
183
lib/audio.c
183
lib/audio.c
@ -12,10 +12,11 @@
|
|||||||
#define FRAMES_PER_BUFFER 64
|
#define FRAMES_PER_BUFFER 64
|
||||||
#define TIME_PER_SAMPLE 1.0f / (SAMPLE_RATE/1000.0f/1000.0f)
|
#define TIME_PER_SAMPLE 1.0f / (SAMPLE_RATE/1000.0f/1000.0f)
|
||||||
#define TIME_PER_AUDIO_TICK 1.0f / (1048576.0f/1000.0f/1000.0f)
|
#define TIME_PER_AUDIO_TICK 1.0f / (1048576.0f/1000.0f/1000.0f)
|
||||||
#define AUDIO_TICKS_PER_SAMPLE 2157281.28 / SAMPLE_RATE
|
#define AUDIO_TICKS_PER_SAMPLE 4194304.0 / SAMPLE_RATE
|
||||||
|
#define SAMPLES_PER_AUDIO_TICK SAMPLE_RATE / 4194304.0
|
||||||
#define TIME_PER_WAVE_TICK 1.0f / (2104718.0f/1000.0f/1000.0f)
|
#define TIME_PER_WAVE_TICK 1.0f / (2104718.0f/1000.0f/1000.0f)
|
||||||
#define LFSR_BASE_CLOCK 262144.0f
|
#define LFSR_BASE_CLOCK 262144.0f
|
||||||
#define AUDIO_BUFFER_SIZE (int)(SAMPLE_RATE / 10)
|
#define AUDIO_BUFFER_SIZE FRAMES_PER_BUFFER
|
||||||
|
|
||||||
static audio_context ctx;
|
static audio_context ctx;
|
||||||
|
|
||||||
@ -103,14 +104,17 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
|
|||||||
//}
|
//}
|
||||||
for(int i = 0; i < framesPerBuffer; i++) {
|
for(int i = 0; i < framesPerBuffer; i++) {
|
||||||
//samples_occured = samples_occured + AUDIO_TICKS_PER_SAMPLE-1;
|
//samples_occured = samples_occured + AUDIO_TICKS_PER_SAMPLE-1;
|
||||||
while(ctx.buffer_cnt == 0) {
|
//while(ctx.buffer_cnt == 0) {
|
||||||
delay(1);
|
// delay(1);
|
||||||
}
|
//}
|
||||||
if(ctx.buffer_cnt == 0) {
|
if(ctx.buffer_cnt == 0) {
|
||||||
//samples_occured = samples_occured - ((int)samples_occured - ctx.buffer_cnt);
|
//samples_occured = samples_occured - ((int)samples_occured - ctx.buffer_cnt);
|
||||||
//ctx.sq1_read_index = ctx.sq1_write_index-1;
|
//ctx.sq1_read_index = ctx.sq1_write_index-1;
|
||||||
//printf("buffer underflow\n");
|
//printf("buffer underflow\n");
|
||||||
return paContinue;
|
continue;
|
||||||
|
//ctx.buffer_cnt++;
|
||||||
|
//ctx.sq1_read_index--;
|
||||||
|
//ctx.sq1_read_index %= AUDIO_BUFFER_SIZE;
|
||||||
} else {
|
} else {
|
||||||
//ctx.buffer_cnt -= (u8)samples_occured;
|
//ctx.buffer_cnt -= (u8)samples_occured;
|
||||||
//ctx.sq1_read_index += (u8)samples_occured;
|
//ctx.sq1_read_index += (u8)samples_occured;
|
||||||
@ -218,9 +222,6 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
|
|||||||
left *= (float)left_vol/7.0f;
|
left *= (float)left_vol/7.0f;
|
||||||
right *= (float)right_vol/7.0f;
|
right *= (float)right_vol/7.0f;
|
||||||
|
|
||||||
//left /= 4;
|
|
||||||
//right /= 4;
|
|
||||||
|
|
||||||
left = ctx.sq1_audio_buffer[ctx.sq1_read_index];
|
left = ctx.sq1_audio_buffer[ctx.sq1_read_index];
|
||||||
right = ctx.sq2_audio_buffer[ctx.sq1_read_index];
|
right = ctx.sq2_audio_buffer[ctx.sq1_read_index];
|
||||||
ctx.sq1_read_index++;
|
ctx.sq1_read_index++;
|
||||||
@ -233,8 +234,8 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
|
|||||||
if(dacs) {
|
if(dacs) {
|
||||||
left_out = left - left_cap;
|
left_out = left - left_cap;
|
||||||
right_out = right - right_cap;
|
right_out = right - right_cap;
|
||||||
left_cap = left - left_out * 0.996f;
|
left_cap = left - left_out * 0.999958f;
|
||||||
right_cap = right - right_out * 0.996f;
|
right_cap = right - right_out * 0.999958f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -333,9 +334,9 @@ void audio_init(){
|
|||||||
ctx.sq2_env_direction = false;
|
ctx.sq2_env_direction = false;
|
||||||
ctx.sq2_env_pace = 0x0;
|
ctx.sq2_env_pace = 0x0;
|
||||||
ctx.sq2_env_timer = 0x0;
|
ctx.sq2_env_timer = 0x0;
|
||||||
ctx.sq1_write_index = 0;
|
ctx.sq1_write_index = AUDIO_BUFFER_SIZE - 1;
|
||||||
ctx.sq1_read_index = 0;
|
ctx.sq1_read_index = 0;
|
||||||
ctx.buffer_cnt = 0;
|
ctx.buffer_cnt = AUDIO_BUFFER_SIZE - 1;
|
||||||
|
|
||||||
err = Pa_Initialize();
|
err = Pa_Initialize();
|
||||||
if (err != paNoError) goto error;
|
if (err != paNoError) goto error;
|
||||||
@ -345,7 +346,7 @@ void audio_init(){
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
output_parameters.channelCount = 2;
|
output_parameters.channelCount = 2;
|
||||||
output_parameters.sampleFormat = paFloat32;
|
output_parameters.sampleFormat = paFloat32 | paNonInterleaved;
|
||||||
output_parameters.suggestedLatency = Pa_GetDeviceInfo(output_parameters.device)->defaultLowOutputLatency;
|
output_parameters.suggestedLatency = Pa_GetDeviceInfo(output_parameters.device)->defaultLowOutputLatency;
|
||||||
output_parameters.hostApiSpecificStreamInfo = NULL;
|
output_parameters.hostApiSpecificStreamInfo = NULL;
|
||||||
printf("default sample rate: %lf\n", Pa_GetDeviceInfo(output_parameters.device)->defaultSampleRate);
|
printf("default sample rate: %lf\n", Pa_GetDeviceInfo(output_parameters.device)->defaultSampleRate);
|
||||||
@ -354,9 +355,9 @@ void audio_init(){
|
|||||||
NULL,
|
NULL,
|
||||||
&output_parameters,
|
&output_parameters,
|
||||||
SAMPLE_RATE,
|
SAMPLE_RATE,
|
||||||
paFramesPerBufferUnspecified,
|
FRAMES_PER_BUFFER,
|
||||||
paNoFlag,
|
paNoFlag,
|
||||||
audio_callback,
|
NULL,
|
||||||
&ctx);
|
&ctx);
|
||||||
if(err != paNoError) goto error;
|
if(err != paNoError) goto error;
|
||||||
err = Pa_StartStream(stream);
|
err = Pa_StartStream(stream);
|
||||||
@ -399,51 +400,10 @@ void lfsr_tick() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double cycles_needed = 0;
|
||||||
|
|
||||||
void audio_period_tick() {
|
void audio_sample_tick() {
|
||||||
period_tick++;
|
lfsr_tick();
|
||||||
u32 end = get_ticks();
|
|
||||||
samples_per_sec++;
|
|
||||||
if (end - start >= 1000) {
|
|
||||||
printf("Samples In Buffer: %ld\n", ctx.buffer_cnt);
|
|
||||||
start = end;
|
|
||||||
samples_per_sec = 0;
|
|
||||||
}
|
|
||||||
if(period_tick % 2 == 0){
|
|
||||||
ctx.sq1_period_timer++;
|
|
||||||
ctx.sq2_period_timer++;
|
|
||||||
|
|
||||||
if(ctx.sq1_period_timer >= 0x800) {
|
|
||||||
ctx.sq1_period_timer = ctx.sq1_period_reset;
|
|
||||||
ctx.sq1_sample = (ctx.sq1_sample + 1) % 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ctx.sq2_period_timer >= 0x800) {
|
|
||||||
ctx.sq2_period_timer = ctx.sq2_period_reset;
|
|
||||||
ctx.sq2_sample = (ctx.sq2_sample + 1) % 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u8 shift = 0;
|
|
||||||
if(ctx.ch3_volume == 0b10) {
|
|
||||||
shift = 1;
|
|
||||||
}
|
|
||||||
if(ctx.ch3_volume == 0b00) {
|
|
||||||
shift = 4;
|
|
||||||
}
|
|
||||||
if(ctx.ch3_volume == 0b11) {
|
|
||||||
shift = 2;
|
|
||||||
}
|
|
||||||
ctx.ch3_period_timer++;
|
|
||||||
if(ctx.ch3_period_timer >= 0x800) {
|
|
||||||
ctx.ch3_period_timer = ctx.ch3_period_reset;
|
|
||||||
ctx.ch3_sample = (ctx.ch3_sample + 1) % 32;
|
|
||||||
if((ctx.ch3_sample & 0b1) == 0b1) {
|
|
||||||
ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] & 0xF;
|
|
||||||
} else {
|
|
||||||
ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float left = 0;
|
float left = 0;
|
||||||
float right = 0;
|
float right = 0;
|
||||||
float sq1_val = 0;
|
float sq1_val = 0;
|
||||||
@ -490,6 +450,16 @@ void audio_period_tick() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ctx.ch3_dac){
|
if(ctx.ch3_dac){
|
||||||
|
u8 shift = 0;
|
||||||
|
if(ctx.ch3_volume == 0b10) {
|
||||||
|
shift = 1;
|
||||||
|
}
|
||||||
|
if(ctx.ch3_volume == 0b00) {
|
||||||
|
shift = 4;
|
||||||
|
}
|
||||||
|
if(ctx.ch3_volume == 0b11) {
|
||||||
|
shift = 2;
|
||||||
|
}
|
||||||
ch3_val = -1;
|
ch3_val = -1;
|
||||||
if(ctx.ch3_enable) {
|
if(ctx.ch3_enable) {
|
||||||
ch3_val = (((float)(ctx.ch3_last_sample >> shift) - 7.5f)/7.5f);
|
ch3_val = (((float)(ctx.ch3_last_sample >> shift) - 7.5f)/7.5f);
|
||||||
@ -557,25 +527,100 @@ void audio_period_tick() {
|
|||||||
ctx.ch4_index = 0;
|
ctx.ch4_index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
smooth_left = smooth_left - (LPF_Beta * (smooth_left - left));
|
smooth_left = smooth_left - (LPF_Beta * (smooth_left - left));
|
||||||
smooth_right = smooth_right - (LPF_Beta * (smooth_right - right));
|
smooth_right = smooth_right - (LPF_Beta * (smooth_right - right));
|
||||||
|
cycles_needed += SAMPLES_PER_AUDIO_TICK;
|
||||||
if((period_tick % (int)(AUDIO_TICKS_PER_SAMPLE)) == 0){
|
if(cycles_needed > 1){
|
||||||
//printf("tick\n");
|
//printf("tick\n");
|
||||||
while(ctx.buffer_cnt == AUDIO_BUFFER_SIZE){
|
//if(ctx.buffer_cnt == AUDIO_BUFFER_SIZE){
|
||||||
//ctx.buffer_cnt--;
|
//ctx.buffer_cnt--;
|
||||||
//ctx.sq1_read_index++;
|
//ctx.sq1_read_index++;
|
||||||
//ctx.sq1_read_index %= AUDIO_BUFFER_SIZE;
|
//ctx.sq1_read_index %= AUDIO_BUFFER_SIZE;
|
||||||
delay(10);
|
//delay(1);
|
||||||
//printf("overflow\n");
|
//printf("overflow\n");
|
||||||
|
//return;
|
||||||
|
//}
|
||||||
|
cycles_needed -= 1;
|
||||||
|
|
||||||
|
bool dacs = ctx.ch1_dac || ctx.ch2_dac || ctx.ch3_dac || ctx.ch4_dac;
|
||||||
|
float left_out = 0;
|
||||||
|
float right_out = 0;
|
||||||
|
if(dacs) {
|
||||||
|
left_out = smooth_left - left_cap;
|
||||||
|
right_out = smooth_right - right_cap;
|
||||||
|
left_cap = smooth_left - left_out * 0.996f;
|
||||||
|
right_cap = smooth_right - right_out * 0.996f;
|
||||||
}
|
}
|
||||||
ctx.sq1_audio_buffer[(ctx.sq1_write_index)] = smooth_left;
|
|
||||||
ctx.sq2_audio_buffer[(ctx.sq1_write_index)] = smooth_right;
|
|
||||||
|
left_out /= 4;
|
||||||
|
right_out /= 4;
|
||||||
|
|
||||||
|
if(left_out < -1.0f) {
|
||||||
|
left_out = -1;
|
||||||
|
}
|
||||||
|
if(left_out > 1.0f) {
|
||||||
|
left_out = 1;
|
||||||
|
}
|
||||||
|
if(right_out < -1.0f) {
|
||||||
|
right_out = -1;
|
||||||
|
}
|
||||||
|
if(right_out > 1.0f) {
|
||||||
|
right_out = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.sq1_audio_buffer[(ctx.sq1_write_index)] = left_out;
|
||||||
|
ctx.sq2_audio_buffer[(ctx.sq1_write_index)] = right_out;
|
||||||
//ctx.ch3_audio_buffer[(ctx.sq1_write_index)] = (((float)(ctx.ch3_last_sample >> shift)-7.5f)/7.5f);
|
//ctx.ch3_audio_buffer[(ctx.sq1_write_index)] = (((float)(ctx.ch3_last_sample >> shift)-7.5f)/7.5f);
|
||||||
//ctx.ch4_audio_buffer[(ctx.sq1_write_index)] = (ctx.ch4_lfsr & 0b1) ? (float)(ctx.ch4_volume-7.5f)/7.5f : -1.0f;
|
//ctx.ch4_audio_buffer[(ctx.sq1_write_index)] = (ctx.ch4_lfsr & 0b1) ? (float)(ctx.ch4_volume-7.5f)/7.5f : -1.0f;
|
||||||
ctx.sq1_write_index = (ctx.sq1_write_index + 1) % AUDIO_BUFFER_SIZE;
|
ctx.sq1_write_index = (ctx.sq1_write_index + 1);
|
||||||
ctx.buffer_cnt++;
|
//ctx.buffer_cnt++;
|
||||||
|
if(ctx.sq1_write_index == FRAMES_PER_BUFFER) {
|
||||||
|
ctx.sq1_write_index = 0;
|
||||||
|
float *data[2];
|
||||||
|
data[0] = ctx.sq1_audio_buffer;
|
||||||
|
data[1] = ctx.sq2_audio_buffer;
|
||||||
|
int err = Pa_WriteStream(stream, data, FRAMES_PER_BUFFER);
|
||||||
|
if(err != paNoError) {
|
||||||
|
fprintf(stderr, "portaudio stream error\n\tError Number: %d\n\tError Message: %s\n", err, Pa_GetErrorText(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skipped = false;
|
||||||
|
void audio_period_tick() {
|
||||||
|
period_tick++;
|
||||||
|
u32 end = get_ticks();
|
||||||
|
samples_per_sec++;
|
||||||
|
if (end - start >= 1000) {
|
||||||
|
printf("Samples In Buffer: %ld\n", ctx.buffer_cnt);
|
||||||
|
start = end;
|
||||||
|
samples_per_sec = 0;
|
||||||
|
}
|
||||||
|
if(period_tick % 2 == 0){
|
||||||
|
ctx.sq1_period_timer++;
|
||||||
|
ctx.sq2_period_timer++;
|
||||||
|
|
||||||
|
if(ctx.sq1_period_timer >= 0x800) {
|
||||||
|
ctx.sq1_period_timer = ctx.sq1_period_reset;
|
||||||
|
ctx.sq1_sample = (ctx.sq1_sample + 1) % 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx.sq2_period_timer >= 0x800) {
|
||||||
|
ctx.sq2_period_timer = ctx.sq2_period_reset;
|
||||||
|
ctx.sq2_sample = (ctx.sq2_sample + 1) % 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.ch3_period_timer++;
|
||||||
|
if(ctx.ch3_period_timer >= 0x800) {
|
||||||
|
ctx.ch3_period_timer = ctx.ch3_period_reset;
|
||||||
|
ctx.ch3_sample = (ctx.ch3_sample + 1) % 32;
|
||||||
|
if((ctx.ch3_sample & 0b1) == 0b1) {
|
||||||
|
ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] & 0xF;
|
||||||
|
} else {
|
||||||
|
ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] >> 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ void timer_tick() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lfsr_tick();
|
audio_sample_tick();
|
||||||
|
|
||||||
if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){
|
if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){
|
||||||
audio_tick();
|
audio_tick();
|
||||||
|
Loading…
Reference in New Issue
Block a user