diff --git a/CMakeLists.txt b/CMakeLists.txt index cc6cf6f0..63ad6011 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,9 +338,11 @@ if(BACKEND_AUDIO MATCHES "SDL2") ) elseif(BACKEND_AUDIO MATCHES "SDL1") target_sources(CSE2 PRIVATE - "src/Backends/Audio/SDL1.cpp" "src/Backends/Audio/SoftwareMixer.cpp" - "src/Backends/Audio/SoftwareMixer.h" + "src/Backends/Audio/SoftwareMixer/Mixer.cpp" + "src/Backends/Audio/SoftwareMixer/Mixer.h" + "src/Backends/Audio/SoftwareMixer/Backend.h" + "src/Backends/Audio/SoftwareMixer/SDL1.cpp" ) elseif(BACKEND_AUDIO MATCHES "miniaudio") target_sources(CSE2 PRIVATE diff --git a/src/Backends/Audio/SDL1.cpp b/src/Backends/Audio/SDL1.cpp deleted file mode 100644 index 791c801f..00000000 --- a/src/Backends/Audio/SDL1.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "../Audio.h" - -#include -#include -#include - -#include "SDL.h" - -#include "../Misc.h" - -#include "SoftwareMixer.h" - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -static unsigned long output_frequency; - -static void (*organya_callback)(void); -static unsigned int organya_callback_milliseconds; - -static void MixSoundsAndUpdateOrganya(long *stream, size_t frames_total) -{ - if (organya_callback_milliseconds == 0) - { - Mixer_MixSounds(stream, frames_total); - } - else - { - // Synchronise audio generation with Organya. - // In the original game, Organya ran asynchronously in a separate thread, - // firing off commands to DirectSound in realtime. To match that, we'd - // need a very low-latency buffer, otherwise we'd get mistimed instruments. - // Instead, we can just do this. - unsigned int frames_done = 0; - - while (frames_done != frames_total) - { - static unsigned long organya_countdown; - - if (organya_countdown == 0) - { - organya_countdown = (organya_callback_milliseconds * output_frequency) / 1000; // organya_timer is in milliseconds, so convert it to audio frames - organya_callback(); - } - - const unsigned int frames_to_do = MIN(organya_countdown, frames_total - frames_done); - - Mixer_MixSounds(stream + frames_done * 2, frames_to_do); - - frames_done += frames_to_do; - organya_countdown -= frames_to_do; - } - } -} - -static void Callback(void *user_data, Uint8 *stream_uint8, int len) -{ - (void)user_data; - - short *stream = (short*)stream_uint8; - const size_t frames_total = len / sizeof(short) / 2; - - size_t frames_done = 0; - - while (frames_done != frames_total) - { - long mix_buffer[0x800 * 2]; // 2 because stereo - - size_t subframes = MIN(0x800, frames_total - frames_done); - - memset(mix_buffer, 0, subframes * sizeof(long) * 2); - - MixSoundsAndUpdateOrganya(mix_buffer, subframes); - - for (size_t i = 0; i < subframes * 2; ++i) - { - if (mix_buffer[i] > 0x7FFF) - *stream++ = 0x7FFF; - else if (mix_buffer[i] < -0x7FFF) - *stream++ = -0x7FFF; - else - *stream++ = mix_buffer[i]; - } - - frames_done += subframes; - } -} - -bool AudioBackend_Init(void) -{ - if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) - { - std::string errorMessage = std::string("'SDL_InitSubSystem(SDL_INIT_AUDIO)' failed: ") + SDL_GetError(); - Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", errorMessage.c_str()); - return false; - } - - SDL_AudioSpec specification; - specification.freq = 48000; - specification.format = AUDIO_S16; - specification.channels = 2; - specification.samples = 0x400; // Roughly 10 milliseconds for 48000Hz - specification.callback = Callback; - specification.userdata = NULL; - - SDL_AudioSpec obtained_specification; - if (SDL_OpenAudio(&specification, &obtained_specification) != 0) - { - std::string error_message = std::string("'SDL_OpenAudio' failed: ") + SDL_GetError(); - Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", error_message.c_str()); - return false; - } - - output_frequency = obtained_specification.freq; - Mixer_Init(obtained_specification.freq); - - SDL_PauseAudio(0); - - char driver[20]; - Backend_PrintInfo("Selected SDL audio driver: %s", SDL_AudioDriverName(driver, 20)); - - return true; -} - -void AudioBackend_Deinit(void) -{ - SDL_CloseAudio(); - - SDL_QuitSubSystem(SDL_INIT_AUDIO); -} - -AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length) -{ - SDL_LockAudio(); - - Mixer_Sound *sound = Mixer_CreateSound(frequency, samples, length); - - SDL_UnlockAudio(); - - return (AudioBackend_Sound*)sound; -} - -void AudioBackend_DestroySound(AudioBackend_Sound *sound) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_DestroySound((Mixer_Sound*)sound); - - SDL_UnlockAudio(); -} - -void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_PlaySound((Mixer_Sound*)sound, looping); - - SDL_UnlockAudio(); -} - -void AudioBackend_StopSound(AudioBackend_Sound *sound) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_StopSound((Mixer_Sound*)sound); - - SDL_UnlockAudio(); -} - -void AudioBackend_RewindSound(AudioBackend_Sound *sound) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_RewindSound((Mixer_Sound*)sound); - - SDL_UnlockAudio(); -} - -void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_SetSoundFrequency((Mixer_Sound*)sound, frequency); - - SDL_UnlockAudio(); -} - -void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_SetSoundVolume((Mixer_Sound*)sound, volume); - - SDL_UnlockAudio(); -} - -void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_SetSoundPan((Mixer_Sound*)sound, pan); - - SDL_UnlockAudio(); -} - -void AudioBackend_SetOrganyaCallback(void (*callback)(void)) -{ - SDL_LockAudio(); - - organya_callback = callback; - - SDL_UnlockAudio(); -} - -void AudioBackend_SetOrganyaTimer(unsigned int milliseconds) -{ - SDL_LockAudio(); - - organya_callback_milliseconds = milliseconds; - - SDL_UnlockAudio(); -} diff --git a/src/Backends/Audio/SoftwareMixer/SDL1.cpp b/src/Backends/Audio/SoftwareMixer/SDL1.cpp new file mode 100644 index 00000000..0f99165c --- /dev/null +++ b/src/Backends/Audio/SoftwareMixer/SDL1.cpp @@ -0,0 +1,113 @@ +#include "Backend.h" + +#include +#include +#include + +#include "SDL.h" + +#include "../../Misc.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static void (*parent_callback)(long *stream, size_t frames_total); + +static void Callback(void *user_data, Uint8 *stream_uint8, int len) +{ + (void)user_data; + + short *stream = (short*)stream_uint8; + const size_t frames_total = len / sizeof(short) / 2; + + size_t frames_done = 0; + + while (frames_done != frames_total) + { + long mix_buffer[0x800 * 2]; // 2 because stereo + + size_t subframes = MIN(0x800, frames_total - frames_done); + + memset(mix_buffer, 0, subframes * sizeof(long) * 2); + + parent_callback(mix_buffer, subframes); + + for (size_t i = 0; i < subframes * 2; ++i) + { + if (mix_buffer[i] > 0x7FFF) + *stream++ = 0x7FFF; + else if (mix_buffer[i] < -0x7FFF) + *stream++ = -0x7FFF; + else + *stream++ = mix_buffer[i]; + } + + frames_done += subframes; + } +} + +unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total)) +{ + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) + { + std::string errorMessage = std::string("'SDL_InitSubSystem(SDL_INIT_AUDIO)' failed: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", errorMessage.c_str()); + return false; + } + + SDL_AudioSpec specification; + specification.freq = 48000; + specification.format = AUDIO_S16; + specification.channels = 2; + specification.samples = 0x400; // Roughly 10 milliseconds for 48000Hz + specification.callback = Callback; + specification.userdata = NULL; + + SDL_AudioSpec obtained_specification; + if (SDL_OpenAudio(&specification, &obtained_specification) != 0) + { + std::string error_message = std::string("'SDL_OpenAudio' failed: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", error_message.c_str()); + return false; + } + + char driver[20]; + Backend_PrintInfo("Selected SDL audio driver: %s", SDL_AudioDriverName(driver, 20)); + + parent_callback = callback; + + return obtained_specification.freq; +} + +void SoftwareMixerBackend_Deinit(void) +{ + SDL_CloseAudio(); + + SDL_QuitSubSystem(SDL_INIT_AUDIO); +} + +bool SoftwareMixerBackend_Start(void) +{ + SDL_PauseAudio(0); + + return true; +} + +void SoftwareMixerBackend_LockMixerMutex(void) +{ + SDL_LockAudio(); +} + +void SoftwareMixerBackend_UnlockMixerMutex(void) +{ + SDL_UnlockAudio(); +} + +void SoftwareMixerBackend_LockOrganyaMutex(void) +{ + SDL_LockAudio(); +} + +void SoftwareMixerBackend_UnlockOrganyaMutex(void) +{ + SDL_UnlockAudio(); +} diff --git a/src/Backends/Platform/SDL1.cpp b/src/Backends/Platform/SDL1.cpp index 75e0fc46..b8b3d8ea 100644 --- a/src/Backends/Platform/SDL1.cpp +++ b/src/Backends/Platform/SDL1.cpp @@ -11,9 +11,6 @@ #include "../Rendering.h" #include "../../Attributes.h" -#include "../../Main.h" -#include "../../Organya.h" -#include "../../Profile.h" #define DO_KEY(SDL_KEY, BACKEND_KEY) \ case SDL_KEY: \ @@ -22,8 +19,12 @@ static bool keyboard_state[BACKEND_KEYBOARD_TOTAL]; -bool Backend_Init(void) +static void (*window_focus_callback)(bool focus); + +bool Backend_Init(void (*drag_and_drop_callback_param)(const char *path), void (*window_focus_callback_param)(bool focus)) { + window_focus_callback = window_focus_callback_param; + if (SDL_Init(SDL_INIT_VIDEO) == 0) { char driver[20]; @@ -57,9 +58,10 @@ void Backend_PostWindowCreation(void) { } -bool Backend_GetBasePath(std::string *string_buffer) +bool Backend_GetPaths(std::string *module_path, std::string *data_path) { - (void)string_buffer; + (void)module_path; + (void)data_path; return false; } @@ -69,7 +71,7 @@ void Backend_HideMouse(void) SDL_ShowCursor(SDL_DISABLE); } -void Backend_SetWindowIcon(const unsigned char *rgb_pixels, unsigned int width, unsigned int height) +void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height) { SDL_Surface *surface = SDL_CreateRGBSurfaceFrom((void*)rgb_pixels, width, height, 24, width * 3, 0x0000FF, 0x00FF00, 0xFF0000, 0); @@ -84,7 +86,7 @@ void Backend_SetWindowIcon(const unsigned char *rgb_pixels, unsigned int width, } } -void Backend_SetCursor(const unsigned char *rgb_pixels, unsigned int width, unsigned int height) +void Backend_SetCursor(const unsigned char *rgb_pixels, size_t width, size_t height) { (void)rgb_pixels; (void)width; @@ -92,7 +94,7 @@ void Backend_SetCursor(const unsigned char *rgb_pixels, unsigned int width, unsi // SDL1 only supports black and white cursors } -void PlaybackBackend_EnableDragAndDrop(void) +void Backend_EnableDragAndDrop(void) { } @@ -197,10 +199,7 @@ bool Backend_SystemTask(bool active) case SDL_ACTIVEEVENT: if (event.active.state & SDL_APPINPUTFOCUS) { - if (event.active.gain) - ActiveWindow(); - else - InactiveWindow(); + window_focus_callback(event.active.gain); } break; @@ -210,7 +209,6 @@ bool Backend_SystemTask(bool active) break; case SDL_QUIT: - StopOrganyaMusic(); return false; } } @@ -225,7 +223,7 @@ void Backend_GetKeyboardState(bool *out_keyboard_state) void Backend_ShowMessageBox(const char *title, const char *message) { - fprintf(stderr, "ShowMessageBox - '%s' - '%s'\n", title, message); + Backend_PrintInfo("ShowMessageBox - '%s' - '%s'\n", title, message); } ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...) @@ -243,8 +241,8 @@ ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...) va_list argumentList; va_start(argumentList, format); fputs("INFO: ", stdout); - vprintf(format, argumentList); - putchar('\n'); + vfprintf(stdout, format, argumentList); + fputc('\n', stdout); va_end(argumentList); } diff --git a/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp b/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp index 44a7d867..efcfac23 100644 --- a/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp +++ b/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp @@ -8,7 +8,7 @@ #include "../../../Misc.h" -bool WindowBackend_OpenGL_CreateWindow(const char *window_title, int *screen_width, int *screen_height, bool fullscreen) +bool WindowBackend_OpenGL_CreateWindow(const char *window_title, size_t *screen_width, size_t *screen_height, bool fullscreen) { if (SDL_SetVideoMode(*screen_width, *screen_height, 0, SDL_RESIZABLE | SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)) != NULL) { diff --git a/src/Backends/Rendering/Window/Software/SDL1.cpp b/src/Backends/Rendering/Window/Software/SDL1.cpp index cce2f798..84267274 100644 --- a/src/Backends/Rendering/Window/Software/SDL1.cpp +++ b/src/Backends/Rendering/Window/Software/SDL1.cpp @@ -13,7 +13,7 @@ static Uint32 window_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_ANYFORMAT; static SDL_Surface *window_sdlsurface; static SDL_Surface *framebuffer_sdlsurface; -bool WindowBackend_Software_CreateWindow(const char *window_title, int screen_width, int screen_height, bool fullscreen) +bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen) { if (fullscreen) window_flags |= SDL_FULLSCREEN; @@ -34,6 +34,8 @@ bool WindowBackend_Software_CreateWindow(const char *window_title, int screen_wi if (framebuffer_sdlsurface != NULL) { + SDL_LockSurface(framebuffer_sdlsurface); // If this errors then oh dear + Backend_PostWindowCreation(); return true; @@ -67,14 +69,18 @@ unsigned char* WindowBackend_Software_GetFramebuffer(size_t *pitch) void WindowBackend_Software_Display(void) { + SDL_UnlockSurface(framebuffer_sdlsurface); + if (SDL_BlitSurface(framebuffer_sdlsurface, NULL, window_sdlsurface, NULL) < 0) Backend_PrintError("Couldn't blit framebuffer surface to window surface: %s", SDL_GetError()); + SDL_LockSurface(framebuffer_sdlsurface); // If this errors then oh dear + if (SDL_Flip(window_sdlsurface) < 0) Backend_PrintError("Couldn't copy window surface to the screen: %s", SDL_GetError()); } -void WindowBackend_Software_HandleWindowResize(unsigned int width, unsigned int height) +void WindowBackend_Software_HandleWindowResize(size_t width, size_t height) { window_sdlsurface = SDL_SetVideoMode(width, height, bits_per_pixel, window_flags); if (window_sdlsurface == NULL)