From ef4eb506de324df73bcda06f027a20349c69d05f Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 11 May 2008 19:51:59 +0000 Subject: [PATCH] Pico PCM, only one hardcoded mode for now git-svn-id: file:///home/notaz/opt/svn/PicoDrive@444 be3aeb3a-fb24-0410-a615-afba39da0efa --- Pico/Pico.h | 8 +++- Pico/Pico/Memory.c | 16 ++++++- Pico/Pico/Pico.c | 28 ++++++++--- Pico/Pico/xpcm.c | 100 ++++++++++++++++++++++++++++++++++++++++ Pico/PicoInt.h | 4 ++ Pico/sound/sound.c | 5 ++ platform/linux/Makefile | 2 +- 7 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 Pico/Pico/xpcm.c diff --git a/Pico/Pico.h b/Pico/Pico.h index 8398e74..0178590 100644 --- a/Pico/Pico.h +++ b/Pico/Pico.h @@ -71,14 +71,18 @@ extern int (*PicoMCDcloseTray)(void); extern int PicoCDBuffers; // Pico/Pico.c +#define XPCM_BUFFER_SIZE (320+32) typedef struct { int pen_pos[2]; int page; // internal - int fifo_bytes; + int fifo_bytes; // free bytes in FIFO + int fifo_line_bytes; // float part, << 16 int line_counter; - unsigned int r1, r12; + unsigned short r1, r12; + unsigned char xpcm_buffer[XPCM_BUFFER_SIZE+4]; + unsigned char *xpcm_ptr; } picohw_state; extern picohw_state PicoPicohw; diff --git a/Pico/Pico/Memory.c b/Pico/Pico/Memory.c index 2216691..5760324 100644 --- a/Pico/Pico/Memory.c +++ b/Pico/Pico/Memory.c @@ -143,8 +143,20 @@ static void PicoWritePico16(u32 a,u16 d) if ((a&0xfffff0)==0xc00000) { PicoVideoWrite(a,(u16)d); return; } // VDP // if (a == 0x800010) dump(d); - if (a == 0x800010) PicoPicohw.fifo_bytes += 2; - if (a == 0x800012) PicoPicohw.r12 = d; + if (a == 0x800010) + { + PicoPicohw.fifo_bytes += 2; + + if (PicoPicohw.xpcm_ptr < PicoPicohw.xpcm_buffer + XPCM_BUFFER_SIZE) { + *PicoPicohw.xpcm_ptr++ = d >> 8; + *PicoPicohw.xpcm_ptr++ = d; + } + else if (PicoPicohw.xpcm_ptr == PicoPicohw.xpcm_buffer + XPCM_BUFFER_SIZE) { + elprintf(EL_ANOMALY, "xpcm_buffer overflow!"); + PicoPicohw.xpcm_ptr++; + } + } + else if (a == 0x800012) PicoPicohw.r12 = d; elprintf(EL_UIO, "w16: %06x, %04x", a&0xffffff, d); } diff --git a/Pico/Pico/Pico.c b/Pico/Pico/Pico.c index e1133c0..ece6d64 100644 --- a/Pico/Pico/Pico.c +++ b/Pico/Pico/Pico.c @@ -6,8 +6,9 @@ picohw_state PicoPicohw; static int prev_line_cnt_irq3 = 0, prev_line_cnt_irq5 = 0; +static int fifo_bytes_line = (16000<<16)/60/262/2; // fifo bytes/line. FIXME: other rates, modes -static void PicoLineHookPico(int count) +static void PicoLinePico(int count) { PicoPicohw.line_counter += count; @@ -29,11 +30,18 @@ static void PicoLineHookPico(int count) } #endif - if ((PicoPicohw.line_counter & 3) == 0 || count > 10) + if (PicoPicohw.fifo_bytes > 0) { - if (PicoPicohw.fifo_bytes > 0) - PicoPicohw.fifo_bytes--; + PicoPicohw.fifo_line_bytes += fifo_bytes_line * count; + if (PicoPicohw.fifo_line_bytes >= (1<<16)) { + PicoPicohw.fifo_bytes -= PicoPicohw.fifo_line_bytes >> 16; + PicoPicohw.fifo_line_bytes &= 0xffff; + if (PicoPicohw.fifo_bytes < 0) + PicoPicohw.fifo_bytes = 0; + } } + else + PicoPicohw.fifo_line_bytes = 0; #if 0 if (PicoPicohw.line_counter - prev_line_cnt_irq5 > 512) { @@ -44,20 +52,26 @@ static void PicoLineHookPico(int count) #endif } +static void PicoResetPico(void) +{ + PicoPicoPCMReset(); + PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer; +} + PICO_INTERNAL int PicoInitPico(void) { elprintf(EL_STATUS, "Pico detected"); - PicoLineHook = PicoLineHookPico; + PicoLineHook = PicoLinePico; + PicoResetHook = PicoResetPico; PicoAHW = PAHW_PICO; memset(&PicoPicohw, 0, sizeof(PicoPicohw)); PicoPicohw.pen_pos[0] = 0x03c + 352/2; PicoPicohw.pen_pos[1] = 0x200 + 252/2; - prev_line_cnt_irq3 = 0, prev_line_cnt_irq5 = 0; + prev_line_cnt_irq3 = prev_line_cnt_irq5 = 0; // map version register PicoDetectRegion(); - elprintf(EL_STATUS, "a %x", Pico.m.hardware); switch (Pico.m.hardware >> 6) { case 0: PicoPicohw.r1 = 0x00; break; case 1: PicoPicohw.r1 = 0x00; break; diff --git a/Pico/Pico/xpcm.c b/Pico/Pico/xpcm.c new file mode 100644 index 0000000..a92f4d6 --- /dev/null +++ b/Pico/Pico/xpcm.c @@ -0,0 +1,100 @@ +/* + * The following ADPCM algorithm was stolen from MAME aica driver. + * I'm quite sure it's not the right one, but it's the + * best sounding of the ones that I tried. + */ + +#include "../PicoInt.h" + +#define ADPCMSHIFT 8 +#define ADFIX(f) (int) ((double)f * (double)(1< max ) val = max; \ + else if ( val < min ) val = min; \ +} + +const int TableQuant[8] = +{ + ADFIX(0.8984375), + ADFIX(0.8984375), + ADFIX(0.8984375), + ADFIX(0.8984375), + ADFIX(1.19921875), + ADFIX(1.59765625), + ADFIX(2.0), + ADFIX(2.3984375) +}; + +// changed using trial and error.. +//const int quant_mul[16] = { 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15 }; +const int quant_mul[16] = { 1, 3, 5, 7, 9, 11, 13, -1, -1, -3, -5, -7, -9, -11, -13, -15 }; + +static int sample = 0, quant = 0; + +PICO_INTERNAL void PicoPicoPCMReset(void) +{ + sample = 0; + quant = 0x7f; + memset(PicoPicohw.xpcm_buffer, 0, sizeof(PicoPicohw.xpcm_buffer)); +} + +#define XSHIFT 7 + +#define do_sample() \ +{ \ + sample += quant * quant_mul[srcval] >> XSHIFT; \ + quant = (quant * TableQuant[srcval&7]) >> ADPCMSHIFT; \ + Limit(quant, 0x6000, 0x7f); \ + Limit(sample, 32767, -32768); \ +} + +PICO_INTERNAL void PicoPicoPCMUpdate(short *buffer, int length, int stereo) +{ + unsigned char *src = PicoPicohw.xpcm_buffer; + unsigned char *lim = PicoPicohw.xpcm_ptr; + int srcval, stepsamples = (44100<<10)/16000, needsamples = 0; // TODO: stepsamples + + if (src == lim) + { + if (stereo) + // still must expand SN76496 to stereo + for (; length > 0; buffer+=2, length--) + buffer[1] = buffer[0]; + sample = quant = 0; + return; + } + + for (; length > 0 && src < lim; src++) + { + srcval = *src >> 4; + do_sample(); + + for (needsamples += stepsamples; needsamples > (1<<10) && length > 0; needsamples -= (1<<10), length--) { + *buffer++ = sample; + if (stereo) { buffer[0] = buffer[-1]; buffer++; } + } + + srcval = *src & 0xf; + do_sample(); + + for (needsamples += stepsamples; needsamples > (1<<10) && length > 0; needsamples -= (1<<10), length--) { + *buffer++ = sample; + if (stereo) { buffer[0] = buffer[-1]; buffer++; } + } + } + + if (src < lim) { + int di = lim - src; + memmove(PicoPicohw.xpcm_buffer, src, di); + PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer + di; + elprintf(EL_STATUS, "xpcm update: over %i", di); + } + else + { + elprintf(EL_STATUS, "xpcm update: under %i", length); + PicoPicohw.xpcm_ptr = PicoPicohw.xpcm_buffer; + } +} + diff --git a/Pico/PicoInt.h b/Pico/PicoInt.h index b5cb06d..eb78f8c 100644 --- a/Pico/PicoInt.h +++ b/Pico/PicoInt.h @@ -444,6 +444,10 @@ PICO_INTERNAL int PicoFrameMCD(void); // Pico/Pico.c PICO_INTERNAL int PicoInitPico(void); +// Pico/xpcm.c +PICO_INTERNAL void PicoPicoPCMUpdate(short *buffer, int length, int stereo); +PICO_INTERNAL void PicoPicoPCMReset(void); + // Sek.c PICO_INTERNAL int SekInit(void); PICO_INTERNAL int SekReset(void); diff --git a/Pico/sound/sound.c b/Pico/sound/sound.c index 4c13a2f..f0348db 100644 --- a/Pico/sound/sound.c +++ b/Pico/sound/sound.c @@ -326,6 +326,11 @@ PICO_INTERNAL int PsndRender(int offset, int length) if (PicoOpt & POPT_EN_PSG) SN76496Update(PsndOut+offset, length, stereo); + if (PicoAHW & PAHW_PICO) { + PicoPicoPCMUpdate(PsndOut+offset, length, stereo); + return length; + } + // Add in the stereo FM buffer if (PicoOpt & POPT_EN_FM) { buf32_updated = YM2612UpdateOne(buf32, length, stereo, 1); diff --git a/platform/linux/Makefile b/platform/linux/Makefile index 5cde7f6..e3c89fc 100644 --- a/platform/linux/Makefile +++ b/platform/linux/Makefile @@ -42,7 +42,7 @@ OBJS += Pico/cd/Pico.o Pico/cd/Memory.o Pico/cd/Sek.o Pico/cd/LC89510.o \ Pico/cd/cd_sys.o Pico/cd/cd_file.o Pico/cd/cue.o Pico/cd/gfx_cd.o \ Pico/cd/Area.o Pico/cd/Misc.o Pico/cd/pcm.o Pico/cd/buffering.o # Pico - Pico -OBJS += Pico/Pico/Pico.o Pico/Pico/Memory.o +OBJS += Pico/Pico/Pico.o Pico/Pico/Memory.o Pico/Pico/xpcm.o # Pico - sound OBJS += Pico/sound/sound.o Pico/sound/sn76496.o Pico/sound/ym2612.o Pico/sound/mix.o # Pico - carthw -- 2.39.2