Re-ported ft2play from original sources
parent
0b436c8437
commit
00a014f270
|
@ -1,36 +1,33 @@
|
|||
/*
|
||||
** FT2PLAY v0.42a
|
||||
** ==============
|
||||
**
|
||||
** 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
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
**
|
||||
** non-FT2 effects:
|
||||
** - E8x - set panning
|
||||
**
|
||||
** (extreme) non-FT2 extensions:
|
||||
** - Max 127 channels (was 32)
|
||||
** - Any amount-of-channels number (FT2 supports *even* numbers only)
|
||||
** - Max 256 instruments (was 128)
|
||||
** - Max 32 samples per instrument (was 16)
|
||||
** - Max 1024 rows per pattern (was 256)
|
||||
** - Stereo samples
|
||||
**
|
||||
** These additions shouldn't break FT2 accuracy, unless the XM is malicious.
|
||||
**
|
||||
*/
|
||||
** FT2PLAY v0.42a
|
||||
** ==============
|
||||
**
|
||||
** 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
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
**
|
||||
** (extreme) non-FT2 extensions:
|
||||
** - Max 127 channels (was 32)
|
||||
** - Any amount-of-channels number (FT2 supports *even* numbers only)
|
||||
** - Max 256 instruments (was 128)
|
||||
** - Max 32 samples per instrument (was 16)
|
||||
** - Max 1024 rows per pattern (was 256)
|
||||
** - Stereo samples
|
||||
**
|
||||
** These additions shouldn't break FT2 accuracy, unless the XM is malicious.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "resampler.h"
|
||||
|
||||
|
@ -42,6 +39,8 @@
|
|||
|
||||
#define USE_VOL_RAMP
|
||||
|
||||
enum { _soundBufferSize = 512 };
|
||||
|
||||
enum
|
||||
{
|
||||
IS_Vol = 1,
|
||||
|
@ -174,9 +173,9 @@ typedef struct SongTyp_t
|
|||
uint8_t PosJumpFlag;
|
||||
uint8_t SongTab[256];
|
||||
uint16_t Ver;
|
||||
/*char Name[21];
|
||||
char Name[21];
|
||||
char ProgName[21];
|
||||
char InstrName[256][23];*/
|
||||
char InstrName[256][23];
|
||||
uint16_t startOrder;
|
||||
} SongTyp;
|
||||
|
||||
|
@ -309,11 +308,10 @@ typedef struct TonTyp_t
|
|||
|
||||
typedef struct
|
||||
{
|
||||
const int8_t *sampleData;
|
||||
int8_t loopEnabled;
|
||||
int8_t sixteenBit;
|
||||
int8_t stereo;
|
||||
int8_t busy;
|
||||
const int8_t *sampleData;
|
||||
int8_t loopBidi;
|
||||
int8_t loopDir;
|
||||
int32_t sampleLength;
|
||||
|
@ -323,7 +321,6 @@ typedef struct
|
|||
int8_t interpolating;
|
||||
|
||||
float incRate;
|
||||
float frac;
|
||||
float volume;
|
||||
float panningL;
|
||||
float panningR;
|
||||
|
@ -344,12 +341,13 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
uint8_t *_ptr;
|
||||
uintptr_t _cnt;
|
||||
size_t _cnt;
|
||||
uint8_t *_base;
|
||||
uintptr_t _bufsiz;
|
||||
size_t _bufsiz;
|
||||
int32_t _eof;
|
||||
} MEM;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int8_t *VibSineTab;
|
||||
|
@ -359,7 +357,7 @@ typedef struct
|
|||
int16_t *amigaPeriods;
|
||||
uint32_t *LogTab;
|
||||
int8_t LinearFrqTab;
|
||||
int32_t soundBufferSize;
|
||||
uint32_t soundBufferSize;
|
||||
uint32_t outputFreq;
|
||||
|
||||
TonTyp *NilPatternLine;
|
||||
|
@ -387,19 +385,16 @@ typedef struct
|
|||
|
||||
// pre-initialized variables
|
||||
int8_t samplingInterpolation;// = 1;
|
||||
#ifdef USE_VOL_RAMP
|
||||
int8_t rampStyle;
|
||||
#endif
|
||||
float *masterBufferL;// = NULL;
|
||||
float *masterBufferR;// = NULL;
|
||||
int32_t samplesLeft;// = 0; // must be signed
|
||||
int8_t isMixing;// = 0;
|
||||
uint32_t samplesPerFrame;// = 882;
|
||||
|
||||
// globally accessed
|
||||
int8_t ModuleLoaded;// = 0;
|
||||
int8_t Playing;// = 0;
|
||||
uint8_t numChannels;// = 127;
|
||||
uint16_t numChannels;// = 127;
|
||||
|
||||
uint8_t muted[16];
|
||||
|
||||
|
@ -407,17 +402,14 @@ typedef struct
|
|||
uint8_t playedOrder[8192];
|
||||
} PLAYER;
|
||||
|
||||
enum { _soundBufferSize = 512 };
|
||||
|
||||
// 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 intptr_t mtell(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 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 voiceSetSource(PLAYER *, uint8_t i, const int8_t *sampleData,
|
||||
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);
|
||||
static void voiceSetSamplePosition(PLAYER *, uint8_t i, uint16_t value);
|
||||
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 ft2play_FreeSong(PLAYER *);
|
||||
|
||||
|
||||
// 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,
|
||||
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
|
||||
static const uint8_t VibTab[32] =
|
||||
static uint8_t VibTab[32] =
|
||||
{
|
||||
0, 24, 49, 74, 97,120,141,161,
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
// CODE START
|
||||
|
||||
|
||||
static inline void RetrigVolume(StmTyp *ch)
|
||||
{
|
||||
ch->RealVol = ch->OldVol;
|
||||
|
@ -965,13 +960,19 @@ CheckEffects:
|
|||
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
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (ch->TonTyp & 0xFF00)
|
||||
RetrigVolume(ch);
|
||||
|
||||
if (ch->TonTyp & 0xFF00) RetrigVolume(ch);
|
||||
RetrigEnvelopeVibrato(ch);
|
||||
|
||||
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]);
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
voiceSetSamplePosition(p, ch->Nr, ch->SmpStartPos);
|
||||
}
|
||||
|
||||
ch->Status = 0;
|
||||
|
@ -2094,20 +2092,21 @@ static void StopVoices(PLAYER *p)
|
|||
|
||||
for (a = 0; a < 127; ++a)
|
||||
{
|
||||
p->Stm[a].Nr = a;
|
||||
p->Stm[a].TonTyp = 0;
|
||||
p->Stm[a].RelTonNr = 0;
|
||||
p->Stm[a].InstrNr = 0;
|
||||
p->Stm[a].InstrSeg = *p->Instr[0];
|
||||
p->Stm[a].Status = IS_Vol;
|
||||
p->Stm[a].RealVol = 0;
|
||||
p->Stm[a].OutVol = 0;
|
||||
p->Stm[a].OldVol = 0;
|
||||
p->Stm[a].FinalVol = 0.0f;
|
||||
p->Stm[a].OldPan = 128;
|
||||
p->Stm[a].OutPan = 128;
|
||||
p->Stm[a].FinalPan = 128;
|
||||
p->Stm[a].VibDepth = 0;
|
||||
StmTyp *ch = &p->Stm[a];
|
||||
ch->Nr = a;
|
||||
ch->TonTyp = 0;
|
||||
ch->RelTonNr = 0;
|
||||
ch->InstrNr = 0;
|
||||
ch->InstrSeg = *p->Instr[0];
|
||||
ch->Status = IS_Vol;
|
||||
ch->RealVol = 0;
|
||||
ch->OutVol = 0;
|
||||
ch->OldVol = 0;
|
||||
ch->FinalVol = 0.0f;
|
||||
ch->OldPan = 128;
|
||||
ch->OutPan = 128;
|
||||
ch->FinalPan = 128;
|
||||
ch->VibDepth = 0;
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -2273,9 +2305,10 @@ static void FreeAllInstr(PLAYER *p)
|
|||
|
||||
static int8_t AllocateInstr(PLAYER *pl, uint16_t i)
|
||||
{
|
||||
InstrTyp *p;
|
||||
uint8_t j;
|
||||
|
||||
InstrTyp *p;
|
||||
|
||||
if (pl->Instr[i] == NULL)
|
||||
{
|
||||
p = (InstrTyp *)(calloc(1, sizeof (InstrTyp)));
|
||||
|
@ -2329,75 +2362,43 @@ static int8_t LoadInstrHeader(PLAYER *p, MEM *f, uint16_t i)
|
|||
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)
|
||||
{
|
||||
uint16_t j;
|
||||
int32_t l;
|
||||
|
||||
InstrTyp *Instr;
|
||||
SampleTyp *s;
|
||||
|
||||
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;
|
||||
p->Instr[i]->Samp[j - 1].Pek = NULL;
|
||||
s = &Instr->Samp[j - 1];
|
||||
s->Pek = NULL;
|
||||
|
||||
l = p->Instr[i]->Samp[j - 1].Len;
|
||||
if (p->Instr[i]->Samp[j - 1].skrap == 0xAD &&
|
||||
!(p->Instr[i]->Samp[j - 1].Typ & (16|32)))
|
||||
adpcm = (((l + 1) / 2) + 16);
|
||||
l = s->Len;
|
||||
if (s->skrap == 0xAD &&
|
||||
!(s->Typ & (16|32)))
|
||||
adpcm = ((l + 1) / 2) + 16;
|
||||
if (l > 0)
|
||||
{
|
||||
p->Instr[i]->Samp[j - 1].Pek = (int8_t *)(malloc(l));
|
||||
if (p->Instr[i]->Samp[j - 1].Pek == NULL)
|
||||
s->Pek = (int8_t *)(malloc(l));
|
||||
if (s->Pek == NULL)
|
||||
{
|
||||
for (j = i; j <= p->Song.AntInstrs; ++j) FreeInstr(p, j);
|
||||
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)
|
||||
Delta2Samp(p->Instr[i]->Samp[j - 1].Pek, l, p->Instr[i]->Samp[j - 1].Typ);
|
||||
Delta2Samp(s->Pek, l, s->Typ);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
uint16_t i;
|
||||
|
@ -2491,12 +2492,12 @@ static int8_t PatternEmpty(PLAYER *p, uint16_t nr)
|
|||
|
||||
static int8_t LoadPatterns(PLAYER *p, MEM *f)
|
||||
{
|
||||
PatternHeaderTyp ph;
|
||||
uint8_t *patttmp;
|
||||
|
||||
uint16_t i;
|
||||
uint8_t tmpLen;
|
||||
|
||||
PatternHeaderTyp ph;
|
||||
|
||||
for (i = 0; i < p->Song.AntPtn; ++i)
|
||||
{
|
||||
mread(&ph.PatternHeaderSize, 4, 1, f);
|
||||
|
@ -2522,6 +2523,7 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f)
|
|||
|
||||
if (meof(f))
|
||||
{
|
||||
mclose(f);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -2531,12 +2533,14 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f)
|
|||
p->Patt[i] = (TonTyp *)(calloc(sizeof (TonTyp), ph.PattLen * 127));
|
||||
if (p->Patt[i] == NULL)
|
||||
{
|
||||
mclose(f);
|
||||
return (0);
|
||||
}
|
||||
|
||||
patttmp = (uint8_t *)(malloc(ph.DataLen));
|
||||
if (patttmp == NULL)
|
||||
{
|
||||
mclose(f);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -2547,9 +2551,12 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f)
|
|||
|
||||
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->PattLens[i] = 64;
|
||||
}
|
||||
}
|
||||
|
@ -2557,10 +2564,8 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f)
|
|||
return (1);
|
||||
}
|
||||
|
||||
static void ft2play_FreeSong(void *_p)
|
||||
static void ft2play_FreeSong(PLAYER *p)
|
||||
{
|
||||
PLAYER * p = (PLAYER *)_p;
|
||||
|
||||
p->Playing = 0;
|
||||
|
||||
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;
|
||||
|
||||
AllocateInstr(p, 0); // instr0 = placeholder for invalid ins
|
||||
p->Instr[0]->Samp[0].Vol = 0; // mute invalid instruments
|
||||
// instr 0 is a placeholder for invalid instruments
|
||||
AllocateInstr(p, 0);
|
||||
p->Instr[0]->Samp[0].Vol = 0;
|
||||
// ------------------------------------------------
|
||||
|
||||
FreeMusic(p);
|
||||
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);
|
||||
|
||||
// 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 > 0x0104))
|
||||
if ((memcmp(h.Sig, "Extended Module: ", 17) != 0) || (h.Ver < 0x0102) || (h.Ver > 0x104))
|
||||
{
|
||||
mclose(f);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((h.AntChn < 1) || (h.AntChn > 127) || (h.AntPtn > 256))
|
||||
{
|
||||
mclose(f);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -2614,16 +2622,16 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*memcpy(p->Song.Name, h.Name, 20);
|
||||
memcpy(p->Song.ProgName, h.ProggName, 20);*/
|
||||
memcpy(p->Song.Name, h.Name, 20);
|
||||
memcpy(p->Song.ProgName, h.ProggName, 20);
|
||||
|
||||
p->Song.Len = h.Len;
|
||||
p->Song.RepS = h.RepS;
|
||||
p->Song.AntChn = (uint8_t)(h.AntChn);
|
||||
p->Song.InitSpeed = h.DefSpeed ? h.DefSpeed : 125;
|
||||
p->Song.Speed = p->Song.InitSpeed;
|
||||
p->Song.InitTempo = h.DefTempo ? h.DefTempo : 6;
|
||||
p->Song.Tempo = p->Song.InitTempo;
|
||||
p->Song.Speed = h.DefSpeed ? h.DefSpeed : 125;
|
||||
p->Song.Tempo = h.DefTempo ? h.DefTempo : 6;
|
||||
p->Song.InitSpeed = p->Song.Speed;
|
||||
p->Song.InitTempo = p->Song.Tempo;
|
||||
p->Song.AntInstrs = h.AntInstrs;
|
||||
p->Song.AntPtn = h.AntPtn;
|
||||
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)
|
||||
{
|
||||
FreeInstr(p, i);
|
||||
FreeInstr(p, (uint8_t)(i));
|
||||
mclose(f);
|
||||
f = NULL;
|
||||
break;
|
||||
|
@ -2704,7 +2712,22 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size)
|
|||
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 sampleLoopEnd, int8_t loopEnabled,
|
||||
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].stereo = stereo;
|
||||
p->voice[i].interpolating = 1;
|
||||
#ifdef USE_VOL_RAMP
|
||||
p->voice[i].rampTerminates = 0;
|
||||
#endif
|
||||
|
||||
resampler_clear(p->resampler[i]);
|
||||
#ifdef USE_VOL_RAMP
|
||||
|
@ -2745,7 +2765,7 @@ void voiceSetSource(PLAYER *p, uint8_t i, const int8_t *sampleData,
|
|||
#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;
|
||||
if (p->voice[i].samplePosition >= p->voice[i].sampleLength)
|
||||
|
@ -2764,7 +2784,7 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t i, uint16_t value)
|
|||
#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
|
||||
if (p->rampStyle > 0 && !sharp)
|
||||
|
@ -2778,15 +2798,13 @@ void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t sharp)
|
|||
if (sharp)
|
||||
{
|
||||
if (vol)
|
||||
{
|
||||
p->voice[i].volume = 0.0f;
|
||||
}
|
||||
p->voice[i].volume = 0;
|
||||
else if (sharp != 3)
|
||||
p->voice[i].rampTerminates = 1;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -2795,11 +2813,11 @@ void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t sharp)
|
|||
p->voice[i].volDelta = 0;
|
||||
}
|
||||
#else
|
||||
p->voice[i].volume = vol;
|
||||
voice[i].volume = vol;
|
||||
#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
|
||||
if (p->rampStyle > 1)
|
||||
|
@ -2820,12 +2838,12 @@ void voiceSetPanning(PLAYER *p, uint8_t i, uint8_t pan)
|
|||
p->voice[i].panDeltaR = 0;
|
||||
}
|
||||
#else
|
||||
voice[i].panningL = p->PanningTab[256 - pan];
|
||||
voice[i].panningR = p->PanningTab[ pan];
|
||||
voice[i].panningL = PanningTab[256 - pan];
|
||||
voice[i].panningR = PanningTab[ pan];
|
||||
#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;
|
||||
}
|
||||
|
@ -2871,11 +2889,10 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
|
|||
|
||||
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)
|
||||
{
|
||||
p->voice[ch].busy = 1;
|
||||
samplePosition = p->voice[ch].samplePosition;
|
||||
|
||||
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) )
|
||||
{
|
||||
p->voice[ch].sampleData = NULL;
|
||||
p->voice[ch].busy = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
sample = resampler_get_sample(resampler);
|
||||
resampler_remove_sample(resampler);
|
||||
|
||||
sample = (sample * p->voice[ch].volume);
|
||||
sample *= p->voice[ch].volume;
|
||||
|
||||
sampleL = (sample * p->voice[ch].panningL);
|
||||
sampleR = (sample * p->voice[ch].panningR);
|
||||
sampleL = sample * p->voice[ch].panningL;
|
||||
sampleR = sample * p->voice[ch].panningR;
|
||||
|
||||
#ifdef USE_VOL_RAMP
|
||||
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)
|
||||
{
|
||||
p->voice[ch].sampleData = NULL;
|
||||
p->voice[ch].samplePosition = 0;
|
||||
p->voice[ch].busy = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3040,12 +3052,11 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
|
|||
resampler[1] = p->resampler[ch+127];
|
||||
#endif
|
||||
|
||||
resampler_set_rate(resampler[0], p->voice[ch].incRate );
|
||||
resampler_set_rate(resampler[1], p->voice[ch].incRate );
|
||||
resampler_set_rate(resampler[0], p->voice[ch].incRate);
|
||||
resampler_set_rate(resampler[1], p->voice[ch].incRate);
|
||||
|
||||
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
|
||||
{
|
||||
p->voice[ch].busy = 1;
|
||||
samplePosition = p->voice[ch].samplePosition;
|
||||
|
||||
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]) )
|
||||
{
|
||||
p->voice[ch].sampleData = NULL;
|
||||
p->voice[ch].busy = 0;
|
||||
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[1]);
|
||||
|
||||
sampleL = (sampleL * p->voice[ch].volume);
|
||||
sampleR = (sampleR * p->voice[ch].volume);
|
||||
sampleL *= p->voice[ch].volume;
|
||||
sampleR *= p->voice[ch].volume;
|
||||
|
||||
sampleL = (sampleL * p->voice[ch].panningL);
|
||||
sampleR = (sampleR * p->voice[ch].panningR);
|
||||
sampleL *= p->voice[ch].panningL;
|
||||
sampleR *= p->voice[ch].panningR;
|
||||
|
||||
#ifdef USE_VOL_RAMP
|
||||
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)
|
||||
{
|
||||
p->voice[ch].sampleData = NULL;
|
||||
p->voice[ch].samplePosition = 0;
|
||||
p->voice[ch].busy = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3206,15 +3212,14 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples)
|
|||
loopDir = p->voice[ch].loopDir;
|
||||
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_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)
|
||||
{
|
||||
p->voice[ch].busy = 1;
|
||||
samplePosition = p->voice[ch].samplePosition;
|
||||
|
||||
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) )
|
||||
{
|
||||
p->voice[ch].sampleData = NULL;
|
||||
p->voice[ch].busy = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
sample = resampler_get_sample(resampler);
|
||||
resampler_remove_sample(resampler);
|
||||
|
||||
sample = (sample * p->voice[ch].volume);
|
||||
sample *= p->voice[ch].volume;
|
||||
|
||||
sampleL = (sample * p->voice[ch].panningL);
|
||||
sampleR = (sample * p->voice[ch].panningR);
|
||||
sampleL = sample * p->voice[ch].panningL;
|
||||
sampleR = sample * p->voice[ch].panningR;
|
||||
|
||||
#ifdef USE_VOL_RAMP
|
||||
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)
|
||||
{
|
||||
p->voice[ch].sampleData = NULL;
|
||||
p->voice[ch].samplePosition = 0;
|
||||
p->voice[ch].busy = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3370,7 +3370,7 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
|
|||
loopDir = p->voice[ch].loopDir;
|
||||
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];
|
||||
#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];
|
||||
#endif
|
||||
|
||||
resampler_set_rate(resampler[0], p->voice[ch].incRate );
|
||||
resampler_set_rate(resampler[1], p->voice[ch].incRate );
|
||||
resampler_set_rate(resampler[0], p->voice[ch].incRate);
|
||||
resampler_set_rate(resampler[1], p->voice[ch].incRate);
|
||||
|
||||
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
|
||||
{
|
||||
p->voice[ch].busy = 1;
|
||||
samplePosition = p->voice[ch].samplePosition;
|
||||
|
||||
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]) )
|
||||
{
|
||||
p->voice[ch].sampleData = NULL;
|
||||
p->voice[ch].busy = 0;
|
||||
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[1]);
|
||||
|
||||
sampleL = (sampleL * p->voice[ch].volume);
|
||||
sampleR = (sampleR * p->voice[ch].volume);
|
||||
sampleL *= p->voice[ch].volume;
|
||||
sampleR *= p->voice[ch].volume;
|
||||
|
||||
sampleL = (sampleL * p->voice[ch].panningL);
|
||||
sampleR = (sampleR * p->voice[ch].panningR);
|
||||
sampleL *= p->voice[ch].panningL;
|
||||
sampleR *= p->voice[ch].panningR;
|
||||
|
||||
#ifdef USE_VOL_RAMP
|
||||
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)
|
||||
{
|
||||
p->voice[ch].sampleData = NULL;
|
||||
p->voice[ch].samplePosition = 0;
|
||||
p->voice[ch].busy = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3569,7 +3563,7 @@ void ft2play_RenderFloat(void *_p, float *buffer, int32_t count)
|
|||
int32_t samplesTodo;
|
||||
float * outputStream;
|
||||
|
||||
if (p->isMixing)
|
||||
if (p->Playing)
|
||||
{
|
||||
outputStream = buffer;
|
||||
|
||||
|
@ -3664,13 +3658,13 @@ void * ft2play_Alloc(uint32_t _samplingFrequency, int8_t interpolation, int8_t r
|
|||
if ( !p->masterBufferL || !p->masterBufferR )
|
||||
goto error;
|
||||
|
||||
p->samplingInterpolation = interpolation;
|
||||
setSamplingInterpolation(p, interpolation);
|
||||
|
||||
#ifdef USE_VOL_RAMP
|
||||
p->rampStyle = ramp_style;
|
||||
#endif
|
||||
|
||||
resampler_init();
|
||||
|
||||
#ifdef USE_VOL_RAMP
|
||||
for ( i = 0; i < 127 * 2 * 2; ++i )
|
||||
#else
|
||||
|
@ -3753,10 +3747,8 @@ void ft2play_Free(void *_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->masterBufferR) free(p->masterBufferR); p->masterBufferR = NULL;
|
||||
}
|
||||
|
@ -3799,7 +3791,6 @@ void ft2play_PlaySong(void *_p, int32_t startOrder)
|
|||
p->Playing = 1;
|
||||
|
||||
setSamplesPerFrame(p, ((p->outputFreq * 5UL) / 2 / p->Song.Speed));
|
||||
p->isMixing = 1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static MEM *mopen(const uint8_t *src, uintptr_t length)
|
||||
static MEM *mopen(const uint8_t *src, size_t length)
|
||||
{
|
||||
MEM *b;
|
||||
|
||||
|
@ -3831,23 +3822,13 @@ static MEM *mopen(const uint8_t *src, uintptr_t length)
|
|||
static void mclose(MEM *buf)
|
||||
{
|
||||
if (buf != NULL)
|
||||
{
|
||||
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)
|
||||
{
|
||||
size_t wrcnt;
|
||||
intptr_t pcnt;
|
||||
ssize_t pcnt;
|
||||
|
||||
if (buf == 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;
|
||||
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);
|
||||
|
||||
buf->_cnt -= pcnt;
|
||||
|
@ -3871,35 +3852,6 @@ static size_t mread(void *buffer, size_t size, size_t count, MEM *buf)
|
|||
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)
|
||||
{
|
||||
if (buf == NULL) return (1); // XXX: Should return a different value?
|
||||
|
@ -3907,7 +3859,7 @@ static int32_t meof(MEM *buf)
|
|||
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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
PLAYER * p = (PLAYER *)_p;
|
||||
|
@ -3970,11 +3912,11 @@ void ft2play_GetInfo(void *_p, ft2_info *info)
|
|||
info->speed = p->Song.Tempo; // Hurr
|
||||
info->tempo = p->Song.Speed;
|
||||
channels_playing = 0;
|
||||
if (p->isMixing)
|
||||
if (p->Playing)
|
||||
{
|
||||
for (i = 0; i < p->Song.AntChn; ++i)
|
||||
{
|
||||
if (p->voice[i].busy)
|
||||
if (p->voice[i].sampleData)
|
||||
++channels_playing;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue