From: notaz Date: Fri, 17 Sep 2010 22:57:14 +0000 (+0000) Subject: redo OSS frag setup. Compute real pollux rate X-Git-Tag: v1.85~161 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f6a4e907bc86412c9279809d133e6e2fb896c0c;p=picodrive.git redo OSS frag setup. Compute real pollux rate git-svn-id: file:///home/notaz/opt/svn/PicoDrive@896 be3aeb3a-fb24-0410-a615-afba39da0efa --- diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c index 625f481a..659d3a71 100644 --- a/platform/gp2x/emu.c +++ b/platform/gp2x/emu.c @@ -17,6 +17,7 @@ #include "plat_gp2x.h" #include "soc.h" +#include "soc_pollux.h" #include "../common/plat.h" #include "../common/menu.h" #include "../common/arm_utils.h" @@ -733,21 +734,22 @@ void pemu_sound_start(void) if (currentConfig.EmuOpt & EOPT_EN_SOUND) { int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0; - int target_fps = Pico.m.pal ? 50 : 60; - int frame_samples, snd_excess_add; int snd_rate_oss = PsndRate; gp2x_soc_t soc; + memset(sndBuffer, 0, sizeof(sndBuffer)); + PsndOut = sndBuffer; + PicoWriteSound = updateSound; + plat_update_volume(0, 0); + + printf("starting audio: %i len: %i stereo: %i, pal: %i\n", + PsndRate, PsndLen, is_stereo, Pico.m.pal); + sndout_oss_start(snd_rate_oss, is_stereo, 1); + sndout_oss_setvol(currentConfig.volume, currentConfig.volume); + soc = soc_detect(); - if (soc == SOCID_POLLUX) { - /* POLLUX pain: DPLL1 / mclk_div / bitclk_div / 4 */ - switch (PsndRate) { - case 44100: PsndRate = 44171; break; // 44170.673077 - case 22050: PsndRate = 22086; break; // 22085.336538 - case 11025: PsndRate = 11043; break; // 11042.668269 - default: break; - } - } + if (soc == SOCID_POLLUX) + PsndRate = pollux_get_real_snd_rate(PsndRate); #define SOUND_RERATE_FLAGS (POPT_EN_FM|POPT_EN_PSG|POPT_EN_STEREO|POPT_EXT_FM|POPT_EN_MCD_CDDA) if (PsndRate != PsndRate_old || Pico.m.pal != pal_old || ((PicoOpt & POPT_EXT_FM) && crashed_940) || @@ -755,40 +757,25 @@ void pemu_sound_start(void) PsndRerate(Pico.m.frame_count ? 1 : 0); } - memset(sndBuffer, 0, sizeof(sndBuffer)); - PsndOut = sndBuffer; - PicoWriteSound = updateSound; PsndRate_old = PsndRate; PicoOpt_old = PicoOpt; pal_old = Pico.m.pal; - plat_update_volume(0, 0); - - frame_samples = PsndLen; - snd_excess_add = ((PsndRate - PsndLen * target_fps)<<16) / target_fps; - if (snd_excess_add != 0) - frame_samples++; - if (soc == SOCID_POLLUX) - frame_samples *= 2; /* force larger buffer */ - - printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n", - PsndRate, PsndLen, snd_excess_add, is_stereo, Pico.m.pal); - sndout_oss_setvol(currentConfig.volume, currentConfig.volume); - sndout_oss_start(snd_rate_oss, frame_samples, is_stereo); - - /* Wiz's sound hardware needs more prebuffer */ - if (soc == SOCID_POLLUX) - updateSound(frame_samples); } } +static const int sound_rates[] = { 44100, 32000, 22050, 16000, 11025, 8000 }; + void pemu_sound_stop(void) { - /* get back from Wiz pain */ - switch (PsndRate) { - case 44171: PsndRate = 44100; break; - case 22086: PsndRate = 22050; break; - case 11043: PsndRate = 11025; break; - default: break; + int i; + + /* get back from Pollux pain */ + PsndRate += 1000; + for (i = 0; i < ARRAY_SIZE(sound_rates); i++) { + if (PsndRate >= sound_rates[i]) { + PsndRate = sound_rates[i]; + break; + } } } @@ -801,7 +788,6 @@ void pemu_forced_frame(int no_scale, int do_emu) { int po_old = PicoOpt; - doing_bg_frame = 1; PicoOpt &= ~POPT_ALT_RENDERER; PicoOpt |= POPT_ACC_SPRITES; if (!no_scale) @@ -815,13 +801,14 @@ void pemu_forced_frame(int no_scale, int do_emu) PicoDrawSetCallbacks(NULL, NULL); Pico.m.dirtyPal = 1; + doing_bg_frame = 1; if (do_emu) PicoFrame(); else PicoFrameDrawOnly(); + doing_bg_frame = 0; g_menubg_src_ptr = g_screen_ptr; - doing_bg_frame = 0; PicoOpt = po_old; } diff --git a/platform/gp2x/soc_pollux.c b/platform/gp2x/soc_pollux.c index 9dae4903..ab56b993 100644 --- a/platform/gp2x/soc_pollux.c +++ b/platform/gp2x/soc_pollux.c @@ -39,7 +39,8 @@ static int fbdev = -1; static char cpuclk_was_changed = 0; static unsigned short memtimex_old[2]; -static unsigned int pllsetreg0; +static unsigned int pllsetreg0_old; +static unsigned int timer_drift; // count per real second static int last_pal_setting = 0; @@ -219,13 +220,13 @@ static int gp2x_read_battery_(void) #define TIMER_BASE3 0x1980 #define TIMER_REG(x) memregl[(TIMER_BASE3 + x) >> 2] -unsigned int gp2x_get_ticks_us_(void) +static unsigned int gp2x_get_ticks_us_(void) { TIMER_REG(0x08) = 0x4b; /* run timer, latch value */ return TIMER_REG(0); } -unsigned int gp2x_get_ticks_ms_(void) +static unsigned int gp2x_get_ticks_ms_(void) { /* approximate /= 1000 */ unsigned long long v64; @@ -261,10 +262,42 @@ static int decode_pll(unsigned int reg) return v; } +int pollux_get_real_snd_rate(int req_rate) +{ + int clk0_src, clk1_src, rate, div; + + clk0_src = (memregl[0xdbc4>>2] >> 1) & 7; + clk1_src = (memregl[0xdbc8>>2] >> 1) & 7; + if (clk0_src > 1 || clk1_src != 7) { + fprintf(stderr, "get_real_snd_rate: bad clk sources: %d %d\n", clk0_src, clk1_src); + return req_rate; + } + + rate = decode_pll(clk0_src ? memregl[0xf008>>2] : memregl[0xf004>>2]); + + // apply divisors + div = ((memregl[0xdbc4>>2] >> 4) & 0x1f) + 1; + rate /= div; + div = ((memregl[0xdbc8>>2] >> 4) & 0x1f) + 1; + rate /= div; + rate /= 64; + + //printf("rate %d\n", rate); + rate -= rate * timer_drift / 1000000; + printf("adjusted rate: %d\n", rate); + + if (rate < 8000-1000 || rate > 44100+1000) { + fprintf(stderr, "get_real_snd_rate: got bad rate: %d\n", rate); + return req_rate; + } + + return rate; +} + void pollux_init(void) { struct fb_fix_screeninfo fbfix; - int i, ret, rate; + int i, ret, rate, timer_div; memdev = open("/dev/mem", O_RDWR); if (memdev == -1) { @@ -320,16 +353,18 @@ void pollux_init(void) /* find what PLL1 runs at, for the timer */ rate = decode_pll(memregl[0xf008>>2]); printf("PLL1 @ %dHz\n", rate); - rate /= 1000000; /* setup timer */ - if (1 <= rate && rate <= 256) { + timer_div = (rate + 500000) / 1000000; + if (1 <= timer_div && timer_div <= 256) { + timer_drift = (rate - (timer_div * 1000000)) / timer_div; + if (TIMER_REG(0x08) & 8) { fprintf(stderr, "warning: timer in use, overriding!\n"); timer_cleanup(); } - TIMER_REG(0x44) = ((rate - 1) << 4) | 2; /* using PLL1, divide by it's rate */ + TIMER_REG(0x44) = ((timer_div - 1) << 4) | 2; /* using PLL1, divide by it's rate */ TIMER_REG(0x40) = 0x0c; /* clocks on */ TIMER_REG(0x08) = 0x6b; /* run timer, clear irq, latch value */ @@ -344,7 +379,7 @@ void pollux_init(void) gp2x_get_ticks_us = plat_get_ticks_us_good; } - pllsetreg0 = memregl[0xf004>>2]; + pllsetreg0_old = memregl[0xf004>>2]; memtimex_old[0] = memregs[0x14802>>1]; memtimex_old[1] = memregs[0x14804>>1]; @@ -384,7 +419,7 @@ void pollux_finish(void) gp2x_video_changemode_ll_(16); unset_ram_timings_(); if (cpuclk_was_changed) { - memregl[0xf004>>2] = pllsetreg0; + memregl[0xf004>>2] = pllsetreg0_old; memregl[0xf07c>>2] |= 0x8000; } timer_cleanup(); diff --git a/platform/gp2x/soc_pollux.h b/platform/gp2x/soc_pollux.h new file mode 100644 index 00000000..f26e594b --- /dev/null +++ b/platform/gp2x/soc_pollux.h @@ -0,0 +1,2 @@ + +int pollux_get_real_snd_rate(int req_rate); diff --git a/platform/linux/emu.c b/platform/linux/emu.c index 0b4361d1..f5a21c3e 100644 --- a/platform/linux/emu.c +++ b/platform/linux/emu.c @@ -255,19 +255,13 @@ void pemu_sound_start(void) if (currentConfig.EmuOpt & EOPT_EN_SOUND) { - int snd_excess_add, frame_samples; int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0; PsndRerate(Pico.m.frame_count ? 1 : 0); - frame_samples = PsndLen; - snd_excess_add = ((PsndRate - PsndLen * target_fps)<<16) / target_fps; - if (snd_excess_add != 0) - frame_samples++; - - printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n", - PsndRate, PsndLen, snd_excess_add, is_stereo, Pico.m.pal); - sndout_oss_start(PsndRate, frame_samples, is_stereo); + printf("starting audio: %i len: %i stereo: %i, pal: %i\n", + PsndRate, PsndLen, is_stereo, Pico.m.pal); + sndout_oss_start(PsndRate, is_stereo, 1); sndout_oss_setvol(currentConfig.volume, currentConfig.volume); PicoWriteSound = updateSound; plat_update_volume(0, 0); diff --git a/platform/linux/sndout_oss.c b/platform/linux/sndout_oss.c index 52496888..f9cc6c23 100644 --- a/platform/linux/sndout_oss.c +++ b/platform/linux/sndout_oss.c @@ -12,6 +12,7 @@ static int sounddev = -1, mixerdev = -1; static int can_write_safe; +#define FRAG_COUNT 4 int sndout_oss_init(void) { @@ -35,14 +36,14 @@ void sndout_oss_stop(void) sounddev = -1; } -int sndout_oss_start(int rate, int frame_samples, int stereo) +int sndout_oss_start(int rate, int stereo, int frames_in_frag) { - static int s_oldrate = 0, s_old_fsamples = 0, s_oldstereo = 0; + static int s_oldrate = 0, s_oldstereo = 0; int frag, bsize, bits, ret; // GP2X: if no settings change, we don't need to do anything, // since audio is never stopped there - if (sounddev >= 0 && rate == s_oldrate && s_old_fsamples == frame_samples && s_oldstereo == stereo) + if (sounddev >= 0 && rate == s_oldrate && s_oldstereo == stereo) return 0; sndout_oss_stop(); @@ -57,14 +58,15 @@ int sndout_oss_start(int rate, int frame_samples, int stereo) } } - // calculate buffer size. We want to fit 1 frame worth of sound data. - // Also ignore mono because both GP2X and Wiz mixes mono to stereo anyway. - bsize = frame_samples << 2; + // try to fit frames_in_frag frames worth of data in fragment + // ignore mono because it's unlikely to be used and + // both GP2X and Wiz mixes mono to stereo anyway. + bsize = (frames_in_frag * rate / 50) * 4; for (frag = 0; bsize; bsize >>= 1, frag++) ; - frag |= 16 << 16; // fragment count + frag |= FRAG_COUNT << 16; // fragment count ret = ioctl(sounddev, SNDCTL_DSP_SETFRAGMENT, &frag); if (ret < 0) perror("SNDCTL_DSP_SETFRAGMENT failed"); @@ -86,7 +88,7 @@ int sndout_oss_start(int rate, int frame_samples, int stereo) printf("sndout_oss_start: %d/%dbit/%s, %d buffers of %i bytes\n", rate, bits, stereo ? "stereo" : "mono", frag >> 16, 1 << (frag & 0xffff)); - s_oldrate = rate; s_old_fsamples = frame_samples; s_oldstereo = stereo; + s_oldrate = rate; s_oldstereo = stereo; can_write_safe = 0; return 0; } @@ -111,8 +113,8 @@ int sndout_oss_can_write(int bytes) if (ret < 0) return 1; - // have enough bytes to write + 4 extra frags - return bi.bytes - bi.fragsize * 4 >= bytes ? 1 : 0; + // have enough bytes to write + 1 frag + return bi.bytes - bi.fragsize >= bytes ? 1 : 0; } void sndout_oss_sync(void) diff --git a/platform/linux/sndout_oss.h b/platform/linux/sndout_oss.h index 2c48860e..cfbd70d2 100644 --- a/platform/linux/sndout_oss.h +++ b/platform/linux/sndout_oss.h @@ -1,5 +1,5 @@ int sndout_oss_init(void); -int sndout_oss_start(int rate, int frame_samples, int stereo); +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_can_write(int bytes);