With SDL2 I am trying to play a frequency that will be changed on a keydown event. There is a clicking sound when the frequency is changed, that i would like to get rid of.
The wave with the new frequency is phase shifted and the values of sin(2*pi*time*freq)
and sin(2*pi*time*new_freq + phase_shift)
is equal, but it has no impact on the clicking sound.
I have also tried to do a fade-out fade-in on two frequencies without any luck.
Here is the code with phase-shift.
#include <stdio.h>
#include <math.h>
#include <SDL2/SDL.h>
#define PI 3.14159265
typedef void (*periodic_function)(double time, Sint16 *sample, int max);
typedef struct callback_struct {
int *sample_nr;
float *frequency;
float *new_frequency;
periodic_function periodic_function;
} callback_struct;
void sinewave(double time, Sint16 *sample, int max) {
double val = sin(time)*max;
*sample = val;
}
void audio_callback(void *userdata, Uint8 *stream_, int len) {
Sint16 *stream = (Sint16*)stream_;
callback_struct *user_data = userdata;
float sample_len = len / sizeof(Sint16);
int *sample_nr = (*user_data).sample_nr;
float *frequency = (*user_data).frequency;
float *new_frequency = (*user_data).new_frequency;
float deg;
Sint16 sample;
for (int i = 0; i < sample_len; i++, (*sample_nr)++) {
float time = (*sample_nr) / 48000.0;
if (*new_frequency != *frequency) {
// Frequency has changed, add phase.
double phase_shift = 2 * PI * time * (*frequency - *new_frequency);
deg = 2 * PI * time * *new_frequency + phase_shift;
*frequency = *new_frequency;
} else {
// Frequency has not changed.
deg = 2 * PI * time * *frequency;
}
(*user_data).periodic_function(deg, &sample, 28000);
*stream++ = sample;
}
}
int main(int argc, char* argv[])
{
SDL_Window *window;
SDL_Renderer *renderer;
if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0)
{
printf("Error initializing sdl\n");
return -1;
}
SDL_CreateWindowAndRenderer(680,440, 0, &window, &renderer);
if(!window)
{
printf("Failed to create window\n");
return -1;
}
// Set up user_data struct
struct callback_struct user_data;
int sample_nr = 0;
float frequency = 240.0;
float new_frequency = 240.0;
user_data.sample_nr = &sample_nr;
user_data.frequency = &frequency;
user_data.new_frequency = &new_frequency;
user_data.periodic_function = sinewave;
SDL_AudioSpec want,have;
SDL_AudioDeviceID dev;
SDL_memset(&want, 0, sizeof(want));
want.freq = 48000;
want.format = AUDIO_S16SYS;
want.channels = 1;
want.samples = 1024;
want.callback = audio_callback;
want.userdata = &user_data;
if((dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE)) < 0) {
printf("Error open audio device\n");
return -1;
}
// Play audio
SDL_PauseAudioDevice(dev, 0);
// Main loop
int run_program = 1;
while(run_program) {
SDL_Event e;
while(SDL_PollEvent(&e) > 0)
{
switch(e.type) {
case SDL_QUIT:
run_program = 0;
break;
case SDL_KEYDOWN:
char key = (char) *SDL_GetKeyName(e.key.keysym.sym);
if(key == 'P') {
new_frequency = frequency + 1;
} else if(key == 'O') {
new_frequency = frequency - 1;
}
continue;
default:
break;
}
}
}
// Stop playing audio
SDL_PauseAudioDevice(dev, 1);
// Clean up and quit
SDL_CloseAudioDevice(dev);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}