diff options
author | neonloop | 2021-08-04 15:09:12 +0000 |
---|---|---|
committer | neonloop | 2021-08-04 15:09:12 +0000 |
commit | 99632f66e74fc57c463072be312d634aeb67bc61 (patch) | |
tree | e4ccaf52b93d04c69865d82556e2ce4cd3a6c599 /plat_sdl.c | |
download | picoarch-99632f66e74fc57c463072be312d634aeb67bc61.tar.gz picoarch-99632f66e74fc57c463072be312d634aeb67bc61.tar.bz2 picoarch-99632f66e74fc57c463072be312d634aeb67bc61.zip |
Initial commit
Diffstat (limited to 'plat_sdl.c')
-rw-r--r-- | plat_sdl.c | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/plat_sdl.c b/plat_sdl.c new file mode 100644 index 0000000..7223a0d --- /dev/null +++ b/plat_sdl.c @@ -0,0 +1,277 @@ +#include <SDL/SDL.h> +#include "core.h" +#include "libpicofe/fonts.h" +#include "libpicofe/menu.h" +#include "libpicofe/plat.h" +#include "plat.h" +#include "scale.h" + +static SDL_Surface* screen; + +struct audio_state { + int buf_w; + int max_buf_w; + int buf_r; + size_t buf_len; + struct audio_frame *buf; + int freq; + int in_sample_rate; + int out_sample_rate; +}; + +struct audio_state audio; + +static char msg[HUD_LEN]; + +static void video_clear_msg(uint16_t *dst, uint32_t h, uint32_t pitch) +{ + memset(dst + (h - 10) * pitch, 0, 10 * pitch * sizeof(uint16_t)); +} + +static void video_print_msg(uint16_t *dst, uint32_t h, uint32_t pitch, char *msg) +{ + basic_text_out16_nf(dst, pitch, 2, h - 10, msg); +} + +static int audio_resample_nearest(struct audio_frame data) { + static int diff = 0; + int consumed = 0; + + if (diff <= 0) { + audio.buf[audio.buf_w++] = data; + if (audio.buf_w >= audio.buf_len) audio.buf_w = 0; + + diff += audio.in_sample_rate; + } + + if (diff > 0) { + consumed++; + diff -= audio.out_sample_rate; + } + + return consumed; +} + +static void *fb_flip(void) +{ + SDL_Flip(screen); + return screen->pixels; +} + +void plat_video_menu_enter(int is_rom_loaded) +{ +} + +void plat_video_menu_begin(void) +{ + g_menuscreen_ptr = fb_flip(); +} + +void plat_video_menu_end(void) +{ + g_menuscreen_ptr = fb_flip(); +} + +void plat_video_menu_leave(void) +{ + SDL_LockSurface(screen); + memset(g_menuscreen_ptr, 0, SCREEN_WIDTH * SCREEN_HEIGHT * SCREEN_BPP); + SDL_UnlockSurface(screen); + g_menuscreen_ptr = fb_flip(); + SDL_LockSurface(screen); + memset(g_menuscreen_ptr, 0, SCREEN_WIDTH * SCREEN_HEIGHT * SCREEN_BPP); + SDL_UnlockSurface(screen); +} + +void plat_video_open(void) +{ +} + +void plat_video_set_msg(const char *new_msg) +{ + snprintf(msg, HUD_LEN, "%s", new_msg); +} + +void plat_video_process(const void *data, unsigned width, unsigned height, size_t pitch) { + SDL_LockSurface(screen); + + if (msg[0]) + video_clear_msg(screen->pixels, screen->h, screen->pitch / SCREEN_BPP); + + scale(width, height, pitch, data, screen->pixels); + + if (msg[0]) + video_print_msg(screen->pixels, screen->h, screen->pitch / SCREEN_BPP, msg); + + SDL_UnlockSurface(screen); +} + +void plat_video_flip(void) +{ + g_menuscreen_ptr = fb_flip(); + msg[0] = 0; +} + +void plat_video_close(void) +{ +} + +static void plat_sound_callback(void *unused, uint8_t *stream, int len) +{ + int16_t *p = (int16_t *)stream; + len /= (sizeof(int16_t) * 2); + + while (audio.buf_r != audio.buf_w && len > 0) { + *p++ = audio.buf[audio.buf_r].left; + *p++ = audio.buf[audio.buf_r].right; + audio.max_buf_w = audio.buf_r; + + len--; + audio.buf_r++; + + if (audio.buf_r >= audio.buf_len) audio.buf_r = 0; + } + + while(len > 0) { + *p++ = 0; + --len; + } +} + +static void plat_sound_finish(void) +{ + SDL_PauseAudio(1); + SDL_CloseAudio(); + if (audio.buf) { + free(audio.buf); + audio.buf = NULL; + } +} + +static int plat_sound_init(void) +{ + if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { + return -1; + } + + SDL_AudioSpec spec, received; + + spec.freq = SAMPLE_RATE; + spec.format = AUDIO_S16; + spec.channels = 2; + spec.samples = 512; + spec.callback = plat_sound_callback; + + if (SDL_OpenAudio(&spec, &received) < 0) { + plat_sound_finish(); + return -1; + } + + audio.in_sample_rate = sample_rate; + audio.out_sample_rate = received.freq; + plat_sound_resize_buffer(); + + SDL_PauseAudio(0); + return 0; +} + +float plat_sound_capacity(void) +{ + int buffered = 0; + if (audio.buf_w != audio.buf_r) { + buffered = audio.buf_w > audio.buf_r ? + audio.buf_w - audio.buf_r : + (audio.buf_w + audio.buf_len) - audio.buf_r; + } + + return 1.0 - (float)buffered / audio.buf_len; +} + +#define BATCH_SIZE 100 +void plat_sound_write(const struct audio_frame *data, int frames) +{ + int consumed = 0; + SDL_LockAudio(); + + while (frames > 0) { + int tries = 0; + int amount = MIN(BATCH_SIZE, frames); + + while (tries < 10 && audio.buf_w == audio.max_buf_w) { + tries++; + SDL_UnlockAudio(); + + if (!limit_frames) + return; + + plat_sleep_ms(1); + SDL_LockAudio(); + } + + while (amount && audio.buf_w != audio.max_buf_w) { + consumed = audio_resample_nearest(*data); + data += consumed; + amount -= consumed; + frames -= consumed; + } + } + SDL_UnlockAudio(); +} + +void plat_sound_resize_buffer(void) { + size_t buf_size; + audio.buf_len = current_audio_buffer_size * audio.in_sample_rate / frame_rate; + buf_size = audio.buf_len * sizeof(struct audio_frame); + audio.buf = realloc(audio.buf, buf_size); + + if (!audio.buf) { + PA_ERROR("Error initializing sound buffer\n"); + plat_sound_finish(); + return; + } + + memset(audio.buf, 0, buf_size); + audio.buf_w = 0; + audio.buf_r = 0; + audio.max_buf_w = audio.buf_len - 1; +} + +void plat_sdl_event_handler(void *event_) +{ +} + +int plat_init(void) +{ + SDL_Init(SDL_INIT_VIDEO); + screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP * 8, SDL_SWSURFACE); + + if (screen == NULL) { + PA_ERROR("%s, failed to set video mode\n", __func__); + return -1; + } + + SDL_ShowCursor(0); + + g_menuscreen_w = SCREEN_WIDTH; + g_menuscreen_h = SCREEN_HEIGHT; + g_menuscreen_pp = SCREEN_WIDTH; + g_menuscreen_ptr = fb_flip(); + + if (in_sdl_init(&in_sdl_platform_data, plat_sdl_event_handler)) { + PA_ERROR("SDL input failed to init: %s\n", SDL_GetError()); + return -1; + } + in_probe(); + + if (plat_sound_init()) { + PA_ERROR("SDL sound failed to init: %s\n", SDL_GetError()); + return -1; + } + return 0; +} + +void plat_finish(void) +{ + plat_sound_finish(); + SDL_Quit(); +} |