Skip to content

Commit

Permalink
Fixed: Paula/Scope delta cache didn't work properly
Browse files Browse the repository at this point in the history
  • Loading branch information
8bitbubsy committed Aug 12, 2021
1 parent 0d68fc4 commit 01ad396
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 42 deletions.
81 changes: 48 additions & 33 deletions src/pt2_audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ static volatile bool ledFilterEnabled;
static volatile uint8_t filterModel;
static int8_t defStereoSep;
static bool amigaPanFlag;
static int32_t oldPeriod = -1, randSeed = INITIAL_DITHER_SEED;
static int32_t randSeed = INITIAL_DITHER_SEED;
static uint32_t audLatencyPerfValInt, audLatencyPerfValFrac;
static uint64_t tickTime64, tickTime64Frac;
static double *dMixBufferL, *dMixBufferR, *dMixBufferLUnaligned, *dMixBufferRUnaligned, dOldVoiceDelta, dOldVoiceDeltaMul;
static double *dMixBufferL, *dMixBufferR, *dMixBufferLUnaligned, *dMixBufferRUnaligned;
static double dPrngStateL, dPrngStateR, dLState[2], dRState[2];
static blep_t blep[AMIGA_VOICES], blepVol[AMIGA_VOICES];
static rcFilter_t filterLoA500, filterHiA500, filterHiA1200;
Expand Down Expand Up @@ -203,7 +203,13 @@ void turnOffVoices(void)

void resetCachedMixerPeriod(void)
{
oldPeriod = -1;
paulaVoice_t *v = paula;
for (int32_t i = 0; i < AMIGA_VOICES; i++, v++)
{
v->oldPeriod = -1;
v->dOldVoiceDelta = 0.0;
v->dOldVoiceDeltaMul = 1.0;
}
}

// the following routines are only called from the mixer thread.
Expand All @@ -229,10 +235,10 @@ void paulaSetPeriod(int32_t ch, uint16_t period)
scopeSetPeriod(ch, realPeriod);
}

// if the new period was the same as the previous period, use cached deltas
if (realPeriod != oldPeriod)
// if the new period was the same as the previous period, use cached delta
if (realPeriod != v->oldPeriod)
{
oldPeriod = realPeriod;
v->oldPeriod = realPeriod;

// this period is not cached, calculate mixer deltas

Expand All @@ -244,17 +250,23 @@ void paulaSetPeriod(int32_t ch, uint16_t period)
else
dPeriodToDeltaDiv = audio.dPeriodToDeltaDiv;

// cache these
dOldVoiceDelta = dPeriodToDeltaDiv / realPeriod;
dOldVoiceDeltaMul = 1.0 / dOldVoiceDelta; // for BLEP synthesis
v->dOldVoiceDelta = dPeriodToDeltaDiv / realPeriod;

// for BLEP synthesis (prevents division in inner mix loop)
v->dOldVoiceDeltaMul = 1.0 / v->dOldVoiceDelta;
}

v->dDelta = dOldVoiceDelta;
v->dDelta = v->dOldVoiceDelta;

// for BLEP synthesis
v->dDeltaMul = dOldVoiceDeltaMul;
if (v->dLastDelta == 0.0) v->dLastDelta = v->dDelta;
if (v->dLastDeltaMul == 0.0) v->dLastDeltaMul = v->dDeltaMul;
v->dDeltaMul = v->dOldVoiceDeltaMul;

if (v->dLastDelta == 0.0)
v->dLastDelta = v->dDelta;

if (v->dLastDeltaMul == 0.0)
v->dLastDeltaMul = v->dDeltaMul;
// ------------------
}

void paulaSetVolume(int32_t ch, uint16_t vol)
Expand All @@ -263,10 +275,11 @@ void paulaSetVolume(int32_t ch, uint16_t vol)

int32_t realVol = vol;

// confirmed behavior on real Amiga
// this is what WinUAE does, so I assume it's what Paula does too
realVol &= 127;
if (realVol > 64)
realVol = 64;
// ----------------

v->dVolume = realVol * (1.0 / 64.0);

Expand All @@ -283,6 +296,8 @@ void paulaSetVolume(int32_t ch, uint16_t vol)

void paulaSetLength(int32_t ch, uint16_t len)
{
paulaVoice_t *v = &paula[ch];

int32_t realLength = len;
if (realLength == 0)
{
Expand All @@ -298,52 +313,50 @@ void paulaSetLength(int32_t ch, uint16_t len)

realLength <<= 1; // we work with bytes, not words

paula[ch].newLength = realLength;
v->newLength = realLength;
if (editor.songPlaying)
paula[ch].syncFlags |= SET_SCOPE_LENGTH;
v->syncFlags |= SET_SCOPE_LENGTH;
else
scope[ch].newLength = realLength;
}

void paulaSetData(int32_t ch, const int8_t *src)
{
paulaVoice_t *v = &paula[ch];

if (src == NULL)
src = &song->sampleData[RESERVED_SAMPLE_OFFSET]; // 128K reserved sample

paula[ch].newData = src;
v->newData = src;
if (editor.songPlaying)
paula[ch].syncFlags |= SET_SCOPE_DATA;
v->syncFlags |= SET_SCOPE_DATA;
else
scope[ch].newData = src;
}

void paulaStopDMA(int32_t ch)
{
paula[ch].active = false;
paulaVoice_t *v = &paula[ch];

v->active = false;

if (editor.songPlaying)
paula[ch].syncFlags |= STOP_SCOPE;
v->syncFlags |= STOP_SCOPE;
else
scope[ch].active = false;
}

void paulaStartDMA(int32_t ch)
{
const int8_t *dat;
int32_t length;
paulaVoice_t *v;

// trigger voice

v = &paula[ch];
paulaVoice_t *v = &paula[ch];

dat = v->newData;
const int8_t *dat = v->newData;
if (dat == NULL)
dat = &song->sampleData[RESERVED_SAMPLE_OFFSET]; // 128K reserved sample

length = v->newLength; // in bytes, not words
if (length < 2)
length = 2; // for safety
int32_t length = v->newLength; // in bytes, not words
if (length == 0)
length = 1+65535;

v->dPhase = 0.0;
v->pos = 0;
Expand All @@ -359,8 +372,9 @@ void paulaStartDMA(int32_t ch)
}
else
{
scope[ch].newData = dat;
scope[ch].newLength = length;
scope_t *s = &scope[ch];
s->newData = dat;
s->newLength = length;
scopeTrigger(ch);
}
}
Expand Down Expand Up @@ -976,6 +990,7 @@ bool setupAudio(void)

calcAudioLatencyVars(audio.audioBufferSize, audio.outputRate);

resetCachedMixerPeriod();
resetAudioDownsamplingStates();
audio.resetSyncTickTimeFlag = true;
SDL_PauseAudioDevice(dev, false);
Expand Down
4 changes: 4 additions & 0 deletions src/pt2_audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ typedef struct voice_t
int32_t length, newLength, pos;
double dVolume, dDelta, dDeltaMul, dPhase, dLastDelta, dLastDeltaMul, dLastPhase, dPanL, dPanR;

// period cache
int32_t oldPeriod;
double dOldVoiceDelta, dOldVoiceDeltaMul;

// used for pt2_sync.c
uint8_t syncFlags;
uint8_t syncVolume;
Expand Down
25 changes: 16 additions & 9 deletions src/pt2_scopes.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@
// this uses code that is not entirely thread safe, but I have never had any issues so far...

static volatile bool scopesUpdatingFlag, scopesDisplayingFlag;
static int32_t oldPeriod = -1;
static uint32_t scopeTimeLen, scopeTimeLenFrac;
static uint64_t timeNext64, timeNext64Frac;
static double dOldScopeDelta;
static SDL_Thread *scopeThread;

scope_t scope[AMIGA_VOICES]; // global

void resetCachedScopePeriod(void)
{
oldPeriod = -1;
dOldScopeDelta = 0.0;
scope_t *s = scope;
for (int32_t i = 0; i < AMIGA_VOICES; i++, s++)
{
s->oldPeriod = -1;
s->dOldScopeDelta = 0.0;
}
}

// this is quite hackish, but fixes sample swapping issues
Expand Down Expand Up @@ -95,15 +97,18 @@ int32_t getSampleReadPos(int32_t ch) // used for the sampler screen

void scopeSetPeriod(int32_t ch, int32_t period)
{
// if the new period was the same as the previous period, use cached deltas
if (period != oldPeriod)
volatile scope_t *s = &scope[ch];

// if the new period was the same as the previous period, use cached delta
if (period != s->oldPeriod)
{
oldPeriod = period;
s->oldPeriod = period;

const double dPeriodToScopeDeltaDiv = PAULA_PAL_CLK / (double)SCOPE_HZ;
dOldScopeDelta = dPeriodToScopeDeltaDiv / period;
s->dOldScopeDelta = dPeriodToScopeDeltaDiv / period;
}

scope[ch].dDelta = dOldScopeDelta;
s->dDelta = s->dOldScopeDelta;
}

void scopeTrigger(int32_t ch)
Expand Down Expand Up @@ -371,6 +376,8 @@ bool initScopes(void)
dFrac *= UINT32_MAX+1.0;
scopeTimeLenFrac = (uint32_t)dFrac;

resetCachedScopePeriod();

scopeThread = SDL_CreateThread(scopeThreadFunc, NULL, NULL);
if (scopeThread == NULL)
{
Expand Down
4 changes: 4 additions & 0 deletions src/pt2_scopes.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ typedef struct scope_t
uint8_t volume;
int32_t length, pos;

// cache
int32_t oldPeriod;
double dOldScopeDelta;

double dDelta, dPhase;
const int8_t *newData;
int32_t newLength;
Expand Down

0 comments on commit 01ad396

Please sign in to comment.