From aa759ff708196e5ea0f39bedabfbecb8f164294e Mon Sep 17 00:00:00 2001 From: zlago Date: Mon, 2 Sep 2024 10:58:10 +0200 Subject: cleanup --- src/SDL2.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 src/SDL2.c (limited to 'src/SDL2.c') diff --git a/src/SDL2.c b/src/SDL2.c new file mode 100644 index 0000000..4e51269 --- /dev/null +++ b/src/SDL2.c @@ -0,0 +1,221 @@ +#define SDL_MAIN_HANDLED +#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; + +SDL_Window *window = NULL; + +int paused = 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) { + struct userdata *user = userdata_void; + float *stream = (float *) stream_void; + if (user->callback == NULL) { + for (int i = 0; i < length / sizeof (float); i++) { + stream[i] = 0.0; + } + } else { + user->callback(user->user, stream_void, length); + } +} + +int (*file_ext(char *file))(struct blob *, struct userdata *); + +int main(int argc, char **argv) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) { + eprintf("failed to init SDL: %s\n"); + return EXIT_FAILURE; + } + + SDL_StopTextInput(); + + if ((window = SDL_CreateWindow("mu-sdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN)) == NULL) { + eprintf("failed to create a window: %s\n"); + SDL_Quit(); + return EXIT_FAILURE; + } + + SDL_Renderer *renderer; + if ((renderer = SDL_CreateRenderer(window, -1, 0)) == NULL) { + eprintf("failed to create a renderer: %s\n"); + SDL_DestroyWindow(window); + SDL_Quit(); + return EXIT_FAILURE; + } + + SDL_ShowWindow(window); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); + SDL_RenderPresent(renderer); + + SDL_AudioSpec desired = { + .freq = SAMPLE_RATE, + .format = AUDIO_F32SYS, + .channels = OUT_CHANNELS, + .samples = 8096, + .callback = audio_callback, + .userdata = &userdata, + }; + SDL_AudioDeviceID audio = SDL_OpenAudioDevice(NULL, 0, &desired, NULL, 0); + + if (argc == 2) { + int (*module_func)(struct blob *, struct userdata *) = file_ext(argv[1]); + if (module_func == NULL) { + eprintf("%s: unrecognized file extension\n", argv[1]); + goto arg_load_done; + } + struct blob file = load_file(argv[1]); + if (file.data == NULL) { + perror(argv[1]); + goto arg_load_done; + } + module_func(&file, &userdata); + } + arg_load_done: + + SDL_PauseAudioDevice(audio, 0); + while (true) { + SDL_Event evt; + while (SDL_PollEvent(&evt)) { + switch (evt.type) { + case SDL_QUIT: + goto done; + + case SDL_WINDOWEVENT: + SDL_RenderClear(renderer); + SDL_RenderPresent(renderer); + break; + + case SDL_KEYDOWN: + // ^Q + if (evt.key.keysym.sym == SDLK_q && evt.key.keysym.mod & KMOD_CTRL) { + goto done; + } + // ESC + if (evt.key.keysym.sym == SDLK_ESCAPE) { + goto done; + } + + if (evt.key.keysym.sym == SDLK_SPACE) { + paused = !paused; + SDL_PauseAudioDevice(audio, paused); + } + break; + + case SDL_DROPFILE: + puts(evt.drop.file); + struct blob file = load_file(evt.drop.file); + if (file.data == NULL) { + perror(evt.drop.file); + SDL_free(evt.drop.file); + break; + } + struct userdata newuser = {.callback = NULL, .freefunc = NULL}; + int (*module_func)(struct blob *, struct userdata *) = file_ext(evt.drop.file); + if (module_func == NULL) { + eprintf("%s: unrecognized file extension\n", evt.drop.file); + free(file.data); + break; + } + SDL_free(evt.drop.file); + if (module_func(&file, &newuser)) { + // error + } else { + SDL_LockAudioDevice(audio); + if (userdata.freefunc != NULL) { + userdata.freefunc(userdata.user); + } + userdata = newuser; + SDL_UnlockAudioDevice(audio); + } + free(file.data); + break; + + default: + } + } + } + done: + if (userdata.freefunc != NULL) { + SDL_LockAudioDevice(audio); + userdata.freefunc(userdata.user); + SDL_PauseAudioDevice(audio, 1); + SDL_UnlockAudioDevice(audio); + } + + SDL_DestroyRenderer(renderer); + + SDL_DestroyWindow(window); + + SDL_CloseAudioDevice(audio); + + SDL_Quit(); + + return EXIT_SUCCESS; +} + +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