// // main.c // WasmAudio // // Created by Jacky Jack on 06/07/2021. // #include #include #include #include #include #include #include #include #include #if __EMSCRIPTEN__ #include #include #include #include #include #else #include #include #ifdef __APPLE__ #include #else #include #endif //how to use on mac? //#include #endif #ifdef __EMSCRIPTEN__ #define KEEPALIVE EMSCRIPTEN_KEEPALIVE #else #define KEEPALIVE #endif #include "../FIR/firmath.h" #define SCREEN_WIDTH 320 #define SCREEN_WIDTH2 (SCREEN_WIDTH/2) #define SCREEN_HEIGHT 320 #define SCREEN_HEIGHT2 (SCREEN_HEIGHT/2) //Maximum recording time plus padding #define RECORDING_BUFFER_SECONDS (2) //Maximum recording time #define MAX_RECORDING_SECONDS (RECORDING_BUFFER_SECONDS) #define RECORDING_BUFFER_CHANNELS (2) #define RECORDING_BUFFER_SAMPLERATE (48000) #define RECORDING_BUFFER_SAMPLESIZE (4) //LSB float32 #define RECORDING_BUFFER_SAMPLES (4096) #define SDL_CALLBACK_USED_BUFSIZE (RECORDING_BUFFER_SAMPLES*RECORDING_BUFFER_SAMPLESIZE*RECORDING_BUFFER_CHANNELS ) #define BUFSIZE (RECORDING_BUFFER_SECONDS*RECORDING_BUFFER_CHANNELS*RECORDING_BUFFER_SAMPLERATE*RECORDING_BUFFER_SAMPLESIZE) #define BUFSIZE2 (BUFSIZE/2) #define BUFSIZE4 (BUFSIZE/4) #define BUFSIZE8 (BUFSIZE/8) #define BUFSIZE16 (BUFSIZE/16) //SDL drawing recording int first_run=1; static int quit=0; static SDL_Window *window = NULL; static SDL_Renderer *renderer = NULL; //Audio device IDs static SDL_AudioDeviceID recordingDeviceId = 0; static SDL_AudioDeviceID playbackDeviceId = 0; int audio_buf_position=0; int current_state=0; //FIR filter stuff FILE *f_1,*f_2; fir_t fir_lp; firw_t firw_lp; //const int N=200; #define N (200) double h[N],w[N]; int filter_N=180; int filter_FS_hz=48000; int filter_FC_hz=1000; double filter_FC; //audio buffer vars int audio_rec_buffer_size=-1; int audio_rec_buffer_max_size=-1; static uint8_t audio_rec_buffer_[BUFSIZE]; #define PROCESS_BUF_SIZE (BUFSIZE) uint8_t *audio_rec_buffer=NULL; static double process_buf[PROCESS_BUF_SIZE+200]; static double process_buf2[PROCESS_BUF_SIZE+200]; void audio_recording_callback(void *data, uint8_t *insamples, int len) { if (audio_buf_position BUFSIZE4) { printf("Buffer overflow convert_double_to_f32"); exit(1); } float f = d; int32_t *i32_ = &f,i32=*i32_; audio_rec_buffer[i+3] = ((int)i32>>24)&0xff; audio_rec_buffer[i+2] = ((int)i32>>16)&0xff; audio_rec_buffer[i+1] = ((int)i32>>8)&0xff; audio_rec_buffer[i+0] = ((int)i32&0xff); } //printf("\n"); } void convert_f32_to_double() { int i=0; for (i=0;i filter_FS_hz/2) { cutoff = filter_FS_hz/2; filter_FC_hz = cutoff; printf(" cutoff=%d\n", cutoff); filter_FC=1.0*filter_FC_hz/filter_FS_hz; return; } filter_FC_hz = cutoff; } void KEEPALIVE set_cutoff_plus_1k() { set_cutoff_freq(filter_FC_hz+1000); } void KEEPALIVE set_cutoff_minus_1k() { set_cutoff_freq(filter_FC_hz-1000); } int KEEPALIVE get_cutoff_freq() { return filter_FC_hz; } int KEEPALIVE get_tap_number() { return filter_N; } void KEEPALIVE set_tap_number(int tapN) { if (tapN<10) { filter_N = 10; return; } if (tapN>N) { filter_N = 100; return; } filter_N = tapN; } void KEEPALIVE set_tap_number_plus_10() { set_tap_number(filter_N+10); } void KEEPALIVE set_tap_number_minus_10() { set_tap_number(filter_N-10); } int KEEPALIVE recalculate_fir(double *arr) { int i = 0; filter_FC=1.0*filter_FC_hz/filter_FS_hz; fir_lp.num_taps =filter_N; fir_lp.fir_coef = h; firw_lp.num_taps = filter_N; firw_lp.win_coef = w; for (i=0;i ",process_buf[i]); process_buf[i] = process_buf[i]*1.01; if (process_buf[i] > 1.0) process_buf[i] = 1.0; if (process_buf[i] < -1.0) process_buf[i] = -1.0; //printf("%f\n",process_buf[i]); } } void cut_up() { int i=0; for (i=0;i 1.0) process_buf[i] = 1.0; if (process_buf[i] < -1.0) process_buf[i] = -1.0; } } #ifdef __EMSCRIPTEN__ int KEEPALIVE stop_loop() { emscripten_pause_main_loop(); return 0; } int KEEPALIVE start_loop() { emscripten_resume_main_loop(); return 0; } #endif void save_to_matlab(char *name) { int i; FILE *f=NULL; char namebuf[256]; snprintf(namebuf,sizeof(namebuf),"%s.mat",name); f = fopen(namebuf,"w+"); fprintf(f,"# Created by me\n"); fprintf(f,"# name: %s\n",name); fprintf(f,"# type: matrix\n"); fprintf(f,"# rows: 1\n"); int dumpSize=BUFSIZE16; fprintf(f,"# columns: %d\n",dumpSize); #if 1 for (i=0;inum_taps-1], input, (ilength-fir->num_taps)*sizeof(double)); for (n=0; nnum_taps; n++) { coeffp = fir->fir_coef; inputp = &input[fir->num_taps - 1 + n]; acc = 0; for (k=0;knum_taps;k++) { acc += (*coeffp++)*(*inputp--); } output[n] = acc; } printf("max n value %d\n",n); memmove(&input[0], &input[ilength-fir->num_taps], (fir->num_taps-1)*sizeof(double)); } #define MIN(x, y) (((x) < (y)) ? (x) : (y)) void fir_filter2(fir_t *fir, double *input, uint32_t ilength, double *output, uint32_t olength) { double acc; double *coeffp; double *inputp; int i,j; memcpy(&input[fir->num_taps-1], input, (ilength-fir->num_taps)*sizeof(double)); /* for (n=0; nfir_coef; inputp = &input[fir->num_taps - 1 + n]; acc = 0; for (k=0;knum_taps;k++) { acc += (*coeffp++)*(*inputp--); } output[n] = acc; } */ for (i=0;inum_taps);i++) { acc = 0.0f; for (j=0;jnum_taps;j++) { acc += fir->fir_coef[j]*input[ilength-j-1+i]; } if (inum_taps], (fir->num_taps-1)*sizeof(double)); } uint32_t tick_start, tick_end,tick_1sec; #if __EMSCRIPTEN__ void main_tick() { #else int main_tick() { #endif int i; int update_fractal=0; uint64_t perf_start; perf_start = SDL_GetPerformanceCounter(); tick_start = SDL_GetTicks(); SDL_Event event; SDL_StartTextInput(); while (SDL_PollEvent(&event) != 0) { switch (event.type) { case SDL_QUIT: { quit = 1; break; } case SDL_KEYDOWN: { switch (event.key.keysym.sym) { case 21: case SDLK_r: //record if stopped if ((current_state == STOPPED) || (current_state == RECORDED)) { audio_buf_position = 0; SDL_PauseAudioDevice(recordingDeviceId, SDL_FALSE); current_state = RECORDING; printf("State: RECORDING\n"); } break; case 22: case SDLK_s: //play if recorded if (current_state == RECORDED) { audio_buf_position = 0; SDL_PauseAudioDevice( playbackDeviceId, SDL_FALSE ); current_state = PLAYBACK; printf("State: PLAYBACK\n"); } /*else if (current_state == PLAYBACK) { current_state = STOPPED; } else if (current_state == STOPPED) { current_state = PLAYBACK; }*/ break; case 20: case SDLK_q: //process recorderd buffer with low pass filter if (current_state == RECORDED) { convert_f32_to_double(); save_to_matlab("B1"); //simple volume raise #if 0 convert_dobule_up(); #endif //fir filter apply #if 1 fir_filter(&fir_lp, process_buf, PROCESS_BUF_SIZE, process_buf2, PROCESS_BUF_SIZE); //fir_filter2(&fir_lp, process_buf, PROCESS_BUF_SIZE, process_buf2, PROCESS_BUF_SIZE); memcpy(process_buf,process_buf2,PROCESS_BUF_SIZE*sizeof(double)); //cut_up(); save_to_matlab("B2"); #endif convert_double_to_f32(); } break; default: printf("Unknown key %d\n",event.key.keysym.sym); update_fractal = 1; } break; } } //printf("Poll event\n"); } #if __EMSCRIPTEN__ if (current_state == RECORDING) { SDL_LockAudioDevice( recordingDeviceId ); printf("recording=%d\n",audio_buf_position); if( audio_buf_position > audio_rec_buffer_size ) { //Stop recording audio SDL_PauseAudioDevice( recordingDeviceId, SDL_TRUE ); current_state = RECORDED; printf("State: RECORDED\n"); } SDL_UnlockAudioDevice( recordingDeviceId ); } else if (current_state == PLAYBACK) { SDL_LockAudioDevice( playbackDeviceId ); //Finished playback printf("audio_buf_position=%d\n",audio_buf_position); if( audio_buf_position > audio_rec_buffer_size ) { //Stop playing audio //SDL_Delay(500); SDL_PauseAudioDevice( playbackDeviceId, SDL_TRUE ); //printf("%d\n",SDL_GetQueuedAudioSize(playbackDeviceId)); //SDL_ClearQueuedAudio(playbackDeviceId); current_state = RECORDED; printf("State: RECORDED\n"); } //Unlock callback SDL_UnlockAudioDevice( playbackDeviceId ); } #endif //check for first ever run if (first_run == 1) { first_run = 0; update_fractal = 1; } if (update_fractal == 1) { } #ifndef __EMSCRIPTEN__ if (update_fractal == 1) #endif { SDL_GL_SwapWindow( window ); } update_fractal=0; tick_end = SDL_GetTicks(); if ((tick_end-tick_1sec)>1000) { printf("FPS:%f\n",1.0f/((tick_end-tick_start)/1000.0f)); tick_1sec = tick_end; } #if !__EMSCRIPTEN__ return 0; #endif } void main_loop() { tick_1sec = SDL_GetTicks(); #if __EMSCRIPTEN__ emscripten_set_main_loop(main_tick, 25, 1); #else while (0 == quit) { main_tick(); #if !__EMSCRIPTEN__ if (current_state == RECORDING) { SDL_LockAudioDevice( recordingDeviceId ); //printf("recording=%d\n",audio_buf_position); if( audio_buf_position > audio_rec_buffer_size ) { //Stop recording audio SDL_PauseAudioDevice( recordingDeviceId, SDL_TRUE ); current_state = RECORDED; printf("State: RECORDED\n"); } SDL_UnlockAudioDevice( recordingDeviceId ); } else if (current_state == PLAYBACK) { SDL_LockAudioDevice( playbackDeviceId ); //Finished playback //printf("audio_buf_position=%d audio_rec_buffer_size=%d\n",audio_buf_position,audio_rec_buffer_size); if( audio_buf_position >= (audio_rec_buffer_size-SDL_CALLBACK_USED_BUFSIZE) ) { //Stop playing audio SDL_PauseAudioDevice( playbackDeviceId, SDL_TRUE ); current_state = RECORDED; printf("State: RECORDED\n"); } //Unlock callback SDL_UnlockAudioDevice( playbackDeviceId ); } #endif } #endif } int main(int argc, const char * argv[]) { int i,count; char *audio_rec_device_name=NULL; char *audio_play_device_name=NULL; filter_FC=1.0*filter_FC_hz/filter_FS_hz; fir_lp.num_taps =filter_N; fir_lp.fir_coef = h; firw_lp.num_taps = filter_N; firw_lp.win_coef = w; for (i=0;i %d\n",audio_rec_want.freq,audio_rec_have.freq); } if (audio_rec_want.format != audio_rec_have.format) { printf("Format changed %d -> %d\n",audio_rec_want.format, audio_rec_have.format); } printf("F32 is signed (%d)\n",SDL_AUDIO_ISSIGNED(audio_rec_have.format)); printf("F32 is bigend (%d)\n",SDL_AUDIO_ISBIGENDIAN(audio_rec_have.format)); printf("F32 is bitsize(%d)\n",SDL_AUDIO_BITSIZE(audio_rec_have.format)); if (recordingDeviceId == 0) { printf("Failed to open recording device\n"); } else { int byte_per_sample = audio_rec_have.channels * ( SDL_AUDIO_BITSIZE( audio_rec_have.format )/8); int byte_per_second = audio_rec_have.freq * byte_per_sample; printf("bytes per second %d\n",byte_per_second); audio_rec_buffer_size = byte_per_second*RECORDING_BUFFER_SECONDS; audio_rec_buffer_max_size = byte_per_second*MAX_RECORDING_SECONDS; //audio_rec_buffer = malloc(audio_rec_buffer_max_size); audio_rec_buffer = &audio_rec_buffer_[0]; printf("buffsize_max=%d\n",audio_rec_buffer_max_size); printf("buffsize=%d\n",audio_rec_buffer_size); printf("allocated=%d\n",BUFSIZE); memset(audio_rec_buffer,0,audio_rec_buffer_max_size); } SDL_AudioSpec audio_play_want, audio_play_have; audio_play_want.freq = 48000; audio_play_want.format = AUDIO_F32; audio_play_want.channels = 2; audio_play_want.samples = 4096; //audio_play_want.silence = 0; audio_play_want.callback = audio_playback_callback; playbackDeviceId = SDL_OpenAudioDevice(NULL, SDL_FALSE, &audio_play_want, &audio_play_have, SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (audio_play_want.freq != audio_play_have.freq) { printf("Freq changed %d -> %d\n",audio_rec_want.freq,audio_rec_have.freq); } if (audio_play_want.format != audio_play_have.format) { printf("Format changed %d -> %d\n",audio_play_want.format, audio_play_have.format); } current_state = STOPPED; printf("State: STOPED\n"); f_1 = fopen("pre.txt","w+"); f_2 = fopen("post.txt","w+"); main_loop(); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_CloseAudio();//? SDL_VideoQuit();//? SDL_Quit(); fclose(f_1); fclose(f_2); //return 0; }