Updated PLAYPTMOD to version 1.35.

CQTexperiment
Christopher Snowhill 2017-06-11 17:57:00 -07:00
parent f2ee79946f
commit dac58b9f48
1 changed files with 131 additions and 114 deletions

View File

@ -1,8 +1,14 @@
/* /*
** PLAYPTMOD v1.31 - 23rd of December 2016 - http://16-bits.org ** PLAYPTMOD v1.35 - 7th of June 2017 - http://16-bits.org
** ============================================================== ** =========================================================
** This is the foobar2000 version, with added code by kode54 ** This is the foobar2000 version, with added code by kode54
** **
** Changelog from 1.31:
** - Make period variables unsigned, to simulate a period overflow quirk
** - Properly clamp periods<113 to 113 in PT mode
** - Removed a deprecated arpeggio volume quirk
** - Rewrote the mixer rate function to not use LUTs (WTF was I thinking?)
**
** Changelog from 1.3: ** Changelog from 1.3:
** - Fixed an unchecked memcpy when testing for ADPCM samples in possible STK files ** - Fixed an unchecked memcpy when testing for ADPCM samples in possible STK files
** **
@ -115,7 +121,7 @@ typedef struct modnote
unsigned char sample; unsigned char sample;
unsigned char command; unsigned char command;
unsigned char param; unsigned char param;
short period; unsigned short period;
} modnote_t; } modnote_t;
typedef struct typedef struct
@ -175,9 +181,9 @@ typedef struct
unsigned char invertLoopSpeed; unsigned char invertLoopSpeed;
unsigned char chanIndex; unsigned char chanIndex;
unsigned char toneportdirec; unsigned char toneportdirec;
short period; unsigned short period;
short tempPeriod; unsigned short tempPeriod;
short wantedperiod; unsigned short wantedperiod;
int noNote; int noNote;
int invertLoopOffset; int invertLoopOffset;
int offset; int offset;
@ -263,7 +269,7 @@ typedef struct
unsigned char PattDelayTime2; unsigned char PattDelayTime2;
unsigned char PosJumpAssert; unsigned char PosJumpAssert;
unsigned char PBreakFlag; unsigned char PBreakFlag;
short tempPeriod; unsigned short tempPeriod;
int tempoTimerVal; int tempoTimerVal;
char moduleLoaded; char moduleLoaded;
char modulePlaying; char modulePlaying;
@ -271,8 +277,6 @@ typedef struct
unsigned short soundBufferSize; unsigned short soundBufferSize;
unsigned int soundFrequency; unsigned int soundFrequency;
char soundBuffers; char soundBuffers;
float *frequencyTable;
float *extendedFrequencyTable;
unsigned char *sinusTable; unsigned char *sinusTable;
int minPeriod; int minPeriod;
int maxPeriod; int maxPeriod;
@ -299,7 +303,7 @@ static const unsigned char invertLoopSpeeds[16] =
}; };
/* 16 fintunes, 3 octaves, 1 pad each octave, 14 paddings on end */ /* 16 fintunes, 3 octaves, 1 pad each octave, 14 paddings on end */
static const short rawAmigaPeriods[(16 * ((12 * 3) + 1)) + 14] = static const unsigned short rawAmigaPeriods[(16 * ((12 * 3) + 1)) + 14] =
{ {
856,808,762,720,678,640,604,570,538,508,480,453, 856,808,762,720,678,640,604,570,538,508,480,453,
428,404,381,360,339,320,302,285,269,254,240,226, 428,404,381,360,339,320,302,285,269,254,240,226,
@ -353,9 +357,9 @@ static const short rawAmigaPeriods[(16 * ((12 * 3) + 1)) + 14] =
}; };
/* 16 fintunes, 7 octaves, 1 pad each octave, 14 paddings on end */ /* 16 fintunes, 7 octaves, 1 pad each octave, 14 paddings on end */
static short extendedRawPeriods[(16 * ((12 * 7) + 1)) + 14]; static unsigned short extendedRawPeriods[(16 * ((12 * 7) + 1)) + 14];
static const short npertab[12 * 7] = /* 7 octaves, C-3 .. B-9 */ static const unsigned short npertab[12 * 7] = /* 7 octaves, C-3 .. B-9 */
{ {
0x06B0,0x0650,0x05F4,0x05A0,0x054C,0x0500,0x04B8,0x0474,0x0434,0x03F8,0x03C0,0x038A, 0x06B0,0x0650,0x05F4,0x05A0,0x054C,0x0500,0x04B8,0x0474,0x0434,0x03F8,0x03C0,0x038A,
0x0358,0x0328,0x02FA,0x02D0,0x02A6,0x0280,0x025C,0x023A,0x021A,0x01FC,0x01E0,0x01C5, 0x0358,0x0328,0x02FA,0x02D0,0x02A6,0x0280,0x025C,0x023A,0x021A,0x01FC,0x01E0,0x01C5,
@ -436,7 +440,7 @@ static void bufseek(BUF *_SrcBuf, long _Offset, int _Origin)
} }
} }
static inline int periodToNote(player *p, char finetune, short period) static inline int periodToNote(player *p, char finetune, unsigned short period)
{ {
unsigned char i; unsigned char i;
unsigned char maxNotes; unsigned char maxNotes;
@ -445,12 +449,12 @@ static inline int periodToNote(player *p, char finetune, short period)
if (p->minPeriod == PT_MIN_PERIOD) if (p->minPeriod == PT_MIN_PERIOD)
{ {
maxNotes = 12 * 3; maxNotes = 12 * 3;
tablePointer = (short *)&rawAmigaPeriods[finetune * ((12 * 3) + 1)]; tablePointer = (unsigned short *)&rawAmigaPeriods[finetune * ((12 * 3) + 1)];
} }
else else
{ {
maxNotes = 12 * 7; maxNotes = 12 * 7;
tablePointer = (short *)&extendedRawPeriods[finetune * ((12 * 7) + 1)]; tablePointer = (unsigned short *)&extendedRawPeriods[finetune * ((12 * 7) + 1)];
} }
for (i = 0; i < maxNotes; ++i) for (i = 0; i < maxNotes; ++i)
@ -611,9 +615,22 @@ static void mixerCutChannels(player *p)
} }
} }
static void mixerSetChRate(player *p, int ch, float rate) static void mixerSetChRate(player *p, int ch, unsigned short period)
{ {
p->v[ch].rate = 1.0f / rate; if (period == 0)
{
p->v[ch].rate = 0.0f;
return;
}
if (p->minPeriod == PT_MIN_PERIOD)
{
/* in PT mode, wrap period around 113 (Paula behavior) */
if (period < 113)
period = 113;
}
p->v[ch].rate = (3546895.0f / period) / p->soundFrequency;
} }
static void outputAudio(player *p, int *target, int numSamples) static void outputAudio(player *p, int *target, int numSamples)
@ -1825,16 +1842,21 @@ static void efxFinePortamentoSlideUp(player *p, mod_channel *ch)
if (p->minPeriod == PT_MIN_PERIOD) if (p->minPeriod == PT_MIN_PERIOD)
{ {
if (ch->period < 113) if ((ch->period & 0x0FFF) < 113)
ch->period = 113; {
ch->period &= 0xF000;
ch->period |= 113;
}
p->tempPeriod = ch->period & 0x0FFF;
} }
else else
{ {
if (ch->period < p->minPeriod) if (ch->period < p->minPeriod)
ch->period = p->minPeriod; ch->period = p->minPeriod;
}
p->tempPeriod = ch->period;
p->tempPeriod = ch->period; }
} }
} }
} }
@ -1849,16 +1871,21 @@ static void efxFinePortamentoSlideDown(player *p, mod_channel *ch)
if (p->minPeriod == PT_MIN_PERIOD) if (p->minPeriod == PT_MIN_PERIOD)
{ {
if (ch->period > 856) if ((ch->period & 0x0FFF) > 856)
ch->period = 856; {
ch->period &= 0xF000;
ch->period |= 856;
}
p->tempPeriod = ch->period & 0x0FFF;
} }
else else
{ {
if (ch->period > p->maxPeriod) if (ch->period > p->maxPeriod)
ch->period = p->maxPeriod; ch->period = p->maxPeriod;
}
p->tempPeriod = ch->period;
p->tempPeriod = ch->period; }
} }
} }
} }
@ -2012,10 +2039,10 @@ static void efxInvertLoop(player *p, mod_channel *ch)
} }
/* -- this is only for PT mode ---------------------------- */ /* -- this is only for PT mode ---------------------------- */
static void setupGlissando(mod_channel *ch, short period) static void setupGlissando(mod_channel *ch, unsigned short period)
{ {
unsigned char i; unsigned char i;
const short *tablePointer; const unsigned short *tablePointer;
tablePointer = &rawAmigaPeriods[ch->fineTune * ((12 * 3) + 1)]; tablePointer = &rawAmigaPeriods[ch->fineTune * ((12 * 3) + 1)];
@ -2051,18 +2078,24 @@ static void processGlissando(player *p, mod_channel *ch)
signed char m; signed char m;
signed char h; signed char h;
const short *tablePointer; const unsigned short *tablePointer;
if (p->tempPeriod == 0)
{
ch->wantedperiod = 0; /* don't do any more sliding */
return;
}
/* different routine for PT mode */ /* different routine for PT mode */
if (p->minPeriod == PT_MIN_PERIOD) if (p->minPeriod == PT_MIN_PERIOD)
{ {
if ((ch->wantedperiod > 0) && (p->tempPeriod > 0)) if (ch->wantedperiod > 0)
{ {
if (ch->toneportdirec == 0) if (ch->toneportdirec == 0)
{ {
/* downwards */ /* downwards */
ch->period += ch->glissandoSpeed; ch->period += ch->glissandoSpeed;
if (ch->period >= ch->wantedperiod) if ((signed short)ch->period >= ch->wantedperiod)
{ {
ch->period = ch->wantedperiod; ch->period = ch->wantedperiod;
ch->wantedperiod = 0; ch->wantedperiod = 0;
@ -2072,7 +2105,7 @@ static void processGlissando(player *p, mod_channel *ch)
{ {
/* upwards */ /* upwards */
ch->period -= ch->glissandoSpeed; ch->period -= ch->glissandoSpeed;
if (ch->period <= ch->wantedperiod) if ((signed short)ch->period <= ch->wantedperiod)
{ {
ch->period = ch->wantedperiod; ch->period = ch->wantedperiod;
ch->wantedperiod = 0; ch->wantedperiod = 0;
@ -2106,51 +2139,48 @@ static void processGlissando(player *p, mod_channel *ch)
} }
else else
{ {
if (p->tempPeriod > 0) if (ch->period < ch->tempPeriod)
{ {
if (ch->period < ch->tempPeriod) ch->period += ch->glissandoSpeed;
{ if ((signed short)ch->period > ch->tempPeriod)
ch->period += ch->glissandoSpeed; ch->period = ch->tempPeriod;
if (ch->period > ch->tempPeriod) }
ch->period = ch->tempPeriod; else
} {
else ch->period -= ch->glissandoSpeed;
{ if ((signed short)ch->period < ch->tempPeriod)
ch->period -= ch->glissandoSpeed; ch->period = ch->tempPeriod;
if (ch->period < ch->tempPeriod) }
ch->period = ch->tempPeriod;
}
if (ch->glissandoControl == 0) if (ch->glissandoControl == 0)
{ {
p->tempPeriod = ch->period; p->tempPeriod = ch->period;
} }
else else
{ {
l = 0; l = 0;
h = 83; h = 83;
tablePointer = (short *)&extendedRawPeriods[ch->fineTune * ((12 * 7) + 1)]; tablePointer = (unsigned short *)&extendedRawPeriods[ch->fineTune * ((12 * 7) + 1)];
while (h >= l) while (h >= l)
{ {
m = (h + l) / 2; m = (h + l) / 2;
if (tablePointer[m] == ch->period) if (tablePointer[m] == ch->period)
{ {
p->tempPeriod = tablePointer[m]; p->tempPeriod = tablePointer[m];
break; break;
} }
else if (tablePointer[m] > ch->period) else if (tablePointer[m] > ch->period)
{ {
l = m + 1; l = m + 1;
} }
else else
{ {
h = m - 1; h = m - 1;
} }
} }
} }
}
} }
} }
@ -2276,7 +2306,7 @@ static void fxArpeggio(player *p, mod_channel *ch)
signed char noteToAdd; signed char noteToAdd;
signed char arpeggioTick; signed char arpeggioTick;
unsigned char i; unsigned char i;
short *tablePointer; unsigned short *tablePointer;
noteToAdd = 0; noteToAdd = 0;
@ -2297,7 +2327,7 @@ static void fxArpeggio(player *p, mod_channel *ch)
if (p->minPeriod == PT_MIN_PERIOD) /* PT/NT/UST/STK */ if (p->minPeriod == PT_MIN_PERIOD) /* PT/NT/UST/STK */
{ {
tablePointer = (short *)&rawAmigaPeriods[ch->fineTune * ((12 * 3) + 1)]; tablePointer = (unsigned short *)&rawAmigaPeriods[ch->fineTune * ((12 * 3) + 1)];
for (i = 0; i < (12 * 3); ++i) for (i = 0; i < (12 * 3); ++i)
{ {
if (ch->period >= tablePointer[i]) if (ch->period >= tablePointer[i])
@ -2312,7 +2342,7 @@ static void fxArpeggio(player *p, mod_channel *ch)
l = 0; l = 0;
h = (12 * 7) - 1; h = (12 * 7) - 1;
tablePointer = (short *)&extendedRawPeriods[ch->fineTune * ((12 * 7) + 1)]; tablePointer = (unsigned short *)&extendedRawPeriods[ch->fineTune * ((12 * 7) + 1)];
while (h >= l) while (h >= l)
{ {
m = (h + l) / 2; m = (h + l) / 2;
@ -2344,16 +2374,21 @@ static void fxPortamentoSlideUp(player *p, mod_channel *ch)
if (p->minPeriod == PT_MIN_PERIOD) if (p->minPeriod == PT_MIN_PERIOD)
{ {
if (ch->period < 113) if ((ch->period & 0x0FFF) < 113)
ch->period = 113; {
ch->period &= 0xF000;
ch->period |= 113;
}
p->tempPeriod = ch->period & 0x0FFF;
} }
else else
{ {
if (ch->period < p->minPeriod) if (ch->period < p->minPeriod)
ch->period = p->minPeriod; ch->period = p->minPeriod;
}
p->tempPeriod = ch->period;
p->tempPeriod = ch->period; }
} }
} }
} }
@ -2368,16 +2403,21 @@ static void fxPortamentoSlideDown(player *p, mod_channel *ch)
if (p->minPeriod == PT_MIN_PERIOD) if (p->minPeriod == PT_MIN_PERIOD)
{ {
if (ch->period > 856) if ((ch->period & 0x0FFF) > 856)
ch->period = 856; {
ch->period &= 0xF000;
ch->period |= 856;
}
p->tempPeriod = ch->period & 0x0FFF;
} }
else else
{ {
if (ch->period > p->maxPeriod) if (ch->period > p->maxPeriod)
ch->period = p->maxPeriod; ch->period = p->maxPeriod;
}
p->tempPeriod = ch->period;
p->tempPeriod = ch->period; }
} }
} }
} }
@ -2681,7 +2721,7 @@ static void fetchPatternData(player *p, mod_channel *ch)
ch->command = note->command; ch->command = note->command;
ch->param = note->param; ch->param = note->param;
if (note->period > 0) if ((note->period & 0x0FFF) > 0)
{ {
if (ch->command == 0x0E) if (ch->command == 0x0E)
{ {
@ -2689,7 +2729,7 @@ static void fetchPatternData(player *p, mod_channel *ch)
ch->fineTune = ch->param & 0x0F; ch->fineTune = ch->param & 0x0F;
} }
tempNote = periodToNote(p, 0, note->period); tempNote = periodToNote(p, 0, note->period & 0x0FFF);
if ((p->minPeriod == PT_MIN_PERIOD) && (tempNote == (12 * 3))) /* PT/NT/STK/UST only */ if ((p->minPeriod == PT_MIN_PERIOD) && (tempNote == (12 * 3))) /* PT/NT/STK/UST only */
{ {
ch->noNote = true; ch->noNote = true;
@ -2833,10 +2873,7 @@ static void processChannel(player *p, mod_channel *ch)
if (p->minPeriod != PT_MIN_PERIOD) if (p->minPeriod != PT_MIN_PERIOD)
mixerSetChVol(p, ch->chanIndex, p->tempVolume); mixerSetChVol(p, ch->chanIndex, p->tempVolume);
if ((p->tempPeriod >= p->minPeriod) && (p->tempPeriod <= p->maxPeriod)) mixerSetChRate(p, ch->chanIndex, p->tempPeriod);
mixerSetChRate(p, ch->chanIndex, (p->minPeriod == PT_MIN_PERIOD) ? p->frequencyTable[(int)p->tempPeriod] : p->extendedFrequencyTable[(int)p->tempPeriod]);
else
mixerSetChVol(p, ch->chanIndex, 0); /* arpeggio override hack */
} }
} }
@ -3002,14 +3039,6 @@ void *playptmod_Create(int samplingFrequency)
for (i = 0; i < 32; ++i) for (i = 0; i < 32; ++i)
p->sinusTable[i] = (unsigned char)floorf(255.0f * sinf(((float)i * 3.141592f) / 32.0f)); p->sinusTable[i] = (unsigned char)floorf(255.0f * sinf(((float)i * 3.141592f) / 32.0f));
p->frequencyTable = (float *)malloc(sizeof (float) * (937 + 1));
for (i = 14; i <= 937; ++i) /* 0..13 will never be looked up, junk is OK */
p->frequencyTable[i] = (float)samplingFrequency / (3546895.0f / (float)i);
p->extendedFrequencyTable = (float *)malloc(sizeof (float) * (1712 + 1));
for (i = 14; i <= 1712; ++i) /* 0..13 will never be looked up, junk is OK */
p->extendedFrequencyTable[i] = (float)samplingFrequency / (3546895.0f / (float)i);
/* generate extended period table */ /* generate extended period table */
for (j = 0; j < 16; ++j) for (j = 0; j < 16; ++j)
for (i = 0; i < ((12 * 7) + 1); ++i) for (i = 0; i < ((12 * 7) + 1); ++i)
@ -3159,18 +3188,6 @@ void playptmod_Free(void *_p)
p->sinusTable = NULL; p->sinusTable = NULL;
} }
if (p->frequencyTable != NULL)
{
free(p->frequencyTable);
p->frequencyTable = NULL;
}
if (p->extendedFrequencyTable != NULL)
{
free(p->extendedFrequencyTable);
p->extendedFrequencyTable = NULL;
}
for (i = 0; i < MAX_CHANNELS; ++i) for (i = 0; i < MAX_CHANNELS; ++i)
{ {
resampler_delete(p->blep[i]); resampler_delete(p->blep[i]);