From a4edca53b489370b0814a74579acbcc183578355 Mon Sep 17 00:00:00 2001 From: notaz Date: Sat, 18 Sep 2010 16:40:13 +0000 Subject: [PATCH] make OSS detect blocking, adjust audio API git-svn-id: file:///home/notaz/opt/svn/PicoDrive@898 be3aeb3a-fb24-0410-a615-afba39da0efa --- pico/pico.h | 2 +- pico/sound/sound.c | 12 ++++++++---- platform/common/emu.c | 20 +++++++++++++++++++ platform/common/emu.h | 3 +++ platform/gizmondo/emu.c | 6 ++---- platform/gp2x/emu.c | 33 +++++++------------------------ platform/linux/emu.c | 34 +++++++------------------------- platform/linux/sndout_oss.c | 36 ++++++++++++++++++++++++++++++++++ platform/linux/sndout_oss.h | 1 + platform/pandora/plat.c | 39 +++++-------------------------------- platform/psp/emu.c | 5 ++--- 11 files changed, 92 insertions(+), 99 deletions(-) diff --git a/pico/pico.h b/pico/pico.h index e0acda10..ca7577f8 100644 --- a/pico/pico.h +++ b/pico/pico.h @@ -90,7 +90,7 @@ void PicoLoopPrepare(void); void PicoFrame(void); void PicoFrameDrawOnly(void); extern int PicoPad[2]; // Joypads, format is MXYZ SACB RLDU -extern void (*PicoWriteSound)(int len); // called once per frame at the best time to send sound buffer (PsndOut) to hardware +extern void (*PicoWriteSound)(int bytes); // called once per frame at the best time to send sound buffer (PsndOut) to hardware extern void (*PicoMessage)(const char *msg); // callback to output text message from emu typedef enum { PI_ROM, PI_ISPAL, PI_IS40_CELL, PI_IS240_LINES } pint_t; typedef union { int vint; void *vptr; } pint_ret_t; diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 5bb8e9d8..615e324d 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -375,7 +375,8 @@ PICO_INTERNAL void PsndGetSamples(int y) #if SIMPLE_WRITE_SOUND if (y != 224) return; PsndRender(0, PsndLen); - if (PicoWriteSound) PicoWriteSound(PsndLen); + if (PicoWriteSound) + PicoWriteSound(PsndLen * ((PicoOpt & POPT_EN_STEREO) ? 4 : 2)); PsndClear(); #else static int curr_pos = 0; @@ -385,8 +386,11 @@ PICO_INTERNAL void PsndGetSamples(int y) if (emustatus & 2) curr_pos += PsndRender(curr_pos, PsndLen-PsndLen/2); else curr_pos = PsndRender(0, PsndLen); - if (emustatus&1) emustatus|=2; else emustatus&=~2; - if (PicoWriteSound) PicoWriteSound(curr_pos); + if (emustatus & 1) + emustatus |= 2; + else emustatus &= ~2; + if (PicoWriteSound) + PicoWriteSound(curr_pos * ((PicoOpt & POPT_EN_STEREO) ? 4 : 2)); // clear sound buffer PsndClear(); } @@ -424,7 +428,7 @@ PICO_INTERNAL void PsndGetSamplesMS(void) } if (PicoWriteSound != NULL) - PicoWriteSound(length); + PicoWriteSound(length * ((PicoOpt & POPT_EN_STEREO) ? 4 : 2)); PsndClear(); } diff --git a/platform/common/emu.c b/platform/common/emu.c index 8e5a8d58..822d7aab 100644 --- a/platform/common/emu.c +++ b/platform/common/emu.c @@ -1350,6 +1350,26 @@ static void mkdir_path(char *path_with_reserve, int pos, const char *name) lprintf("failed to create: %s\n", path_with_reserve); } +void emu_cmn_forced_frame(int no_scale, int do_emu) +{ + int po_old = PicoOpt; + + memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4); + + PicoOpt |= POPT_ACC_SPRITES; + if (!no_scale) + PicoOpt |= POPT_EN_SOFTSCALE; + + PicoDrawSetOutFormat(PDF_RGB555, 1); + Pico.m.dirtyPal = 1; + if (do_emu) + PicoFrame(); + else + PicoFrameDrawOnly(); + + PicoOpt = po_old; +} + void emu_init(void) { char path[512]; diff --git a/platform/common/emu.h b/platform/common/emu.h index be3e5bfe..cfa3527a 100644 --- a/platform/common/emu.h +++ b/platform/common/emu.h @@ -146,6 +146,9 @@ void emu_get_game_name(char *str150); void emu_set_fastforward(int set_on); void emu_status_msg(const char *format, ...); +/* used by some (but not all) platforms */ +void emu_cmn_forced_frame(int no_scale, int do_emu); + #ifdef __cplusplus } // extern "C" #endif diff --git a/platform/gizmondo/emu.c b/platform/gizmondo/emu.c index 2c7efb2d..2844fb25 100644 --- a/platform/gizmondo/emu.c +++ b/platform/gizmondo/emu.c @@ -273,10 +273,8 @@ static void stdbg(const char *fmt, ...) static void updateSound(int len) { - if (PicoOpt&8) len<<=1; - - snd_all_samples += len; - PsndOut += len; + snd_all_samples += len / 2; + PsndOut += len / 2; if (PsndOut - snd_cbuff >= snd_cbuf_samples) { //if (PsndOut - snd_cbuff != snd_cbuf_samples) diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c index 659d3a71..4addd460 100644 --- a/platform/gp2x/emu.c +++ b/platform/gp2x/emu.c @@ -710,18 +710,13 @@ void plat_update_volume(int has_changed, int is_up) } } -static void updateSound(int len) +static void oss_write_nonblocking(int len) { - len <<= 1; - if (PicoOpt & POPT_EN_STEREO) - len <<= 1; - + // sndout_oss_can_write() is not reliable, only use with no_frmlimit if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len)) return; - /* avoid writing audio when lagging behind to prevent audio lag */ - if (PicoSkipFrame != 2) - sndout_oss_write(PsndOut, len); + sndout_oss_write_nb(PsndOut, len); } void pemu_sound_start(void) @@ -739,7 +734,7 @@ void pemu_sound_start(void) memset(sndBuffer, 0, sizeof(sndBuffer)); PsndOut = sndBuffer; - PicoWriteSound = updateSound; + PicoWriteSound = oss_write_nonblocking; plat_update_volume(0, 0); printf("starting audio: %i len: %i stereo: %i, pal: %i\n", @@ -786,30 +781,16 @@ void pemu_sound_wait(void) void pemu_forced_frame(int no_scale, int do_emu) { - int po_old = PicoOpt; - - PicoOpt &= ~POPT_ALT_RENDERER; - PicoOpt |= POPT_ACC_SPRITES; - if (!no_scale) - PicoOpt |= POPT_EN_SOFTSCALE; - - memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4); - - PicoDrawSetOutFormat(PDF_RGB555, 1); + doing_bg_frame = 1; PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2); PicoDraw32xSetFrameMode(0, 0); PicoDrawSetCallbacks(NULL, NULL); Pico.m.dirtyPal = 1; - doing_bg_frame = 1; - if (do_emu) - PicoFrame(); - else - PicoFrameDrawOnly(); - doing_bg_frame = 0; + emu_cmn_forced_frame(no_scale, do_emu); g_menubg_src_ptr = g_screen_ptr; - PicoOpt = po_old; + doing_bg_frame = 0; } void plat_debug_cat(char *str) diff --git a/platform/linux/emu.c b/platform/linux/emu.c index f5a21c3e..aef21976 100644 --- a/platform/linux/emu.c +++ b/platform/linux/emu.c @@ -210,47 +210,27 @@ void plat_update_volume(int has_changed, int is_up) void pemu_forced_frame(int no_scale, int do_emu) { - int po_old = PicoOpt; - - memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4); - - PicoOpt &= ~POPT_ALT_RENDERER; - PicoOpt |= POPT_ACC_SPRITES; - if (!no_scale) - PicoOpt |= POPT_EN_SOFTSCALE; - - PicoDrawSetOutFormat(PDF_RGB555, 1); PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2); PicoDraw32xSetFrameMode(0, 0); - + PicoDrawSetCallbacks(NULL, NULL); Pico.m.dirtyPal = 1; - if (do_emu) - PicoFrame(); - else - PicoFrameDrawOnly(); + + emu_cmn_forced_frame(no_scale, do_emu); g_menubg_src_ptr = g_screen_ptr; - PicoOpt = po_old; } -static void updateSound(int len) +static void oss_write_nonblocking(int len) { - len <<= 1; - if (PicoOpt & POPT_EN_STEREO) - len <<= 1; - + // sndout_oss_can_write() is not reliable, only use with no_frmlimit if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len)) return; - /* avoid writing audio when lagging behind to prevent audio lag */ - if (PicoSkipFrame != 2) - sndout_oss_write(PsndOut, len); + sndout_oss_write_nb(PsndOut, len); } void pemu_sound_start(void) { - int target_fps = Pico.m.pal ? 50 : 60; - PsndOut = NULL; if (currentConfig.EmuOpt & EOPT_EN_SOUND) @@ -263,7 +243,7 @@ void pemu_sound_start(void) PsndRate, PsndLen, is_stereo, Pico.m.pal); sndout_oss_start(PsndRate, is_stereo, 1); sndout_oss_setvol(currentConfig.volume, currentConfig.volume); - PicoWriteSound = updateSound; + PicoWriteSound = oss_write_nonblocking; plat_update_volume(0, 0); memset(sndBuffer, 0, sizeof(sndBuffer)); PsndOut = sndBuffer; diff --git a/platform/linux/sndout_oss.c b/platform/linux/sndout_oss.c index f9cc6c23..2313d3fb 100644 --- a/platform/linux/sndout_oss.c +++ b/platform/linux/sndout_oss.c @@ -98,6 +98,42 @@ int sndout_oss_write(const void *buff, int len) return write(sounddev, buff, len); } +#include "../common/plat.h" + +/* not really non-blocking, just detects if blocking occurs + * and starts skipping writes in case it does. */ +int sndout_oss_write_nb(const void *buff, int len) +{ + static int lag_counter, skip_counter; + unsigned int t; + int ret; + + if (lag_counter > 2) { + // skip writes if audio starts blocking + lag_counter = 0; + skip_counter = FRAG_COUNT; + } + + if (skip_counter > 0) { + skip_counter--; + return len; + } + + t = plat_get_ticks_ms(); + ret = sndout_oss_write(buff, len); + t = plat_get_ticks_ms() - t; + if (t > 1) { + // this shouldn't really happen, most likely audio is out of sync + lag_counter++; + if (lag_counter > 2) + printf("audio lag %u\n", t); + } + else + lag_counter = 0; + + return ret; +} + int sndout_oss_can_write(int bytes) { audio_buf_info bi; diff --git a/platform/linux/sndout_oss.h b/platform/linux/sndout_oss.h index cfbd70d2..0b3fe6c8 100644 --- a/platform/linux/sndout_oss.h +++ b/platform/linux/sndout_oss.h @@ -2,6 +2,7 @@ int sndout_oss_init(void); int sndout_oss_start(int rate, int stereo, int frames_in_frag); void sndout_oss_stop(void); int sndout_oss_write(const void *buff, int len); +int sndout_oss_write_nb(const void *buff, int len); int sndout_oss_can_write(int bytes); void sndout_oss_sync(void); void sndout_oss_setvol(int l, int r); diff --git a/platform/pandora/plat.c b/platform/pandora/plat.c index a24e3ba2..b95334da 100644 --- a/platform/pandora/plat.c +++ b/platform/pandora/plat.c @@ -240,51 +240,22 @@ static void make_bg(int no_scale) void pemu_forced_frame(int no_scale, int do_emu) { - int po_old = PicoOpt; - - memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4); - - PicoOpt |= POPT_ACC_SPRITES; - if (!no_scale) - PicoOpt |= POPT_EN_SOFTSCALE; - - PicoDrawSetOutFormat(PDF_RGB555, 1); - Pico.m.dirtyPal = 1; doing_bg_frame = 1; - if (do_emu) - PicoFrame(); - else - PicoFrameDrawOnly(); + emu_cmn_forced_frame(no_scale, do_emu); doing_bg_frame = 0; // making a copy because enabling the layer clears it's mem memcpy32((void *)fb_copy, g_screen_ptr, sizeof(fb_copy) / 4); make_bg(no_scale); - - PicoOpt = po_old; } -static void updateSound(int len) +static void oss_write_nonblocking(int len) { - unsigned int t; - - len <<= 1; - if (PicoOpt & POPT_EN_STEREO) - len <<= 1; - - // sndout_oss_can_write() not reliable.. + // sndout_oss_can_write() is not reliable, only use with no_frmlimit if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len)) return; - /* avoid writing audio when lagging behind to prevent audio lag */ - if (PicoSkipFrame == 2) - return; - - t = plat_get_ticks_ms(); - sndout_oss_write(PsndOut, len); - t = plat_get_ticks_ms() - t; - if (t > 1) - printf("audio lag %u\n", t); + sndout_oss_write_nb(PsndOut, len); } void pemu_sound_start(void) @@ -308,7 +279,7 @@ void pemu_sound_start(void) PsndRate, PsndLen, is_stereo, Pico.m.pal); sndout_oss_start(PsndRate, is_stereo, 2); //sndout_oss_setvol(currentConfig.volume, currentConfig.volume); - PicoWriteSound = updateSound; + PicoWriteSound = oss_write_nonblocking; plat_update_volume(0, 0); memset(sndBuffer, 0, sizeof(sndBuffer)); PsndOut = sndBuffer; diff --git a/platform/psp/emu.c b/platform/psp/emu.c index 311a7ecf..feab5f56 100644 --- a/platform/psp/emu.c +++ b/platform/psp/emu.c @@ -637,9 +637,8 @@ static void sound_deinit(void) static void writeSound(int len) { int ret; - if (PicoOpt&8) len<<=1; - PsndOut += len; + PsndOut += len / 2; /*if (PsndOut > sndBuffer_endptr) { memcpy32((int *)(void *)sndBuffer, (int *)endptr, (PsndOut - endptr + 1) / 2); PsndOut = &sndBuffer[PsndOut - endptr]; @@ -651,7 +650,7 @@ static void writeSound(int len) PsndOut = sndBuffer; // signal the snd thread - samples_made += len; + samples_made += len / 2; if (samples_made - samples_done > samples_block*2) { // lprintf("signal, %i/%i\n", samples_done, samples_made); ret = sceKernelSignalSema(sound_sem, 1); -- 2.39.5