Re-ported ft2play from original sources
This commit is contained in:
parent
0b436c8437
commit
00a014f270
1 changed files with 3926 additions and 3984 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue