aboutsummaryrefslogtreecommitdiff
path: root/plat_sdl.c
diff options
context:
space:
mode:
authorneonloop2021-08-04 15:09:12 +0000
committerneonloop2021-08-04 15:09:12 +0000
commit99632f66e74fc57c463072be312d634aeb67bc61 (patch)
treee4ccaf52b93d04c69865d82556e2ce4cd3a6c599 /plat_sdl.c
downloadpicoarch-99632f66e74fc57c463072be312d634aeb67bc61.tar.gz
picoarch-99632f66e74fc57c463072be312d634aeb67bc61.tar.bz2
picoarch-99632f66e74fc57c463072be312d634aeb67bc61.zip
Initial commit
Diffstat (limited to 'plat_sdl.c')
-rw-r--r--plat_sdl.c277
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();
+}