mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-09-10 16:53:15 +02:00
[SCD] improved synchronization between PCM chip & SUB-CPU (Willy Beamish)
[SCD] fixed PCM waveform sign bit and output precision
This commit is contained in:
parent
2cec58e50a
commit
c8d4bb4f91
@ -38,7 +38,7 @@
|
|||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
#include "blip.h"
|
#include "blip.h"
|
||||||
|
|
||||||
#define PCM_CLOCKS_PER_SAMPLE (384 * 4)
|
#define PCM_MCLOCKS_PER_SAMPLE (384 * 4)
|
||||||
|
|
||||||
#define pcm scd.pcm_hw
|
#define pcm scd.pcm_hw
|
||||||
|
|
||||||
@ -49,8 +49,8 @@ void pcm_init(double clock, double samplerate)
|
|||||||
pcm_shutdown();
|
pcm_shutdown();
|
||||||
|
|
||||||
/* allocate blip buffers */
|
/* allocate blip buffers */
|
||||||
blip[0] = blip_alloc(clock, samplerate * PCM_CLOCKS_PER_SAMPLE, samplerate / 4);
|
blip[0] = blip_alloc(clock, samplerate * PCM_MCLOCKS_PER_SAMPLE, samplerate / 4);
|
||||||
blip[1] = blip_alloc(clock, samplerate * PCM_CLOCKS_PER_SAMPLE, samplerate / 4);
|
blip[1] = blip_alloc(clock, samplerate * PCM_MCLOCKS_PER_SAMPLE, samplerate / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_shutdown(void)
|
void pcm_shutdown(void)
|
||||||
@ -69,16 +69,19 @@ void pcm_reset(void)
|
|||||||
/* reset default bank */
|
/* reset default bank */
|
||||||
pcm.bank = pcm.ram;
|
pcm.bank = pcm.ram;
|
||||||
|
|
||||||
|
/* reset master clocks counter */
|
||||||
|
pcm.cycles = 0;
|
||||||
|
|
||||||
/* clear blip delta buffers */
|
/* clear blip delta buffers */
|
||||||
blip_clear(blip[0]);
|
blip_clear(blip[0]);
|
||||||
blip_clear(blip[1]);
|
blip_clear(blip[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_update(short *buffer, int length)
|
void pcm_run(unsigned int length)
|
||||||
{
|
{
|
||||||
/* get number of clocks needed */
|
#ifdef LOG_PCM
|
||||||
length = blip_clocks_needed(blip[0], length);
|
error("[%d][%d]run %d PCM samples (from %d)\n", v_counter, s68k.cycles, length, pcm.cycles);
|
||||||
|
#endif
|
||||||
/* check if PCM chip is running */
|
/* check if PCM chip is running */
|
||||||
if (pcm.enabled)
|
if (pcm.enabled)
|
||||||
{
|
{
|
||||||
@ -117,16 +120,21 @@ void pcm_update(short *buffer, int length)
|
|||||||
/* infinite loop should not output any data */
|
/* infinite loop should not output any data */
|
||||||
if (data != 0xff)
|
if (data != 0xff)
|
||||||
{
|
{
|
||||||
/* output L & R subchannels */
|
/* check sign bit (output centered around 0) */
|
||||||
if (data & 0x80)
|
if (data & 0x80)
|
||||||
|
{
|
||||||
|
/* PCM data is positive */
|
||||||
|
data = data & 0x7f;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* PCM data is negative */
|
/* PCM data is negative */
|
||||||
data = -(data & 0x7f);
|
data = -(data & 0x7f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* multiply PCM data with ENV & stereo PAN data then add to outputs (13.6 fixed point) */
|
/* multiply PCM data with ENV & stereo PAN data then add to L/R outputs (14.5 fixed point) */
|
||||||
l += ((data * pcm.chan[j].env * (pcm.chan[j].pan & 0x0F)) >> 6);
|
l += ((data * pcm.chan[j].env * (pcm.chan[j].pan & 0x0F)) >> 5);
|
||||||
r += ((data * pcm.chan[j].env * (pcm.chan[j].pan >> 4)) >> 6);
|
r += ((data * pcm.chan[j].env * (pcm.chan[j].pan >> 4)) >> 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,17 +177,43 @@ void pcm_update(short *buffer, int length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resample to output stereo buffer */
|
/* end of blib buffer frame */
|
||||||
blip_end_frame(blip[0], length);
|
blip_end_frame(blip[0], length);
|
||||||
blip_read_samples(blip[0], buffer, 1);
|
|
||||||
blip_end_frame(blip[1], length);
|
blip_end_frame(blip[1], length);
|
||||||
|
|
||||||
|
/* update PCM master clock counter */
|
||||||
|
pcm.cycles += length * PCM_MCLOCKS_PER_SAMPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_update(short *buffer, int length)
|
||||||
|
{
|
||||||
|
/* get number of internal clocks (samples) needed */
|
||||||
|
unsigned int clocks = blip_clocks_needed(blip[0], length);
|
||||||
|
|
||||||
|
/* run PCM chip */
|
||||||
|
pcm_run(clocks);
|
||||||
|
|
||||||
|
/* resample to output stereo buffer */
|
||||||
|
blip_read_samples(blip[0], buffer, 1);
|
||||||
blip_read_samples(blip[1], buffer + 1, 1);
|
blip_read_samples(blip[1], buffer + 1, 1);
|
||||||
|
|
||||||
|
/* reset PCM master clocks counter */
|
||||||
|
pcm.cycles = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_write(unsigned int address, unsigned char data)
|
void pcm_write(unsigned int address, unsigned char data)
|
||||||
{
|
{
|
||||||
|
/* synchronize PCM chip with SUB-CPU */
|
||||||
|
int clocks = s68k.cycles - pcm.cycles;
|
||||||
|
if (clocks > 0)
|
||||||
|
{
|
||||||
|
/* number of internal clocks (samples) to run */
|
||||||
|
clocks = (clocks + PCM_MCLOCKS_PER_SAMPLE - 1) / PCM_MCLOCKS_PER_SAMPLE;
|
||||||
|
pcm_run(clocks);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef LOG_PCM
|
#ifdef LOG_PCM
|
||||||
error("[%d][%d]PCM %x write -> 0x%02x (%X)\n", v_counter, s68k.cycles, address, data, s68k.pc);
|
error("[%d][%d]PCM write %x -> 0x%02x (%X)\n", v_counter, s68k.cycles, address, data, s68k.pc);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* external RAM is mapped to $1000-$1FFF */
|
/* external RAM is mapped to $1000-$1FFF */
|
||||||
@ -293,8 +327,17 @@ void pcm_write(unsigned int address, unsigned char data)
|
|||||||
|
|
||||||
unsigned char pcm_read(unsigned int address)
|
unsigned char pcm_read(unsigned int address)
|
||||||
{
|
{
|
||||||
|
/* synchronize PCM chip with SUB-CPU */
|
||||||
|
int clocks = s68k.cycles - pcm.cycles;
|
||||||
|
if (clocks > 0)
|
||||||
|
{
|
||||||
|
/* number of internal clocks (samples) to run */
|
||||||
|
clocks = (clocks + PCM_MCLOCKS_PER_SAMPLE - 1) / PCM_MCLOCKS_PER_SAMPLE;
|
||||||
|
pcm_run(clocks);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef LOG_PCM
|
#ifdef LOG_PCM
|
||||||
error("[%d][%d]PCM %x read (%X)\n", v_counter, s68k.cycles, address, s68k.pc);
|
error("[%d][%d]PCM read (%X)\n", v_counter, s68k.cycles, address, s68k.pc);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* external RAM (TODO: verify if possible to read, some docs claim it's not !) */
|
/* external RAM (TODO: verify if possible to read, some docs claim it's not !) */
|
||||||
|
@ -59,6 +59,7 @@ typedef struct
|
|||||||
uint8 status; /* channels ON/OFF status */
|
uint8 status; /* channels ON/OFF status */
|
||||||
uint8 index; /* current channel index */
|
uint8 index; /* current channel index */
|
||||||
uint8 ram[0x10000]; /* 64k external RAM */
|
uint8 ram[0x10000]; /* 64k external RAM */
|
||||||
|
uint32 cycles;
|
||||||
} pcm_t;
|
} pcm_t;
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
|
Loading…
Reference in New Issue
Block a user