Updated playptmod to version 1.31.

CQTexperiment
Christopher Snowhill 2016-12-22 20:43:29 -08:00
parent 68f8979bbe
commit bcff934561
2 changed files with 127 additions and 52 deletions

View File

@ -1,8 +1,17 @@
/* /*
** PLAYPTMOD v1.27 - 8th of October 2015 - http://16-bits.org ** PLAYPTMOD v1.31 - 23rd of December 2016 - 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.3:
** - Fixed an unchecked memcpy when testing for ADPCM samples in possible STK files
**
** Changelog from 1.27:
** - Added support for FEST modules (.MOD with "FEST" tag instead of "M.K.")
** - Added the one-shot loop quirk for PT MODs
** - When setting mixSource, check loopLen>2 *or* loopStart>0 (yes, like PT)
** - Using 9xx on a >64kB sample should result in killing the voice (PT only)
**
** Changelog from 1.26: ** Changelog from 1.26:
** - Only loop module if speed is zero after fully processing an entire row ** - Only loop module if speed is zero after fully processing an entire row
** **
@ -215,6 +224,7 @@ typedef struct voice_data
int newLoopBegin; int newLoopBegin;
int newLoopEnd; int newLoopEnd;
int index; int index;
int loopQuirk;
int vol; int vol;
int panL; int panL;
int panR; int panR;
@ -449,7 +459,7 @@ static inline int periodToNote(player *p, char finetune, short period)
break; break;
} }
return i; return (i);
} }
static void mixerSwapChSource(player *p, int ch, const signed char *src, int length, int loopStart, int loopLength, int step) static void mixerSwapChSource(player *p, int ch, const signed char *src, int length, int loopStart, int loopLength, int step)
@ -465,29 +475,30 @@ static void mixerSwapChSource(player *p, int ch, const signed char *src, int len
v = &p->v[ch]; v = &p->v[ch];
v->swapSampleFlag = true; v->loopQuirk = false;
v->newData = src; v->swapSampleFlag = true;
v->newLoopFlag = loopLength > (2 * step); v->newData = src;
v->newLength = length; v->newLoopFlag = (loopStart + loopLength) > (2 * step);
v->newLoopBegin = loopStart; v->newLength = length;
v->newLoopEnd = loopStart + loopLength; v->newLoopBegin = loopStart;
v->newStep = step; v->newLoopEnd = loopStart + loopLength;
v->interpolating = 1; v->newStep = step;
v->interpolating = 1;
// if the mixer was already shut down earlier after a non-loop swap, // if the mixer was already shut down earlier after a non-loop swap,
// force swap again, but only if the new sample has loop enabled (ONLY!) // force swap again, but only if the new sample has loop enabled (ONLY!)
if ((v->data == NULL) && v->newLoopFlag) if ((v->data == NULL) && v->newLoopFlag)
{ {
v->loopBegin = v->newLoopBegin; v->loopBegin = v->newLoopBegin;
v->loopEnd = v->newLoopEnd; v->loopEnd = v->newLoopEnd;
v->loopFlag = v->newLoopFlag; v->loopFlag = v->newLoopFlag;
v->data = v->newData; v->data = v->newData;
v->length = v->newLength; v->length = v->newLength;
v->step = v->newStep; v->step = v->newStep;
/* we need to wrap here for safety reasons */ /* we need to wrap here for safety reasons */
while (v->index >= v->loopEnd) while (v->index >= v->loopEnd)
v->index = v->loopBegin + (v->index - v->loopEnd); v->index = v->loopBegin + (v->index - v->loopEnd);
} }
} }
@ -497,11 +508,12 @@ static void mixerSetChSource(player *p, int ch, const signed char *src, int leng
v = &p->v[ch]; v = &p->v[ch];
v->loopQuirk = false;
v->swapSampleFlag = false; v->swapSampleFlag = false;
v->data = src; v->data = src;
v->index = offset; v->index = offset;
v->length = length; v->length = length;
v->loopFlag = loopLength > (2 * step); v->loopFlag = (loopStart + loopLength) > (2 * step);
v->loopBegin = loopStart; v->loopBegin = loopStart;
v->loopEnd = loopStart + loopLength; v->loopEnd = loopStart + loopLength;
v->step = step; v->step = step;
@ -521,6 +533,24 @@ static void mixerSetChSource(player *p, int ch, const signed char *src, int leng
if (offset >= v->length) if (offset >= v->length)
v->data = NULL; v->data = NULL;
} }
/* PT specific quirks */
if (p->minPeriod == PT_MIN_PERIOD)
{
/* One-shot loops */
if ((loopLength > 2) && (loopStart == 0))
{
v->loopQuirk = v->loopEnd;
v->loopEnd = v->length;
}
/* 9xx on >64kB samples = kill voice */
if ((length > 65534) && (offset > 0))
{
v->loopQuirk = false;
v->data = NULL;
}
}
} }
// adejr: these sin/cos approximations both use a 0..1 // adejr: these sin/cos approximations both use a 0..1
@ -593,7 +623,7 @@ static void outputAudio(player *p, int *target, int numSamples)
int *out; int *out;
int step; int step;
int tempVolume; int tempVolume;
/*int delta;*/ int delta;
int interpolating; int interpolating;
unsigned int i; unsigned int i;
unsigned int j; unsigned int j;
@ -656,18 +686,24 @@ static void outputAudio(player *p, int *target, int numSamples)
break; break;
} }
v->loopBegin = v->newLoopBegin; v->loopBegin = v->newLoopBegin;
v->loopEnd = v->newLoopEnd; v->loopEnd = v->newLoopEnd;
v->loopFlag = v->newLoopFlag; v->loopFlag = v->newLoopFlag;
v->data = v->newData; v->data = v->newData;
v->length = v->newLength; v->length = v->newLength;
v->step = v->newStep; v->step = v->newStep;
v->index = v->loopBegin; v->index = v->loopBegin;
} }
else else
{ {
v->index = v->loopBegin; v->index = v->loopBegin;
if (v->loopQuirk)
{
v->loopEnd = v->loopQuirk;
v->loopQuirk = false;
}
} }
} }
} }
@ -683,12 +719,12 @@ static void outputAudio(player *p, int *target, int numSamples)
break; break;
} }
v->loopBegin = v->newLoopBegin; v->loopBegin = v->newLoopBegin;
v->loopEnd = v->newLoopEnd; v->loopEnd = v->newLoopEnd;
v->loopFlag = v->newLoopFlag; v->loopFlag = v->newLoopFlag;
v->data = v->newData; v->data = v->newData;
v->length = v->newLength; v->length = v->newLength;
v->step = v->newStep; v->step = v->newStep;
v->index = v->loopBegin; v->index = v->loopBegin;
} }
@ -1075,7 +1111,17 @@ static void checkModType(MODULE_HEADER *h, player *p, const char *buf)
p->maxPeriod = PT_MAX_PERIOD; p->maxPeriod = PT_MAX_PERIOD;
return; return;
} }
else if (!strncmp(buf, "FEST", 4))
{
h->format = FORMAT_FEST; /* NoiseTracker 1.0, special ones (from music disk?) */
p->numChans = h->channelCount = 4;
/* Normal period range */
p->minPeriod = PT_MIN_PERIOD;
p->maxPeriod = PT_MAX_PERIOD;
return;
}
h->format = FORMAT_UNKNOWN; /* May be The Ultimate SoundTracker, 15 samples */ h->format = FORMAT_UNKNOWN; /* May be The Ultimate SoundTracker, 15 samples */
p->numChans = h->channelCount = 4; p->numChans = h->channelCount = 4;
@ -1137,7 +1183,7 @@ int playptmod_LoadMem(void *_p, const unsigned char *buf, unsigned long bufLengt
{ {
i = playptmod_LoadMTM(p, fmodule); i = playptmod_LoadMTM(p, fmodule);
bufclose(fmodule); bufclose(fmodule);
return i; return (i);
} }
bufseek(fmodule, 0x0438, SEEK_SET); bufseek(fmodule, 0x0438, SEEK_SET);
@ -1165,8 +1211,12 @@ int playptmod_LoadMem(void *_p, const unsigned char *buf, unsigned long bufLengt
if (s->length > 9999) if (s->length > 9999)
lateVerSTKFlag = true; /* Only used if mightBeSTK is set */ lateVerSTKFlag = true; /* Only used if mightBeSTK is set */
bufread(&s->fineTune, 1, 1, fmodule); tmp = 0;
s->fineTune = s->fineTune & 0x0F; bufread(&tmp, 1, 1, fmodule); /* xxx: is this big-endian safe? */
if (p->source->head.format == FORMAT_FEST)
s->fineTune = (-tmp & 0x1F) / 2; /* One more bit of precision, + inverted */
else
s->fineTune = tmp & 0x0F;
bufread(&s->volume, 1, 1, fmodule); bufread(&s->volume, 1, 1, fmodule);
if (s->volume > 64) if (s->volume > 64)
@ -1381,8 +1431,14 @@ int playptmod_LoadMem(void *_p, const unsigned char *buf, unsigned long bufLengt
if ((note->param > 0x8F) && (note->param != 0xA4)) if ((note->param > 0x8F) && (note->param != 0xA4))
extendedPanning = true; extendedPanning = true;
} }
if (mightBeSTK) if (p->source->head.format == FORMAT_FEST)
{
/* Any Dxx == D00 in FEST modules */
if (note->command == 0x0D)
note->param = 0x00;
}
else if (mightBeSTK)
{ {
// Convert STK effects to PT effects // Convert STK effects to PT effects
// TODO: Add tracker checking, as there // TODO: Add tracker checking, as there
@ -1446,6 +1502,24 @@ int playptmod_LoadMem(void *_p, const unsigned char *buf, unsigned long bufLengt
if (j > s->length) if (j > s->length)
j = s->length; j = s->length;
if (j < 0 || j > 131072)
{
bufclose(fmodule);
for (pattern = 0; pattern < 256; ++i)
{
if (p->source->patterns[pattern] != NULL)
{
free(p->source->patterns[pattern]);
p->source->patterns[pattern] = NULL;
}
}
free(p->source);
return (false);
}
bufread(tempSample, 1, j, fmodule); bufread(tempSample, 1, j, fmodule);
smpDat8 = tempSample; smpDat8 = tempSample;
@ -1584,7 +1658,7 @@ int playptmod_Load(void *_p, const char *filename)
free(buffer); free(buffer);
return i; return (i);
} }
return (false); return (false);
@ -2262,7 +2336,7 @@ static void fxArpeggio(player *p, mod_channel *ch)
static void fxPortamentoSlideUp(player *p, mod_channel *ch) static void fxPortamentoSlideUp(player *p, mod_channel *ch)
{ {
if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) // all ticks while EDx (weird) if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) /* all ticks while EDx (weird) */
{ {
if (p->tempPeriod > 0) if (p->tempPeriod > 0)
{ {
@ -2286,7 +2360,7 @@ static void fxPortamentoSlideUp(player *p, mod_channel *ch)
static void fxPortamentoSlideDown(player *p, mod_channel *ch) static void fxPortamentoSlideDown(player *p, mod_channel *ch)
{ {
if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) // all ticks while EDx (weird) if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) /* all ticks while EDx (weird) */
{ {
if (p->tempPeriod > 0) if (p->tempPeriod > 0)
{ {
@ -2310,7 +2384,7 @@ static void fxPortamentoSlideDown(player *p, mod_channel *ch)
static void fxGlissando(player *p, mod_channel *ch) static void fxGlissando(player *p, mod_channel *ch)
{ {
if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) // all ticks while EDx (weird) if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) /* all ticks while EDx (weird) */
{ {
if (ch->param != 0) if (ch->param != 0)
{ {
@ -2344,7 +2418,7 @@ static void fxVibrato(player *p, mod_channel *ch)
static void fxGlissandoVolumeSlide(player *p, mod_channel *ch) static void fxGlissandoVolumeSlide(player *p, mod_channel *ch)
{ {
if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) // all ticks while EDx (weird) if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) /* all ticks while EDx (weird) */
{ {
processGlissando(p, ch); processGlissando(p, ch);
fxVolumeSlide(p, ch); fxVolumeSlide(p, ch);
@ -2353,7 +2427,7 @@ static void fxGlissandoVolumeSlide(player *p, mod_channel *ch)
static void fxVibratoVolumeSlide(player *p, mod_channel *ch) static void fxVibratoVolumeSlide(player *p, mod_channel *ch)
{ {
if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) // all ticks while EDx (weird) if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) /* all ticks while EDx (weird) */
{ {
processVibrato(p, ch); processVibrato(p, ch);
fxVolumeSlide(p, ch); fxVolumeSlide(p, ch);
@ -2416,7 +2490,7 @@ static void fxVolumeSlide(player *p, mod_channel *ch)
unsigned char hiNybble; unsigned char hiNybble;
unsigned char loNybble; unsigned char loNybble;
if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) // all ticks while EDx (weird) if ((p->modTick > 0) || (p->PattDelayTime2 > 0)) /* all ticks while EDx (weird) */
{ {
hiNybble = ch->param >> 4; hiNybble = ch->param >> 4;
loNybble = ch->param & 0x0F; loNybble = ch->param & 0x0F;
@ -2470,7 +2544,7 @@ static void fxPatternBreak(player *p, mod_channel *ch)
if (p->modTick == 0) if (p->modTick == 0)
{ {
pos = (((ch->param >> 4) * 10) + (ch->param & 0x0F)); pos = ((ch->param >> 4) * 10) + (ch->param & 0x0F);
if (pos > 63) if (pos > 63)
p->PBreakPosition = 0; p->PBreakPosition = 0;
@ -2517,8 +2591,8 @@ static void fxSetTempo(player *p, mod_channel *ch)
static void processEffects(player *p, mod_channel *ch) static void processEffects(player *p, mod_channel *ch)
{ {
if (p->modTick > 0) if (p->modTick > 0)
processInvertLoop(p, ch); processInvertLoop(p, ch);
if ((!ch->command && !ch->param) == 0) if ((!ch->command && !ch->param) == 0)
{ {
@ -2696,7 +2770,7 @@ static void processChannel(player *p, mod_channel *ch)
{ {
ch->flags &= ~FLAG_NEWSAMPLE; ch->flags &= ~FLAG_NEWSAMPLE;
// sample swapping (PT only) /* sample swapping (PT only) */
if ((ch->sample > 0) && (p->minPeriod == PT_MIN_PERIOD)) if ((ch->sample > 0) && (p->minPeriod == PT_MIN_PERIOD))
{ {
s = &p->source->samples[ch->sample - 1]; s = &p->source->samples[ch->sample - 1];
@ -2821,7 +2895,6 @@ static void processTick(player *p)
p->PosJumpAssert = true; p->PosJumpAssert = true;
} }
p->modTick++; p->modTick++;
if (p->modTick >= p->modSpeed) if (p->modTick >= p->modSpeed)
{ {
@ -2877,6 +2950,7 @@ void playptmod_Render(void *_p, int *target, int length)
outputAudio(p, target, tempSamples); outputAudio(p, target, tempSamples);
target += tempSamples * 2; target += tempSamples * 2;
} }
p->sampleCounter -= tempSamples; p->sampleCounter -= tempSamples;
length -= tempSamples; length -= tempSamples;
} }
@ -2936,12 +3010,12 @@ void *playptmod_Create(int samplingFrequency)
for (i = 14; i <= 1712; ++i) /* 0..13 will never be looked up, junk is OK */ 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); 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)
extendedRawPeriods[(j * ((12 * 7) + 1)) + i] = (i == (12 * 7)) ? 0 : (npertab[i] * 8363 / finetune[j]); extendedRawPeriods[(j * ((12 * 7) + 1)) + i] = (i == (12 * 7)) ? 0 : (npertab[i] * 8363 / finetune[j]);
// add padding (zeroes) /* add padding (zeroes) */
for (i = 0; i < 14; ++i) for (i = 0; i < 14; ++i)
extendedRawPeriods[(16 * ((12 * 7) + 1)) + i] = 0; extendedRawPeriods[(16 * ((12 * 7) + 1)) + i] = 0;
@ -2965,7 +3039,7 @@ void *playptmod_Create(int samplingFrequency)
mixerCutChannels(p); mixerCutChannels(p);
return p; return (p);
} }
void playptmod_Config(void *_p, int option, int value) void playptmod_Config(void *_p, int option, int value)

View File

@ -17,6 +17,7 @@ enum
FORMAT_32CN, // FastTracker II (32 channel MODs) FORMAT_32CN, // FastTracker II (32 channel MODs)
FORMAT_STK, // The Ultimate SoundTracker (15 samples) FORMAT_STK, // The Ultimate SoundTracker (15 samples)
FORMAT_NT, // NoiseTracker 1.0 FORMAT_NT, // NoiseTracker 1.0
FORMAT_FEST, // NoiseTracker (special ones)
FORMAT_MTM, // MultiTracker FORMAT_MTM, // MultiTracker