Re-ported ft2play from original sources

This commit is contained in:
Chris Moeller 2014-04-04 13:40:09 -07:00
parent 0b436c8437
commit 00a014f270

View file

@ -1,36 +1,33 @@
/* /*
** FT2PLAY v0.42a ** FT2PLAY v0.42a
** ============== ** ==============
** **
** C port of FastTracker II's replayer, by 8bitbubsy (Olav Sørensen) ** C port of FastTracker II's replayer, by 8bitbubsy (Olav Sørensen)
** using the original pascal+asm source codes by Mr.H (Fredrik Huss) of Triton ** using the original pascal+asm source codes by Mr.H (Fredrik Huss) of Triton
** **
** This is by no means a piece of beautiful code, nor is it meant to be... ** This is by no means a piece of beautiful code, nor is it meant to be...
** It's just an accurate FastTracker II replayer port for people to enjoy. ** It's just an accurate FastTracker II replayer port for people to enjoy.
** **
** **
** non-FT2 effects: ** (extreme) non-FT2 extensions:
** - E8x - set panning ** - Max 127 channels (was 32)
** ** - Any amount-of-channels number (FT2 supports *even* numbers only)
** (extreme) non-FT2 extensions: ** - Max 256 instruments (was 128)
** - Max 127 channels (was 32) ** - Max 32 samples per instrument (was 16)
** - Any amount-of-channels number (FT2 supports *even* numbers only) ** - Max 1024 rows per pattern (was 256)
** - Max 256 instruments (was 128) ** - Stereo samples
** - Max 32 samples per instrument (was 16) **
** - Max 1024 rows per pattern (was 256) ** These additions shouldn't break FT2 accuracy, unless the XM is malicious.
** - Stereo samples **
** */
** These additions shouldn't break FT2 accuracy, unless the XM is malicious.
**
*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <limits.h>
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#include <limits.h>
#include "resampler.h" #include "resampler.h"
@ -42,6 +39,8 @@
#define USE_VOL_RAMP #define USE_VOL_RAMP
enum { _soundBufferSize = 512 };
enum enum
{ {
IS_Vol = 1, IS_Vol = 1,
@ -174,9 +173,9 @@ typedef struct SongTyp_t
uint8_t PosJumpFlag; uint8_t PosJumpFlag;
uint8_t SongTab[256]; uint8_t SongTab[256];
uint16_t Ver; uint16_t Ver;
/*char Name[21]; char Name[21];
char ProgName[21]; char ProgName[21];
char InstrName[256][23];*/ char InstrName[256][23];
uint16_t startOrder; uint16_t startOrder;
} SongTyp; } SongTyp;
@ -309,11 +308,10 @@ typedef struct TonTyp_t
typedef struct typedef struct
{ {
const int8_t *sampleData;
int8_t loopEnabled; int8_t loopEnabled;
int8_t sixteenBit; int8_t sixteenBit;
int8_t stereo; int8_t stereo;
int8_t busy;
const int8_t *sampleData;
int8_t loopBidi; int8_t loopBidi;
int8_t loopDir; int8_t loopDir;
int32_t sampleLength; int32_t sampleLength;
@ -323,7 +321,6 @@ typedef struct
int8_t interpolating; int8_t interpolating;
float incRate; float incRate;
float frac;
float volume; float volume;
float panningL; float panningL;
float panningR; float panningR;
@ -344,12 +341,13 @@ typedef struct
typedef struct typedef struct
{ {
uint8_t *_ptr; uint8_t *_ptr;
uintptr_t _cnt; size_t _cnt;
uint8_t *_base; uint8_t *_base;
uintptr_t _bufsiz; size_t _bufsiz;
int32_t _eof; int32_t _eof;
} MEM; } MEM;
typedef struct typedef struct
{ {
int8_t *VibSineTab; int8_t *VibSineTab;
@ -359,7 +357,7 @@ typedef struct
int16_t *amigaPeriods; int16_t *amigaPeriods;
uint32_t *LogTab; uint32_t *LogTab;
int8_t LinearFrqTab; int8_t LinearFrqTab;
int32_t soundBufferSize; uint32_t soundBufferSize;
uint32_t outputFreq; uint32_t outputFreq;
TonTyp *NilPatternLine; TonTyp *NilPatternLine;
@ -387,19 +385,16 @@ typedef struct
// pre-initialized variables // pre-initialized variables
int8_t samplingInterpolation;// = 1; int8_t samplingInterpolation;// = 1;
#ifdef USE_VOL_RAMP
int8_t rampStyle; int8_t rampStyle;
#endif
float *masterBufferL;// = NULL; float *masterBufferL;// = NULL;
float *masterBufferR;// = NULL; float *masterBufferR;// = NULL;
int32_t samplesLeft;// = 0; // must be signed int32_t samplesLeft;// = 0; // must be signed
int8_t isMixing;// = 0;
uint32_t samplesPerFrame;// = 882; uint32_t samplesPerFrame;// = 882;
// globally accessed // globally accessed
int8_t ModuleLoaded;// = 0; int8_t ModuleLoaded;// = 0;
int8_t Playing;// = 0; int8_t Playing;// = 0;
uint8_t numChannels;// = 127; uint16_t numChannels;// = 127;
uint8_t muted[16]; uint8_t muted[16];
@ -407,17 +402,14 @@ typedef struct
uint8_t playedOrder[8192]; uint8_t playedOrder[8192];
} PLAYER; } PLAYER;
enum { _soundBufferSize = 512 };
// FUNCTION DECLARATIONS // FUNCTION DECLARATIONS
static MEM *mopen(const uint8_t *src, uintptr_t length);
static MEM *mopen(const uint8_t *src, size_t length);
static void mclose(MEM *buf); static void mclose(MEM *buf);
//static intptr_t mtell(MEM *buf);
static size_t mread(void *buffer, size_t size, size_t count, MEM *buf); static size_t mread(void *buffer, size_t size, size_t count, MEM *buf);
//static size_t mwrite(const void *buffer, size_t size, size_t count, MEM *buf);
static int32_t meof(MEM *buf); static int32_t meof(MEM *buf);
static void mseek(MEM *buf, intptr_t offset, int32_t whence); static void mseek(MEM *buf, ssize_t offset, int32_t whence);
static void setSamplesPerFrame(PLAYER *, uint32_t val); static void setSamplesPerFrame(PLAYER *, uint32_t val);
static void voiceSetSource(PLAYER *, uint8_t i, const int8_t *sampleData, static void voiceSetSource(PLAYER *, uint8_t i, const int8_t *sampleData,
int32_t sampleLength, int32_t sampleLoopLength, int32_t sampleLength, int32_t sampleLoopLength,
@ -425,14 +417,15 @@ static void voiceSetSource(PLAYER *, uint8_t i, const int8_t *sampleData,
int8_t sixteenbit, int8_t stereo); int8_t sixteenbit, int8_t stereo);
static void voiceSetSamplePosition(PLAYER *, uint8_t i, uint16_t value); static void voiceSetSamplePosition(PLAYER *, uint8_t i, uint16_t value);
static void voiceSetVolume(PLAYER *, uint8_t i, float vol, uint8_t sharp); static void voiceSetVolume(PLAYER *, uint8_t i, float vol, uint8_t sharp);
void voiceSetPanning(PLAYER *, uint8_t i, uint8_t pan); static void voiceSetPanning(PLAYER *, uint8_t i, uint8_t pan);
static void voiceSetSamplingFrequency(PLAYER *, uint8_t i, uint32_t samplingFrequency); static void voiceSetSamplingFrequency(PLAYER *, uint8_t i, uint32_t samplingFrequency);
static void ft2play_FreeSong(PLAYER *);
// TABLES AND VARIABLES // TABLES AND VARIABLES
static const uint16_t AmigaFinePeriod[12 * 8] = static uint16_t AmigaFinePeriod[12 * 8] =
{ {
907,900,894,887,881,875,868,862,856,850,844,838, 907,900,894,887,881,875,868,862,856,850,844,838,
832,826,820,814,808,802,796,791,785,779,774,768, 832,826,820,814,808,802,796,791,785,779,774,768,
@ -445,7 +438,7 @@ static const uint16_t AmigaFinePeriod[12 * 8] =
}; };
// This table is so small that generating it is almost as big // This table is so small that generating it is almost as big
static const uint8_t VibTab[32] = static uint8_t VibTab[32] =
{ {
0, 24, 49, 74, 97,120,141,161, 0, 24, 49, 74, 97,120,141,161,
180,197,212,224,235,244,250,253, 180,197,212,224,235,244,250,253,
@ -453,8 +446,10 @@ static const uint8_t VibTab[32] =
180,161,141,120, 97, 74, 49, 24 180,161,141,120, 97, 74, 49, 24
}; };
// CODE START // CODE START
static inline void RetrigVolume(StmTyp *ch) static inline void RetrigVolume(StmTyp *ch)
{ {
ch->RealVol = ch->OldVol; ch->RealVol = ch->OldVol;
@ -965,13 +960,19 @@ CheckEffects:
pl->Song.PBreakFlag = 1; pl->Song.PBreakFlag = 1;
} }
} }
if (pl->Song.PBreakFlag == 1 && pl->Song.PBreakPos == 0)
{
int32_t offset = pl->Song.SongPos / 8;
int32_t bit = 1 << (pl->Song.SongPos % 8);
pl->playedOrder[offset] &= ~bit;
}
} }
} }
// E7x - set tremolo waveform // E7x - set tremolo waveform
else if ((ch->Eff & 0xF0) == 0x70) ch->WaveCtrl = ((ch->Eff & 0x0F) << 4) | (ch->WaveCtrl & 0x0F); else if ((ch->Eff & 0xF0) == 0x70) ch->WaveCtrl = ((ch->Eff & 0x0F) << 4) | (ch->WaveCtrl & 0x0F);
// E8x - set panning - *non-FT2* // E8x - set panning *non-FT2*
else if ((ch->Eff & 0xF0) == 0x80) else if ((ch->Eff & 0xF0) == 0x80)
{ {
ch->OutPan = (ch->Eff & 0x0F) << 4; ch->OutPan = (ch->Eff & 0x0F) << 4;
@ -1884,9 +1885,7 @@ static inline void DoEffects(PLAYER *p, StmTyp *ch)
{ {
StartTone(p, ch->TonTyp & 0x00FF, 0, 0, ch); StartTone(p, ch->TonTyp & 0x00FF, 0, 0, ch);
if (ch->TonTyp & 0xFF00) if (ch->TonTyp & 0xFF00) RetrigVolume(ch);
RetrigVolume(ch);
RetrigEnvelopeVibrato(ch); RetrigEnvelopeVibrato(ch);
if ((ch->VolKolVol >= 0x10) && (ch->VolKolVol <= 0x50)) if ((ch->VolKolVol >= 0x10) && (ch->VolKolVol <= 0x50))
@ -2075,11 +2074,10 @@ static void MainPlayer(PLAYER *p) // periodically called from mixer
resampler_dup_inplace(p->resampler[ch->Nr + 127 + 254], p->resampler[ch->Nr + 254]); resampler_dup_inplace(p->resampler[ch->Nr + 127 + 254], p->resampler[ch->Nr + 254]);
} }
#endif #endif
s = ch->InstrOfs; s = ch->InstrOfs;
voiceSetSamplePosition(p, ch->Nr, ch->SmpStartPos);
voiceSetSource(p, ch->Nr, s.Pek, s.Len, s.RepL, s.RepS + s.RepL, s.Typ & 3, s.Typ & 16, s.Typ & 32); voiceSetSource(p, ch->Nr, s.Pek, s.Len, s.RepL, s.RepS + s.RepL, s.Typ & 3, s.Typ & 16, s.Typ & 32);
voiceSetSamplePosition(p, ch->Nr, ch->SmpStartPos);
} }
ch->Status = 0; ch->Status = 0;
@ -2094,20 +2092,21 @@ static void StopVoices(PLAYER *p)
for (a = 0; a < 127; ++a) for (a = 0; a < 127; ++a)
{ {
p->Stm[a].Nr = a; StmTyp *ch = &p->Stm[a];
p->Stm[a].TonTyp = 0; ch->Nr = a;
p->Stm[a].RelTonNr = 0; ch->TonTyp = 0;
p->Stm[a].InstrNr = 0; ch->RelTonNr = 0;
p->Stm[a].InstrSeg = *p->Instr[0]; ch->InstrNr = 0;
p->Stm[a].Status = IS_Vol; ch->InstrSeg = *p->Instr[0];
p->Stm[a].RealVol = 0; ch->Status = IS_Vol;
p->Stm[a].OutVol = 0; ch->RealVol = 0;
p->Stm[a].OldVol = 0; ch->OutVol = 0;
p->Stm[a].FinalVol = 0.0f; ch->OldVol = 0;
p->Stm[a].OldPan = 128; ch->FinalVol = 0.0f;
p->Stm[a].OutPan = 128; ch->OldPan = 128;
p->Stm[a].FinalPan = 128; ch->OutPan = 128;
p->Stm[a].VibDepth = 0; ch->FinalPan = 128;
ch->VibDepth = 0;
voiceSetPanning(p, a, 128); voiceSetPanning(p, a, 128);
} }
@ -2264,6 +2263,39 @@ static void Delta2Samp(int8_t *p, uint32_t len, uint8_t typ)
} }
} }
static inline int8_t GetAdpcmSample(const int8_t *sampleDictionary, const uint8_t *sampleData, int32_t samplePosition, int8_t *lastDelta)
{
uint8_t byte = sampleData[samplePosition / 2];
byte = (samplePosition & 1) ? byte >> 4 : byte & 15;
return *lastDelta += sampleDictionary[byte];
}
static void Adpcm2Samp(uint8_t * sample, uint32_t length)
{
const int8_t *sampleDictionary;
const uint8_t *sampleData;
uint32_t samplePosition;
int8_t lastDelta;
uint8_t * sampleDataOut = (uint8_t *) malloc(length);
if (!sampleDataOut)
return;
sampleDictionary = (const int8_t *)sample;
sampleData = (uint8_t*)sampleDictionary + 16;
samplePosition = 0;
lastDelta = 0;
while (samplePosition < length)
{
sampleDataOut[samplePosition] = GetAdpcmSample(sampleDictionary, sampleData, samplePosition, &lastDelta);
samplePosition++;
}
memcpy(sample, sampleDataOut, length);
}
static void FreeAllInstr(PLAYER *p) static void FreeAllInstr(PLAYER *p)
{ {
@ -2273,9 +2305,10 @@ static void FreeAllInstr(PLAYER *p)
static int8_t AllocateInstr(PLAYER *pl, uint16_t i) static int8_t AllocateInstr(PLAYER *pl, uint16_t i)
{ {
InstrTyp *p;
uint8_t j; uint8_t j;
InstrTyp *p;
if (pl->Instr[i] == NULL) if (pl->Instr[i] == NULL)
{ {
p = (InstrTyp *)(calloc(1, sizeof (InstrTyp))); p = (InstrTyp *)(calloc(1, sizeof (InstrTyp)));
@ -2329,75 +2362,43 @@ static int8_t LoadInstrHeader(PLAYER *p, MEM *f, uint16_t i)
return (1); return (1);
} }
static inline int8_t get_adpcm_sample(const int8_t *sampleDictionary, const uint8_t *sampleData, int32_t samplePosition, int8_t *lastDelta)
{
uint8_t byte = sampleData[samplePosition / 2];
byte = (samplePosition & 1) ? byte >> 4 : byte & 15;
return *lastDelta += sampleDictionary[byte];
}
static void Adpcm2Samp(uint8_t * sample, uint32_t length)
{
const int8_t *sampleDictionary;
const uint8_t *sampleData;
uint32_t samplePosition;
int8_t lastDelta;
uint8_t * sampleDataOut = (uint8_t *) malloc(length);
if (!sampleDataOut)
return;
sampleDictionary = (const int8_t *)sample;
sampleData = (uint8_t*)sampleDictionary + 16;
samplePosition = 0;
lastDelta = 0;
while (samplePosition < length)
{
sampleDataOut[samplePosition] = get_adpcm_sample(sampleDictionary, sampleData, samplePosition, &lastDelta);
samplePosition++;
}
memcpy(sample, sampleDataOut, length);
}
static int8_t LoadInstrSample(PLAYER *p, MEM *f, uint16_t i) static int8_t LoadInstrSample(PLAYER *p, MEM *f, uint16_t i)
{ {
uint16_t j; uint16_t j;
int32_t l; int32_t l;
InstrTyp *Instr;
SampleTyp *s; SampleTyp *s;
if (p->Instr[i] != NULL) if (p->Instr[i] != NULL)
{ {
for (j = 1; j <= p->Instr[i]->AntSamp; ++j) Instr = p->Instr[i];
for (j = 1; j <= Instr->AntSamp; ++j)
{ {
int adpcm = 0; int adpcm = 0;
p->Instr[i]->Samp[j - 1].Pek = NULL; s = &Instr->Samp[j - 1];
s->Pek = NULL;
l = p->Instr[i]->Samp[j - 1].Len; l = s->Len;
if (p->Instr[i]->Samp[j - 1].skrap == 0xAD && if (s->skrap == 0xAD &&
!(p->Instr[i]->Samp[j - 1].Typ & (16|32))) !(s->Typ & (16|32)))
adpcm = (((l + 1) / 2) + 16); adpcm = ((l + 1) / 2) + 16;
if (l > 0) if (l > 0)
{ {
p->Instr[i]->Samp[j - 1].Pek = (int8_t *)(malloc(l)); s->Pek = (int8_t *)(malloc(l));
if (p->Instr[i]->Samp[j - 1].Pek == NULL) if (s->Pek == NULL)
{ {
for (j = i; j <= p->Song.AntInstrs; ++j) FreeInstr(p, j); for (j = i; j <= p->Song.AntInstrs; ++j) FreeInstr(p, j);
return (0); return (0);
} }
mread(p->Instr[i]->Samp[j - 1].Pek, adpcm ? adpcm : l, 1, f); mread(s->Pek, adpcm ? adpcm : l, 1, f);
if (!adpcm) if (!adpcm)
Delta2Samp(p->Instr[i]->Samp[j - 1].Pek, l, p->Instr[i]->Samp[j - 1].Typ); Delta2Samp(s->Pek, l, s->Typ);
else else
Adpcm2Samp((uint8_t *)p->Instr[i]->Samp[j - 1].Pek, l); Adpcm2Samp((uint8_t *)s->Pek, l);
} }
s = &p->Instr[i]->Samp[j - 1];
if (s->Pek == NULL) if (s->Pek == NULL)
{ {
s->Len = 0; s->Len = 0;
@ -2459,7 +2460,7 @@ static void UnpackPatt(PLAYER *p, TonTyp *patdata, uint16_t length, uint16_t pac
} }
} }
static int8_t PatternEmpty(PLAYER *p, uint16_t nr) static inline int8_t PatternEmpty(PLAYER *p, uint16_t nr)
{ {
uint32_t patofs; uint32_t patofs;
uint16_t i; uint16_t i;
@ -2491,12 +2492,12 @@ static int8_t PatternEmpty(PLAYER *p, uint16_t nr)
static int8_t LoadPatterns(PLAYER *p, MEM *f) static int8_t LoadPatterns(PLAYER *p, MEM *f)
{ {
PatternHeaderTyp ph;
uint8_t *patttmp; uint8_t *patttmp;
uint16_t i; uint16_t i;
uint8_t tmpLen; uint8_t tmpLen;
PatternHeaderTyp ph;
for (i = 0; i < p->Song.AntPtn; ++i) for (i = 0; i < p->Song.AntPtn; ++i)
{ {
mread(&ph.PatternHeaderSize, 4, 1, f); mread(&ph.PatternHeaderSize, 4, 1, f);
@ -2522,6 +2523,7 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f)
if (meof(f)) if (meof(f))
{ {
mclose(f);
return (0); return (0);
} }
@ -2531,12 +2533,14 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f)
p->Patt[i] = (TonTyp *)(calloc(sizeof (TonTyp), ph.PattLen * 127)); p->Patt[i] = (TonTyp *)(calloc(sizeof (TonTyp), ph.PattLen * 127));
if (p->Patt[i] == NULL) if (p->Patt[i] == NULL)
{ {
mclose(f);
return (0); return (0);
} }
patttmp = (uint8_t *)(malloc(ph.DataLen)); patttmp = (uint8_t *)(malloc(ph.DataLen));
if (patttmp == NULL) if (patttmp == NULL)
{ {
mclose(f);
return (0); return (0);
} }
@ -2547,9 +2551,12 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f)
if (PatternEmpty(p, i)) if (PatternEmpty(p, i))
{ {
if (p->Patt[i]) free(p->Patt[i]); if (p->Patt[i] != NULL)
{
free(p->Patt[i]);
p->Patt[i] = NULL; p->Patt[i] = NULL;
}
p->PattLens[i] = 64; p->PattLens[i] = 64;
} }
} }
@ -2557,10 +2564,8 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f)
return (1); return (1);
} }
static void ft2play_FreeSong(void *_p) static void ft2play_FreeSong(PLAYER *p)
{ {
PLAYER * p = (PLAYER *)_p;
p->Playing = 0; p->Playing = 0;
memset(p->voice, 0, sizeof (p->voice)); memset(p->voice, 0, sizeof (p->voice));
@ -2584,8 +2589,10 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size)
p->ModuleLoaded = 0; p->ModuleLoaded = 0;
AllocateInstr(p, 0); // instr0 = placeholder for invalid ins // instr 0 is a placeholder for invalid instruments
p->Instr[0]->Samp[0].Vol = 0; // mute invalid instruments AllocateInstr(p, 0);
p->Instr[0]->Samp[0].Vol = 0;
// ------------------------------------------------
FreeMusic(p); FreeMusic(p);
p->LinearFrqTab = 0; p->LinearFrqTab = 0;
@ -2594,16 +2601,17 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size)
if (f == NULL) return (0); if (f == NULL) return (0);
// start loading // start loading
mread(&h, sizeof (h), 1, f);
mread(&h, sizeof(h), 1, f); if ((memcmp(h.Sig, "Extended Module: ", 17) != 0) || (h.Ver < 0x0102) || (h.Ver > 0x104))
if ((memcmp(h.Sig, "Extended Module: ", 17) != 0) || (h.Ver < 0x0102) || (h.Ver > 0x0104))
{ {
mclose(f);
return (0); return (0);
} }
if ((h.AntChn < 1) || (h.AntChn > 127) || (h.AntPtn > 256)) if ((h.AntChn < 1) || (h.AntChn > 127) || (h.AntPtn > 256))
{ {
mclose(f);
return (0); return (0);
} }
@ -2614,16 +2622,16 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size)
return (0); return (0);
} }
/*memcpy(p->Song.Name, h.Name, 20); memcpy(p->Song.Name, h.Name, 20);
memcpy(p->Song.ProgName, h.ProggName, 20);*/ memcpy(p->Song.ProgName, h.ProggName, 20);
p->Song.Len = h.Len; p->Song.Len = h.Len;
p->Song.RepS = h.RepS; p->Song.RepS = h.RepS;
p->Song.AntChn = (uint8_t)(h.AntChn); p->Song.AntChn = (uint8_t)(h.AntChn);
p->Song.InitSpeed = h.DefSpeed ? h.DefSpeed : 125; p->Song.Speed = h.DefSpeed ? h.DefSpeed : 125;
p->Song.Speed = p->Song.InitSpeed; p->Song.Tempo = h.DefTempo ? h.DefTempo : 6;
p->Song.InitTempo = h.DefTempo ? h.DefTempo : 6; p->Song.InitSpeed = p->Song.Speed;
p->Song.Tempo = p->Song.InitTempo; p->Song.InitTempo = p->Song.Tempo;
p->Song.AntInstrs = h.AntInstrs; p->Song.AntInstrs = h.AntInstrs;
p->Song.AntPtn = h.AntPtn; p->Song.AntPtn = h.AntPtn;
p->Song.Ver = h.Ver; p->Song.Ver = h.Ver;
@ -2672,7 +2680,7 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size)
{ {
if (LoadInstrHeader(p, f, i) == 0) if (LoadInstrHeader(p, f, i) == 0)
{ {
FreeInstr(p, i); FreeInstr(p, (uint8_t)(i));
mclose(f); mclose(f);
f = NULL; f = NULL;
break; break;
@ -2704,7 +2712,22 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size)
return (1); return (1);
} }
void voiceSetSource(PLAYER *p, uint8_t i, const int8_t *sampleData, static void setSamplesPerFrame(PLAYER *p, uint32_t val)
{
p->samplesPerFrame = val;
#ifdef USE_VOL_RAMP
p->f_samplesPerFrame = 1.0f / ((float)(val) / 4.0f);
p->f_samplesPerFrameSharp = 1.0f / (p->f_outputFreq / 1000.0f); // 1ms
#endif
}
static void setSamplingInterpolation(PLAYER *p, int8_t value)
{
p->samplingInterpolation = value;
}
static void voiceSetSource(PLAYER *p, uint8_t i, const int8_t *sampleData,
int32_t sampleLength, int32_t sampleLoopLength, int32_t sampleLength, int32_t sampleLoopLength,
int32_t sampleLoopEnd, int8_t loopEnabled, int32_t sampleLoopEnd, int8_t loopEnabled,
int8_t sixteenbit, int8_t stereo) int8_t sixteenbit, int8_t stereo)
@ -2733,9 +2756,6 @@ void voiceSetSource(PLAYER *p, uint8_t i, const int8_t *sampleData,
p->voice[i].loopDir = 0; p->voice[i].loopDir = 0;
p->voice[i].stereo = stereo; p->voice[i].stereo = stereo;
p->voice[i].interpolating = 1; p->voice[i].interpolating = 1;
#ifdef USE_VOL_RAMP
p->voice[i].rampTerminates = 0;
#endif
resampler_clear(p->resampler[i]); resampler_clear(p->resampler[i]);
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
@ -2745,7 +2765,7 @@ void voiceSetSource(PLAYER *p, uint8_t i, const int8_t *sampleData,
#endif #endif
} }
void voiceSetSamplePosition(PLAYER *p, uint8_t i, uint16_t value) static void voiceSetSamplePosition(PLAYER *p, uint8_t i, uint16_t value)
{ {
p->voice[i].samplePosition = value; p->voice[i].samplePosition = value;
if (p->voice[i].samplePosition >= p->voice[i].sampleLength) if (p->voice[i].samplePosition >= p->voice[i].sampleLength)
@ -2764,7 +2784,7 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t i, uint16_t value)
#endif #endif
} }
void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t sharp) static void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t sharp)
{ {
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
if (p->rampStyle > 0 && !sharp) if (p->rampStyle > 0 && !sharp)
@ -2778,15 +2798,13 @@ void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t sharp)
if (sharp) if (sharp)
{ {
if (vol) if (vol)
{ p->voice[i].volume = 0;
p->voice[i].volume = 0.0f;
}
else if (sharp != 3) else if (sharp != 3)
p->voice[i].rampTerminates = 1; p->voice[i].rampTerminates = 1;
} }
p->voice[i].targetVol = vol; p->voice[i].targetVol = vol;
p->voice[i].volDelta = (p->voice[i].targetVol - p->voice[i].volume) * rampRate; p->voice[i].volDelta = rampRate * (p->voice[i].targetVol - p->voice[i].volume);
} }
else else
{ {
@ -2795,11 +2813,11 @@ void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t sharp)
p->voice[i].volDelta = 0; p->voice[i].volDelta = 0;
} }
#else #else
p->voice[i].volume = vol; voice[i].volume = vol;
#endif #endif
} }
void voiceSetPanning(PLAYER *p, uint8_t i, uint8_t pan) static void voiceSetPanning(PLAYER *p, uint8_t i, uint8_t pan)
{ {
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
if (p->rampStyle > 1) if (p->rampStyle > 1)
@ -2820,12 +2838,12 @@ void voiceSetPanning(PLAYER *p, uint8_t i, uint8_t pan)
p->voice[i].panDeltaR = 0; p->voice[i].panDeltaR = 0;
} }
#else #else
voice[i].panningL = p->PanningTab[256 - pan]; voice[i].panningL = PanningTab[256 - pan];
voice[i].panningR = p->PanningTab[ pan]; voice[i].panningR = PanningTab[ pan];
#endif #endif
} }
void voiceSetSamplingFrequency(PLAYER *p, uint8_t i, uint32_t samplingFrequency) static void voiceSetSamplingFrequency(PLAYER *p, uint8_t i, uint32_t samplingFrequency)
{ {
p->voice[i].incRate = (float)(samplingFrequency) / p->f_outputFreq; p->voice[i].incRate = (float)(samplingFrequency) / p->f_outputFreq;
} }
@ -2871,11 +2889,10 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
resampler = p->resampler[ch]; resampler = p->resampler[ch];
resampler_set_rate(resampler, p->voice[ch].incRate ); resampler_set_rate(resampler, p->voice[ch].incRate);
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j) for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
{ {
p->voice[ch].busy = 1;
samplePosition = p->voice[ch].samplePosition; samplePosition = p->voice[ch].samplePosition;
while (interpolating && resampler_get_free_count(resampler)) while (interpolating && resampler_get_free_count(resampler))
@ -2928,17 +2945,16 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
if ( !resampler_ready(resampler) ) if ( !resampler_ready(resampler) )
{ {
p->voice[ch].sampleData = NULL; p->voice[ch].sampleData = NULL;
p->voice[ch].busy = 0;
break; break;
} }
sample = resampler_get_sample(resampler); sample = resampler_get_sample(resampler);
resampler_remove_sample(resampler); resampler_remove_sample(resampler);
sample = (sample * p->voice[ch].volume); sample *= p->voice[ch].volume;
sampleL = (sample * p->voice[ch].panningL); sampleL = sample * p->voice[ch].panningL;
sampleR = (sample * p->voice[ch].panningR); sampleR = sample * p->voice[ch].panningR;
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
if (rampStyle > 0) if (rampStyle > 0)
@ -2982,11 +2998,7 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
} }
if (p->voice[ch].rampTerminates && !p->voice[ch].volume) if (p->voice[ch].rampTerminates && !p->voice[ch].volume)
{
p->voice[ch].sampleData = NULL; p->voice[ch].sampleData = NULL;
p->voice[ch].samplePosition = 0;
p->voice[ch].busy = 0;
}
} }
#endif #endif
@ -3040,12 +3052,11 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
resampler[1] = p->resampler[ch+127]; resampler[1] = p->resampler[ch+127];
#endif #endif
resampler_set_rate(resampler[0], p->voice[ch].incRate ); resampler_set_rate(resampler[0], p->voice[ch].incRate);
resampler_set_rate(resampler[1], p->voice[ch].incRate ); resampler_set_rate(resampler[1], p->voice[ch].incRate);
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j) for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
{ {
p->voice[ch].busy = 1;
samplePosition = p->voice[ch].samplePosition; samplePosition = p->voice[ch].samplePosition;
while (interpolating && resampler_get_free_count(resampler[0])) while (interpolating && resampler_get_free_count(resampler[0]))
@ -3099,7 +3110,6 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
if ( !resampler_ready(resampler[0]) ) if ( !resampler_ready(resampler[0]) )
{ {
p->voice[ch].sampleData = NULL; p->voice[ch].sampleData = NULL;
p->voice[ch].busy = 0;
break; break;
} }
@ -3108,11 +3118,11 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
resampler_remove_sample(resampler[0]); resampler_remove_sample(resampler[0]);
resampler_remove_sample(resampler[1]); resampler_remove_sample(resampler[1]);
sampleL = (sampleL * p->voice[ch].volume); sampleL *= p->voice[ch].volume;
sampleR = (sampleR * p->voice[ch].volume); sampleR *= p->voice[ch].volume;
sampleL = (sampleL * p->voice[ch].panningL); sampleL *= p->voice[ch].panningL;
sampleR = (sampleR * p->voice[ch].panningR); sampleR *= p->voice[ch].panningR;
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
if (rampStyle > 0) if (rampStyle > 0)
@ -3156,11 +3166,7 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
} }
if (p->voice[ch].rampTerminates && !p->voice[ch].volume) if (p->voice[ch].rampTerminates && !p->voice[ch].volume)
{
p->voice[ch].sampleData = NULL; p->voice[ch].sampleData = NULL;
p->voice[ch].samplePosition = 0;
p->voice[ch].busy = 0;
}
} }
#endif #endif
@ -3206,15 +3212,14 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples)
loopDir = p->voice[ch].loopDir; loopDir = p->voice[ch].loopDir;
interpolating = p->voice[ch].interpolating; interpolating = p->voice[ch].interpolating;
sampleData = (const int16_t *)(p->voice[ch].sampleData); sampleData = (const int16_t *) p->voice[ch].sampleData;
resampler = p->resampler[ch]; resampler = p->resampler[ch];
resampler_set_rate(resampler, p->voice[ch].incRate ); resampler_set_rate(resampler, p->voice[ch].incRate);
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j) for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
{ {
p->voice[ch].busy = 1;
samplePosition = p->voice[ch].samplePosition; samplePosition = p->voice[ch].samplePosition;
while (interpolating && resampler_get_free_count(resampler)) while (interpolating && resampler_get_free_count(resampler))
@ -3267,17 +3272,16 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples)
if ( !resampler_ready(resampler) ) if ( !resampler_ready(resampler) )
{ {
p->voice[ch].sampleData = NULL; p->voice[ch].sampleData = NULL;
p->voice[ch].busy = 0;
break; break;
} }
sample = resampler_get_sample(resampler); sample = resampler_get_sample(resampler);
resampler_remove_sample(resampler); resampler_remove_sample(resampler);
sample = (sample * p->voice[ch].volume); sample *= p->voice[ch].volume;
sampleL = (sample * p->voice[ch].panningL); sampleL = sample * p->voice[ch].panningL;
sampleR = (sample * p->voice[ch].panningR); sampleR = sample * p->voice[ch].panningR;
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
if (rampStyle > 0) if (rampStyle > 0)
@ -3321,11 +3325,7 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples)
} }
if (p->voice[ch].rampTerminates && !p->voice[ch].volume) if (p->voice[ch].rampTerminates && !p->voice[ch].volume)
{
p->voice[ch].sampleData = NULL; p->voice[ch].sampleData = NULL;
p->voice[ch].samplePosition = 0;
p->voice[ch].busy = 0;
}
} }
#endif #endif
@ -3370,7 +3370,7 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
loopDir = p->voice[ch].loopDir; loopDir = p->voice[ch].loopDir;
interpolating = p->voice[ch].interpolating; interpolating = p->voice[ch].interpolating;
sampleData = (const int16_t *)(p->voice[ch].sampleData); sampleData = (const int16_t *) p->voice[ch].sampleData;
resampler[0] = p->resampler[ch]; resampler[0] = p->resampler[ch];
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
@ -3379,12 +3379,11 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
resampler[1] = p->resampler[ch+127]; resampler[1] = p->resampler[ch+127];
#endif #endif
resampler_set_rate(resampler[0], p->voice[ch].incRate ); resampler_set_rate(resampler[0], p->voice[ch].incRate);
resampler_set_rate(resampler[1], p->voice[ch].incRate ); resampler_set_rate(resampler[1], p->voice[ch].incRate);
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j) for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
{ {
p->voice[ch].busy = 1;
samplePosition = p->voice[ch].samplePosition; samplePosition = p->voice[ch].samplePosition;
while (interpolating && resampler_get_free_count(resampler[0])) while (interpolating && resampler_get_free_count(resampler[0]))
@ -3438,7 +3437,6 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
if ( !resampler_ready(resampler[0]) ) if ( !resampler_ready(resampler[0]) )
{ {
p->voice[ch].sampleData = NULL; p->voice[ch].sampleData = NULL;
p->voice[ch].busy = 0;
break; break;
} }
@ -3447,11 +3445,11 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
resampler_remove_sample(resampler[0]); resampler_remove_sample(resampler[0]);
resampler_remove_sample(resampler[1]); resampler_remove_sample(resampler[1]);
sampleL = (sampleL * p->voice[ch].volume); sampleL *= p->voice[ch].volume;
sampleR = (sampleR * p->voice[ch].volume); sampleR *= p->voice[ch].volume;
sampleL = (sampleL * p->voice[ch].panningL); sampleL *= p->voice[ch].panningL;
sampleR = (sampleR * p->voice[ch].panningR); sampleR *= p->voice[ch].panningR;
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
if (rampStyle > 0) if (rampStyle > 0)
@ -3495,11 +3493,7 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
} }
if (p->voice[ch].rampTerminates && !p->voice[ch].volume) if (p->voice[ch].rampTerminates && !p->voice[ch].volume)
{
p->voice[ch].sampleData = NULL; p->voice[ch].sampleData = NULL;
p->voice[ch].samplePosition = 0;
p->voice[ch].busy = 0;
}
} }
#endif #endif
@ -3569,7 +3563,7 @@ void ft2play_RenderFloat(void *_p, float *buffer, int32_t count)
int32_t samplesTodo; int32_t samplesTodo;
float * outputStream; float * outputStream;
if (p->isMixing) if (p->Playing)
{ {
outputStream = buffer; outputStream = buffer;
@ -3664,13 +3658,13 @@ void * ft2play_Alloc(uint32_t _samplingFrequency, int8_t interpolation, int8_t r
if ( !p->masterBufferL || !p->masterBufferR ) if ( !p->masterBufferL || !p->masterBufferR )
goto error; goto error;
p->samplingInterpolation = interpolation; setSamplingInterpolation(p, interpolation);
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
p->rampStyle = ramp_style; p->rampStyle = ramp_style;
#endif #endif
resampler_init(); resampler_init();
#ifdef USE_VOL_RAMP #ifdef USE_VOL_RAMP
for ( i = 0; i < 127 * 2 * 2; ++i ) for ( i = 0; i < 127 * 2 * 2; ++i )
#else #else
@ -3753,10 +3747,8 @@ void ft2play_Free(void *_p)
PLAYER * p = (PLAYER *)_p; PLAYER * p = (PLAYER *)_p;
if (p->isMixing) if (p->Playing)
{ {
p->isMixing = 0;
if (p->masterBufferL) free(p->masterBufferL); p->masterBufferL = NULL; if (p->masterBufferL) free(p->masterBufferL); p->masterBufferL = NULL;
if (p->masterBufferR) free(p->masterBufferR); p->masterBufferR = NULL; if (p->masterBufferR) free(p->masterBufferR); p->masterBufferR = NULL;
} }
@ -3799,7 +3791,6 @@ void ft2play_PlaySong(void *_p, int32_t startOrder)
p->Playing = 1; p->Playing = 1;
setSamplesPerFrame(p, ((p->outputFreq * 5UL) / 2 / p->Song.Speed)); setSamplesPerFrame(p, ((p->outputFreq * 5UL) / 2 / p->Song.Speed));
p->isMixing = 1;
SetPos(p, (int16_t)startOrder, 0); SetPos(p, (int16_t)startOrder, 0);
@ -3810,7 +3801,7 @@ void ft2play_PlaySong(void *_p, int32_t startOrder)
p->playedOrder[startOrder / 8] = 1 << (startOrder % 8); p->playedOrder[startOrder / 8] = 1 << (startOrder % 8);
} }
static MEM *mopen(const uint8_t *src, uintptr_t length) static MEM *mopen(const uint8_t *src, size_t length)
{ {
MEM *b; MEM *b;
@ -3831,23 +3822,13 @@ static MEM *mopen(const uint8_t *src, uintptr_t length)
static void mclose(MEM *buf) static void mclose(MEM *buf)
{ {
if (buf != NULL) if (buf != NULL)
{
free(buf); free(buf);
buf = NULL;
}
} }
#if 0
static intptr_t mtell(MEM *buf)
{
return (buf->_bufsiz - buf->_cnt);
}
#endif
static size_t mread(void *buffer, size_t size, size_t count, MEM *buf) static size_t mread(void *buffer, size_t size, size_t count, MEM *buf)
{ {
size_t wrcnt; size_t wrcnt;
intptr_t pcnt; ssize_t pcnt;
if (buf == NULL) return (0); if (buf == NULL) return (0);
if (buf->_ptr == NULL) return (0); if (buf->_ptr == NULL) return (0);
@ -3855,7 +3836,7 @@ static size_t mread(void *buffer, size_t size, size_t count, MEM *buf)
wrcnt = size * count; wrcnt = size * count;
if ((size == 0) || buf->_eof) return (0); if ((size == 0) || buf->_eof) return (0);
pcnt = ((uint32_t)(buf->_cnt) > wrcnt) ? wrcnt : buf->_cnt; pcnt = (buf->_cnt > wrcnt) ? wrcnt : buf->_cnt;
memcpy(buffer, buf->_ptr, pcnt); memcpy(buffer, buf->_ptr, pcnt);
buf->_cnt -= pcnt; buf->_cnt -= pcnt;
@ -3871,35 +3852,6 @@ static size_t mread(void *buffer, size_t size, size_t count, MEM *buf)
return (pcnt / size); return (pcnt / size);
} }
#if 0
static size_t mwrite(const void *buffer, size_t size, size_t count, MEM *buf)
{
size_t wrcnt;
intptr_t pcnt;
if (buf == NULL) return (0);
if (buf->_ptr == NULL) return (0);
wrcnt = size * count;
if ((size == 0) || buf->_eof) return (0);
pcnt = ((uint32_t)(buf->_cnt) > wrcnt) ? wrcnt : buf->_cnt;
memcpy(buf->_ptr, buffer, pcnt);
buf->_cnt -= pcnt;
buf->_ptr += pcnt;
if (buf->_cnt <= 0)
{
buf->_ptr = buf->_base + buf->_bufsiz;
buf->_cnt = 0;
buf->_eof = 1;
}
return (pcnt / size);
}
#endif
static int32_t meof(MEM *buf) static int32_t meof(MEM *buf)
{ {
if (buf == NULL) return (1); // XXX: Should return a different value? if (buf == NULL) return (1); // XXX: Should return a different value?
@ -3907,7 +3859,7 @@ static int32_t meof(MEM *buf)
return (buf->_eof); return (buf->_eof);
} }
static void mseek(MEM *buf, intptr_t offset, int32_t whence) static void mseek(MEM *buf, ssize_t offset, int32_t whence)
{ {
if (buf == NULL) return; if (buf == NULL) return;
@ -3932,16 +3884,6 @@ static void mseek(MEM *buf, intptr_t offset, int32_t whence)
} }
} }
static void setSamplesPerFrame(PLAYER *p, uint32_t val)
{
p->samplesPerFrame = val;
#ifdef USE_VOL_RAMP
p->f_samplesPerFrame = 1.0f / ((float)(val) / 4.0f);
p->f_samplesPerFrameSharp = 1.0f / (p->f_outputFreq / 1000.0f); // 1ms
#endif
}
void ft2play_Mute(void *_p, int8_t channel, int8_t mute) void ft2play_Mute(void *_p, int8_t channel, int8_t mute)
{ {
PLAYER * p = (PLAYER *)_p; PLAYER * p = (PLAYER *)_p;
@ -3970,11 +3912,11 @@ void ft2play_GetInfo(void *_p, ft2_info *info)
info->speed = p->Song.Tempo; // Hurr info->speed = p->Song.Tempo; // Hurr
info->tempo = p->Song.Speed; info->tempo = p->Song.Speed;
channels_playing = 0; channels_playing = 0;
if (p->isMixing) if (p->Playing)
{ {
for (i = 0; i < p->Song.AntChn; ++i) for (i = 0; i < p->Song.AntChn; ++i)
{ {
if (p->voice[i].busy) if (p->voice[i].sampleData)
++channels_playing; ++channels_playing;
} }
} }