#define SDL_MAIN_HANDLED #include #include #include #include #include "include.h" #include "common/common.h" #define eprintf(...) fprintf(stderr, __VA_ARGS__) volatile sig_atomic_t keep_going = 1; void sigint_handler(int sig_num) { signal(SIGINT, SIG_IGN); keep_going = 0; } struct blob load_file(char const *const name); struct userdata userdata = { .callback = NULL, .user = NULL, }; //void audio_callback(void *userdata_void, unsigned char *stream_void, int const length) { int audio_callback(void const *inBuf, void *outBuf, unsigned long const frameCount, PaStreamCallbackTimeInfo const* timeInfo, PaStreamCallbackFlags statusFlags, void *userdata_void) { (void) inBuf; (void) timeInfo; (void) statusFlags; struct userdata *user = userdata_void; user->callback(user->user, outBuf, frameCount * sizeof (float) * 2); return 0; } int (*file_ext(char *file))(struct blob *, struct userdata *); #include #include static void alsa_shut_up(char const *file, int line, char const *function, int err, char const *fmt, ...) { if (err == 0) { // duckGPT claims its not unsafe to return before using va_ functions return; } // ALSA lib (real) fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function); va_list list; va_start(list, fmt); vfprintf(stderr, fmt, list); va_end(list); putc('\n', stderr); } int main(int argc, char **argv) { if (argc != 2) { eprintf("usage: %s audio-file.{mid,mod,xm,it,s3m}\n", argv[0]); return EXIT_FAILURE; } else { int (*module_func)(struct blob *, struct userdata *) = file_ext(argv[1]); if (module_func == NULL) { eprintf("%s: unrecognized file extension\n", argv[1]); return EXIT_FAILURE; } struct blob file = load_file(argv[1]); if (file.data == NULL) { perror(argv[1]); return EXIT_FAILURE; } if (module_func(&file, &userdata)) { eprintf("%s: failed to load\n", argv[1]); return EXIT_FAILURE; } } signal(SIGINT, sigint_handler); // signal(3) claims this method is deprecated, but.. snd_lib_error_set_handler(alsa_shut_up); PaError paErr; if ((paErr = Pa_Initialize()) != paNoError) { printf("error: Pa_Initialize: %s\n", Pa_GetErrorText(paErr)); goto error; } snd_lib_error_set_handler(NULL); PaStream *stream; if ((paErr = Pa_OpenDefaultStream( &stream, IN_CHANNELS, OUT_CHANNELS, paFloat32, SAMPLE_RATE, paFramesPerBufferUnspecified, audio_callback, &userdata )) != paNoError) { printf("error: Pa_OpenDefaultStream: %s\n", Pa_GetErrorText(paErr)); goto error; } if ((paErr = Pa_StartStream(stream)) != paNoError) { printf("error: Pa_StartStream: %s\n", Pa_GetErrorText(paErr)); goto error; } while (keep_going) { Pa_Sleep(1000); } if ((paErr = Pa_StopStream(stream)) != paNoError) { printf("error: Pa_StopStream: %s\n", Pa_GetErrorText(paErr)); goto error; } if ((paErr = Pa_CloseStream(stream)) != paNoError) { printf("error: Pa_CloseStream: %s\n", Pa_GetErrorText(paErr)); goto error; } if ((paErr = Pa_Terminate()) != paNoError) { printf("error: Pa_Terminate: %s\n", Pa_GetErrorText(paErr)); goto error; } return EXIT_SUCCESS; error: return EXIT_FAILURE; }