Skip to content

Commit

Permalink
patch by DJRobX:
Browse files Browse the repository at this point in the history
Apply sound throttling adjustments to WPC DCS games.
Apply sound throttling to WhiteStar II
Make variables that are being read across VPM interface threads volatile so the CPU knows not to cache them.

git-svn-id: https://svn.code.sf.net/p/pinmame/code/trunk@4103 6f51dfdd-75df-4273-8f3b-818b1e6aa8bf
  • Loading branch information
toxieainc committed Nov 26, 2016
1 parent 7487c0c commit 4f6a5ed
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 62 deletions.
15 changes: 1 addition & 14 deletions src/sound/tms320av120.c
Original file line number Diff line number Diff line change
Expand Up @@ -814,17 +814,6 @@ WRITE_HANDLER( TMS320AV120_data_w )
//Reset Frame Buffer position for reading
tms320av120[chipnum].fb_pos = 0;

//Handle PCM wraparound.. (Leave room for this frame)

// this code is wrong. It's a circular buffer - we are full when we are just behind the last sample being output.
/* if( (tms320av120[chipnum].pcm_pos+1152) == CAP_PCMBUFFER_SIZE) {
//Flag SREQ HI to stop data coming in!
set_sreq_line(chipnum,1);
}*/




//Decode the frame (generates 1152 pcm samples)
DecodeLayer2(chipnum); //note: tms320av120[chipnum].pcm_pos will be adjusted +1152 inside the decode function

Expand All @@ -836,15 +825,13 @@ WRITE_HANDLER( TMS320AV120_data_w )
if(tms320av120[chipnum].pcm_pos == CAP_PCMBUFFER_SIZE)
tms320av120[chipnum].pcm_pos=0;

// Circular buffer check. If its a normal case of the output being behind the buffer head, remaining is head - tail.

// If our buffer is full, signal to stop sending data
if(get_sound_buffer_consumed(chipnum) >= CAP_PCMBUFFER_SIZE-1152)
{
//Flag SREQ HI to stop data coming in!
set_sreq_line(chipnum,1);
}


//Reset flag to search for next header
tms320av120[chipnum].found_header = 0;

Expand Down
6 changes: 5 additions & 1 deletion src/win32com/Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ void CController::GetProductVersion(int *nVersionNo0, int *nVersionNo1, int *nVe
* IController: Class construction and destruction
*************************************************/
CController::CController() {
MMRESULT result;

result = timeGetDevCaps(&caps, sizeof(caps));
if (result == TIMERR_NOERROR)
timeBeginPeriod(caps.wPeriodMin);
cli_frontend_init();

lstrcpy(m_szSplashInfoLine, "");
Expand Down Expand Up @@ -190,7 +194,7 @@ CController::CController() {
CController::~CController() {
Stop();
CloseHandle(m_hEmuIsRunning);

timeEndPeriod(caps.wPeriodMin);
m_pGame->Release();
m_pGameSettings->Release();
m_pGames->Release();
Expand Down
1 change: 1 addition & 0 deletions src/win32com/Controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class CController :
private:
void GetProductVersion(int *nVersionNo0, int *nVersionNo1, int *nVersionNo2, int *nVersionNo3);
static DWORD FAR PASCAL RunController(CController* pController);
TIMECAPS caps;

public:

Expand Down
28 changes: 15 additions & 13 deletions src/windows/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -687,21 +687,31 @@ extern HANDLE g_hEnterThrottle;
extern int g_iSyncFactor;
int iCurrentSyncValue = 512;
#endif
int g_iThrottleAdj = 0, g_iThrottleAdjCur = 0;
int g_iThrottleAdj = 0;

#define THROTTLE_MAX_ADJ 1000

#ifdef DEBUG_SOUND
void DebugSound(char *s)
{
FILE *stream = fopen("C:\\temp\\sndlog.txt", "a");
fprintf(stream, "%s\n", s);
fclose(stream);
}
#endif

void SetThrottleAdj(int adj)
{

#ifdef DEBUG_SOUND
char tmp[81];
static int last = 0;

if (adj != last)
{
sprintf(tmp, "Set throttle adj: %d (cur %d)\n", adj, g_iThrottleAdjCur);
OutputDebugString(tmp);
sprintf(tmp, "Set throttle adj: %d (cur %d)", adj, g_iThrottleAdjCur);
DebugSound(tmp);
last = adj;
}
#endif
g_iThrottleAdj = adj;
}

Expand Down Expand Up @@ -746,14 +756,6 @@ void throttle_speed_part(int part, int totalparts)

if (g_iThrottleAdj)
{
/*if (totalparts == 1)
{
g_iThrottleAdjCur += g_iThrottleAdj;
if (g_iThrottleAdjCur > THROTTLE_MAX_ADJ)
g_iThrottleAdjCur = THROTTLE_MAX_ADJ;
if (g_iThrottleAdjCur < -THROTTLE_MAX_ADJ)
g_iThrottleAdjCur = -THROTTLE_MAX_ADJ;
}*/
target -= (cycles_t)(g_iThrottleAdj*ticks_per_sleep_msec);
}
// sync
Expand Down
54 changes: 54 additions & 0 deletions src/wpc/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include "snd_cmd.h"
#include "mech.h"
#include "core.h"
#include "video.h"

#ifdef PROC_SUPPORT
#include "p-roc/p-roc.h"
#endif
Expand Down Expand Up @@ -1925,6 +1927,58 @@ UINT8 core_calc_modulated_light(UINT32 bits, UINT32 bit_count, UINT8 *prev_level
return outputlevel;
}

void core_sound_throttle_adj(int sIn, int *sOut, int buffersize, int samplerate)
{
int delta;

if (sIn >= *sOut)
delta = sIn - *sOut;
else
delta = sIn + buffersize - *sOut;

#ifdef DEBUG_SOUND
{
char tmp[161];
LARGE_INTEGER performance_count;
QueryPerformanceCounter(&performance_count);

sprintf(tmp, "snd clk: %llu in: %d out: %d size: %d delta %d", performance_count.QuadPart, sIn, *sOut, buffersize, delta);
DebugSound(tmp);
}
#endif

if (delta > samplerate * 50 / 1000)
{
// Over 50ms delta and throttle didn't catch it fast enough. Drop some samples, but not so
// much that we have to restart from a zero buffer.
*sOut = sIn - (samplerate * 20 / 1000);
if (*sOut < 0)
*sOut += buffersize;

SetThrottleAdj(0);
}
else if (delta > samplerate * 35 / 1000)
{
SetThrottleAdj(-6);
}
else if (delta > samplerate * 25 / 1000)
{
SetThrottleAdj(-1);
}
else if (delta < samplerate * 10 / 1000)
{
SetThrottleAdj(10);
}
else if (delta < samplerate * 20 / 1000)
{
SetThrottleAdj(2);
}
else
{
SetThrottleAdj(0);
}
}

/*----------------------------------------------
/ Add a timer when building the machine driver
/-----------------------------------------------*/
Expand Down
23 changes: 12 additions & 11 deletions src/wpc/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,26 +385,26 @@ typedef union { struct { UINT8 lo, hi; } b; UINT16 w; } core_tSeg[CORE_SEGCOUNT]
typedef union { struct { UINT8 hi, lo; } b; UINT16 w; } core_tSeg[CORE_SEGCOUNT];
#endif /* LSB_FIRST */
typedef struct {
UINT8 swMatrix[CORE_MAXSWCOL];
UINT8 invSw[CORE_MAXSWCOL]; /* Active low switches */
UINT8 lampMatrix[CORE_MAXLAMPCOL], tmpLampMatrix[CORE_MAXLAMPCOL];
UINT8 RGBlamps[CORE_MAXRGBLAMPS];
volatile UINT8 swMatrix[CORE_MAXSWCOL];
volatile UINT8 invSw[CORE_MAXSWCOL]; /* Active low switches */
volatile UINT8 lampMatrix[CORE_MAXLAMPCOL], tmpLampMatrix[CORE_MAXLAMPCOL];
volatile UINT8 RGBlamps[CORE_MAXRGBLAMPS];
core_tSeg segments; /* segments data from driver */
UINT16 drawSeg[CORE_SEGCOUNT]; /* segments drawn */
UINT32 solenoids; /* on power driver bord */
UINT32 solenoids2; /* flipper solenoids */
UINT8 modulatedSolenoids[2][CORE_MODSOL_MAX];
UINT32 pulsedSolState; /* current pulse value of solenoids on driver board */
volatile UINT32 solenoids; /* on power driver bord */
volatile UINT32 solenoids2; /* flipper solenoids */
volatile UINT8 modulatedSolenoids[2][CORE_MODSOL_MAX];
volatile UINT32 pulsedSolState; /* current pulse value of solenoids on driver board */
UINT64 lastSol; /* last state of all solenoids */
int gi[CORE_MAXGI]; /* WPC gi strings */
volatile int gi[CORE_MAXGI]; /* WPC gi strings */
int simAvail; /* simulator (keys) available */
int soundEn; /* Sound enabled ? */
int diagnosticLed; /* data relating to diagnostic led(s)*/
volatile int diagnosticLed; /* data relating to diagnostic led(s)*/
#ifdef PROC_SUPPORT
int p_rocEn; /* P-ROC support enable */
int isKickbackLamp[255];
#endif
char segDim[CORE_SEGCOUNT]; /* segments dimming */
volatile char segDim[CORE_SEGCOUNT]; /* segments dimming */
} core_tGlobals;
extern core_tGlobals coreGlobals;
/* shortcut for coreGlobals */
Expand Down Expand Up @@ -483,6 +483,7 @@ INLINE void core_update_modulated_light(UINT32 *light, int bit){
}

extern UINT8 core_calc_modulated_light(UINT32 bits, UINT32 bit_count, UINT8 *prev_level);
extern void core_sound_throttle_adj(int sIn, int *sOut, int buffersize, int samplerate);

/*-- nvram handling --*/
extern void core_nvram(void *file, int write, void *mem, size_t length, UINT8 init);
Expand Down
12 changes: 4 additions & 8 deletions src/wpc/desound.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,6 @@ static INTERRUPT_GEN(de2s_firq) {
#define ARMSNDBUFSIZE 4 // Sound command input port buffer size (doublebuffer should actually be good enough, but lets play safe)
#define BUFFSIZE 0x40000

#define AT91_SOUND_CATCHUP_HACK // Catch up during sound buffer update, if generated sound and consumed sound is too far apart (e.g. somewhere some frequencies or CPU cycles do not match yet :/)

//Includes
#if AT91IMP_MAKE_WAVS
#include "sound/wavwrite.h"
Expand Down Expand Up @@ -762,15 +760,13 @@ static void at91_sh_update(int num, INT16 *buffer[2], int length)
lastsamp[jj] = buffer[jj][ii];
}

// Will adjust throttling to keep sound buffers at a desired place.
// Also includes previous "sound catchup" hack should throttling strategy not work.
core_sound_throttle_adj(sampnum[jj], &sampout[jj], BUFFSIZE, WAVE_OUT_RATE);

/* fill the rest with last sample output */ //!! should only be needed, if at all, initially?
for ( ; ii < length; ii++)
buffer[jj][ii] = lastsamp[jj];

#ifdef AT91_SOUND_CATCHUP_HACK
/* if sound is more than 1s/10 = 100ms apart, then catch up */
if (sampnum[jj] - sampout[jj] > WAVE_OUT_RATE / 10)
sampout[jj] = sampnum[jj];
#endif
}
}

Expand Down
45 changes: 30 additions & 15 deletions src/wpc/wmssnd.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,11 +767,12 @@ static WRITE_HANDLER(dcs_ctrl_w);
static void dcs_init(struct sndbrdData *brdData);

/*-- local data --*/
#define DCS_BUFFER_SIZE 4096
#define DCS_BUFFER_SIZE 8192 // Must be power of 2 because of how circular buffer works
#define DCS_BUFFER_MASK (DCS_BUFFER_SIZE - 1)
#define DCS_SAMPLE_RATE 31250

static struct {
int enabled;
int status; // 0 = disabled, 1 playing, > 1 startup silence samples remaining
UINT32 sOut, sIn;
INT16 *buffer;
int stream;
Expand Down Expand Up @@ -928,10 +929,11 @@ static int dcs_custStart(const struct MachineSound *msound) {
memset(&dcs_dac,0,sizeof(dcs_dac));

/*-- allocate a DAC stream --*/
dcs_dac.stream = stream_init("DCS DAC", 100, 31250, 0, dcs_dacUpdate);
dcs_dac.stream = stream_init("DCS DAC", 100, DCS_SAMPLE_RATE, 0, dcs_dacUpdate);

/*-- allocate memory for our buffer --*/
dcs_dac.buffer = malloc(DCS_BUFFER_SIZE * sizeof(INT16));
memset(dcs_dac.buffer, 0, DCS_BUFFER_SIZE * sizeof(INT16));

#ifdef DCS_LOWPASS
dcs_dac.filter_f = filter_lp_fir_alloc(0.275, FILTER_ORDER_MAX); // magic, resolves noise on scared stiff for example, while not cutting off too much else -> is this due to DCS compression itself?
Expand All @@ -952,13 +954,14 @@ static void dcs_custStop(void) {
}
}

static void dcs_dacUpdate(int num, INT16 *buffer, int length) {
if (!dcs_dac.enabled)
memset(buffer, 0, length * sizeof(INT16));
else {

static void dcs_dacUpdate(int num, INT16 *buffer, int length)
{
int ii;

/* fill in with samples until we hit the end or run out */
for (ii = 0; ii < length; ii++) {
for (ii = 0; ii < length; ii++)
{
if (dcs_dac.sOut == dcs_dac.sIn) break;
#ifdef DCS_LOWPASS
filter_insert(dcs_dac.filter_f, dcs_dac.filter_state, dcs_dac.buffer[dcs_dac.sOut]);
Expand All @@ -968,7 +971,10 @@ static void dcs_dacUpdate(int num, INT16 *buffer, int length) {
#endif
dcs_dac.sOut = (dcs_dac.sOut + 1) & DCS_BUFFER_MASK;
}
/* fill the rest with the last sample (usually only 1 or 2 samples necessary) */
/* Give core feedback on sound buffer progress, so speed can be throttled to keep sound perfect */
core_sound_throttle_adj(dcs_dac.sIn, &dcs_dac.sOut, DCS_BUFFER_SIZE, DCS_SAMPLE_RATE); //!! hardwired sample rate, but okay as seems to never change

/* fill the rest with the last sample (ideally never necessary) */
for ( ; ii < length; ii++)
{
#ifdef DCS_LOWPASS
Expand All @@ -978,7 +984,6 @@ static void dcs_dacUpdate(int num, INT16 *buffer, int length) {
buffer[ii] = dcs_dac.buffer[(dcs_dac.sOut - 1) & DCS_BUFFER_MASK];
#endif
}
}
}

/*-------------------
Expand Down Expand Up @@ -1067,11 +1072,22 @@ static void dcs_txData(UINT16 start, UINT16 size, UINT16 memStep, int sRate) {
UINT16 *mem = ((UINT16 *)(dcslocals.cpuRegion + ADSP2100_DATA_OFFSET)) + start;
int idx;

stream_update(dcs_dac.stream, 0);
// Let the buffer fill naturally, so the throttling mechanism can work.
// stream_update(dcs_dac.stream, 0);
if (size == 0) /* No data, stop playing */
{ dcs_dac.enabled = FALSE; return; }
if (!dcs_dac.enabled) stream_set_sample_rate(dcs_dac.stream,sRate); // unnecessary as sample rate seems to be always 31250
{ dcs_dac.status = 0; return; }
if (dcs_dac.status==0) stream_set_sample_rate(dcs_dac.stream,sRate); // unnecessary as sample rate seems to be always 31250

// If we were not playing before, pre-load buffer with some silence to prevent jumpy starts.
if (dcs_dac.status == 0)
{
for (idx = 0; idx < DCS_SAMPLE_RATE * 20 / 1000 + 1; idx++) {
dcs_dac.buffer[dcs_dac.sIn] = 0;
dcs_dac.sIn = (dcs_dac.sIn + 1) & DCS_BUFFER_MASK;
}

dcs_dac.status = 1;
}
/*-- size is the size of the buffer not the number of samples --*/
#if MAMEVER >= 3716
for (idx = 0; idx < size; idx += memStep) {
Expand All @@ -1089,8 +1105,7 @@ static void dcs_txData(UINT16 start, UINT16 size, UINT16 memStep, int sRate) {
idx += sStep;
}
#endif /* MAMEVER */
/*-- enable the dac playing --*/
dcs_dac.enabled = TRUE;

}
#define DCS_IRQSTEPS 4
/*--------------------------------------------------*/
Expand Down

0 comments on commit 4f6a5ed

Please sign in to comment.