From e1dbcc7c80e6930f223e4617385931aad1fff2c7 Mon Sep 17 00:00:00 2001 From: zlago Date: Mon, 2 Sep 2024 10:58:22 +0200 Subject: portaudio version --- GNUmakefile | 2 +- src/portaudio.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/portaudio.c diff --git a/GNUmakefile b/GNUmakefile index a9e2537..f7eb64a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -13,7 +13,7 @@ deps ::= $(addprefix out/,$(notdir ${srcs:.c=.d})) .PHONY: all run clean -all: out/mu-SDL2 +all: out/mu-SDL2 out/mu-portaudio run: out/mu-SDL2 ./$< diff --git a/src/portaudio.c b/src/portaudio.c new file mode 100644 index 0000000..f4ca4b7 --- /dev/null +++ b/src/portaudio.c @@ -0,0 +1,162 @@ +#define SDL_MAIN_HANDLED +#include + +#include +#include +#include +#include +#include + +#include "include.h" + +int module_openmpt(struct blob *file, struct userdata *userdata); +int module_fluidsynth(struct blob *file, struct userdata *userdata); + +#define eprintf(...) fprintf(stderr, __VA_ARGS__) + +static const int WINDOW_WIDTH = 160, WINDOW_HEIGHT = 90; + +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 *); + +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; + } + module_func(&file, &userdata); + } + + signal(SIGINT, sigint_handler); // signal(3) claims this method is deprecated, but.. + + PaError paErr; + if ((paErr = Pa_Initialize()) != paNoError) { + printf("error: Pa_Initialize: %s\n", Pa_GetErrorText(paErr)); + goto error; + } + + 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; +} + +int (*file_ext(char *file))(struct blob *, struct userdata *) { + size_t len = strlen(file); + #define ext(extension) memcmp(file + len - sizeof (extension) + 1, extension, sizeof (extension)) + if ((ext(".mptm") && ext(".mod") && ext(".xm") && ext(".s3m") && ext(".it")) == 0) { + return module_openmpt; + } else if ((ext(".mid") && ext(".midi")) == 0) { + return module_fluidsynth; + } + #undef ext + return NULL; +} + +struct blob load_file(char const *const name) { + const size_t START_SIZE = 1; + FILE *file = fopen(name, "rb"); + if (file == NULL) { + return (struct blob) {.data = NULL}; + } + void *data = malloc(START_SIZE); + size_t allocated = START_SIZE; + size_t used = 0; + while (1) { + size_t read = fread(data + used, 1, allocated - used, file); + if (read != allocated - used) { + used += read; + break; + } + used += read; + allocated *= 2; + void *const newdata = realloc(data, allocated); + if (newdata == NULL) { + goto realloc_error; + } + data = newdata; + } + void *const newdata = realloc(data, used); + if (newdata == NULL && used != 0) { + goto realloc_error; + } + fclose(file); + return (struct blob) {.data = newdata, .size = used}; + + realloc_error: + free(data); + fclose(file); + return (struct blob) {.data = NULL}; +} -- cgit 1.4.1-2-gfad0