Updated FT2Play to version 0.79.
parent
085bbf7650
commit
2f9eb42e24
|
@ -1,9 +1,16 @@
|
||||||
/*
|
/*
|
||||||
** FT2PLAY v0.78 - 29th of July 2017
|
** FT2PLAY v0.79 - 14th of September 2017
|
||||||
** =================================
|
** =====================================
|
||||||
**
|
**
|
||||||
** modplay version for foo_dumb.dll (foobar2000)
|
** modplay version for foo_dumb.dll (foobar2000)
|
||||||
**
|
**
|
||||||
|
** Changelog from v0.78:
|
||||||
|
** - RelocateTon() had unneeded logic in it
|
||||||
|
** - Fixed behavior of quirky vol/pan envelopes (like FT2 now)
|
||||||
|
** - Volume ramp is now changed to behave like in FT2
|
||||||
|
** - Added a quirk simulation on <0 (pan slide left 0)
|
||||||
|
** - Fixed Pxy (panning slide) bug
|
||||||
|
**
|
||||||
** Changelog from v0.77
|
** Changelog from v0.77
|
||||||
** - Instr. mute flag should be tested as !=1, not !mute (fixed malicious xm)
|
** - Instr. mute flag should be tested as !=1, not !mute (fixed malicious xm)
|
||||||
**
|
**
|
||||||
|
@ -29,7 +36,7 @@
|
||||||
** of Triton.
|
** of Triton.
|
||||||
**
|
**
|
||||||
** Thanks to aciddose (and kode54) for coding the vol/sample ramp.
|
** Thanks to aciddose (and kode54) for coding the vol/sample ramp.
|
||||||
** The volume ramp is tune to that of FT2 (5ms).
|
** The volume ramp is tune to that of FT2.
|
||||||
**
|
**
|
||||||
** (extreme) non-FT2 extensions:
|
** (extreme) non-FT2 extensions:
|
||||||
** - Max 127 channels (was 32)
|
** - Max 127 channels (was 32)
|
||||||
|
@ -49,11 +56,8 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#include "resampler.h"
|
#include "resampler.h"
|
||||||
|
|
||||||
#include "barray.h"
|
#include "barray.h"
|
||||||
|
|
||||||
#include "ft2play.h"
|
#include "ft2play.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(inline)
|
#if defined(_MSC_VER) && !defined(inline)
|
||||||
|
@ -67,15 +71,15 @@ typedef signed long ssize_t;
|
||||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
#define USE_VOL_RAMP
|
#define USE_VOL_RAMP
|
||||||
|
#define _soundBufferSize 512
|
||||||
enum { _soundBufferSize = 512 };
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
IS_Vol = 1,
|
IS_Vol = 1,
|
||||||
IS_Period = 2,
|
IS_Period = 2,
|
||||||
IS_NyTon = 4,
|
IS_NyTon = 4,
|
||||||
IS_Pan = 8
|
IS_Pan = 8,
|
||||||
|
IS_QuickVol = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -263,13 +267,13 @@ typedef struct StmTyp_t
|
||||||
int8_t RealVol; /* must be signed */
|
int8_t RealVol; /* must be signed */
|
||||||
int8_t RelTonNr; /* must be signed */
|
int8_t RelTonNr; /* must be signed */
|
||||||
int8_t FineTune; /* must be signed */
|
int8_t FineTune; /* must be signed */
|
||||||
int16_t OutPan; /* must be signed */
|
|
||||||
int16_t RealPeriod; /* must be signed */
|
int16_t RealPeriod; /* must be signed */
|
||||||
int32_t FadeOutAmp; /* must be signed */
|
int32_t FadeOutAmp; /* must be signed */
|
||||||
int16_t EnvVIPValue; /* must be signed */
|
int16_t EnvVIPValue; /* must be signed */
|
||||||
int16_t EnvPIPValue; /* must be signed */
|
int16_t EnvPIPValue; /* must be signed */
|
||||||
uint8_t OldVol;
|
uint8_t OldVol;
|
||||||
uint8_t OldPan;
|
uint8_t OldPan;
|
||||||
|
uint8_t OutPan;
|
||||||
uint16_t OutPeriod;
|
uint16_t OutPeriod;
|
||||||
uint8_t FinalPan;
|
uint8_t FinalPan;
|
||||||
uint16_t FinalPeriod;
|
uint16_t FinalPeriod;
|
||||||
|
@ -353,7 +357,6 @@ typedef struct
|
||||||
float incRate;
|
float incRate;
|
||||||
float volumeL;
|
float volumeL;
|
||||||
float volumeR;
|
float volumeR;
|
||||||
|
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
float targetVolL;
|
float targetVolL;
|
||||||
float targetVolR;
|
float targetVolR;
|
||||||
|
@ -417,17 +420,16 @@ typedef struct
|
||||||
float f_outputFreq;
|
float f_outputFreq;
|
||||||
|
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
float f_samplesPerFrame005;
|
float quickVolRampMul_f;
|
||||||
float f_samplesPerFrame010;
|
float tickVolRampMul_f;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* pre-initialized variables */
|
int8_t samplingInterpolation;
|
||||||
int8_t samplingInterpolation;/* = 1; */
|
|
||||||
int8_t rampStyle;
|
int8_t rampStyle;
|
||||||
float *masterBufferL;/* = NULL; */
|
float *masterBufferL;
|
||||||
float *masterBufferR;/* = NULL; */
|
float *masterBufferR;
|
||||||
int32_t samplesLeft;/* = 0; must be signed */
|
int32_t samplesLeft;
|
||||||
uint32_t samplesPerFrame;/* = 882; */
|
uint32_t samplesPerFrame;
|
||||||
|
|
||||||
/* globally accessed */
|
/* globally accessed */
|
||||||
int8_t ModuleLoaded;/* = 0; */
|
int8_t ModuleLoaded;/* = 0; */
|
||||||
|
@ -456,7 +458,7 @@ static void voiceSetSource(PLAYER *, uint8_t i, const int8_t *sampleData,
|
||||||
int32_t sampleLoopEnd, int8_t loopEnabled,
|
int32_t sampleLoopEnd, int8_t loopEnabled,
|
||||||
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 pan, uint8_t note_on);
|
static void voiceSetVolume(PLAYER *, uint8_t i, float vol, uint8_t pan, uint8_t status);
|
||||||
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 *);
|
static void ft2play_FreeSong(PLAYER *);
|
||||||
|
|
||||||
|
@ -499,7 +501,7 @@ static inline void RetrigVolume(StmTyp *ch)
|
||||||
ch->RealVol = ch->OldVol;
|
ch->RealVol = ch->OldVol;
|
||||||
ch->OutVol = ch->OldVol;
|
ch->OutVol = ch->OldVol;
|
||||||
ch->OutPan = ch->OldPan;
|
ch->OutPan = ch->OldPan;
|
||||||
ch->Status |= (IS_Vol + IS_Pan);
|
ch->Status |= (IS_Vol + IS_Pan + IS_QuickVol);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RetrigEnvelopeVibrato(StmTyp *ch)
|
static void RetrigEnvelopeVibrato(StmTyp *ch)
|
||||||
|
@ -514,25 +516,24 @@ static void RetrigEnvelopeVibrato(StmTyp *ch)
|
||||||
|
|
||||||
if (ch->InstrSeg.EnvVTyp & 1)
|
if (ch->InstrSeg.EnvVTyp & 1)
|
||||||
{
|
{
|
||||||
ch->EnvVCnt = 0xFFFF;
|
ch->EnvVCnt = 65535;
|
||||||
ch->EnvVPos = 0;
|
ch->EnvVPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch->InstrSeg.EnvPTyp & 1)
|
if (ch->InstrSeg.EnvPTyp & 1)
|
||||||
{
|
{
|
||||||
ch->EnvPCnt = 0xFFFF;
|
ch->EnvPCnt = 65535;
|
||||||
ch->EnvPPos = 0;
|
ch->EnvPPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FT2 doesn't check if fadeout is more than 32768 */
|
ch->FadeOutSpeed = ch->InstrSeg.FadeOut; /* FT2 doesn't check if fadeout is more than 4095 */
|
||||||
ch->FadeOutSpeed = ch->InstrSeg.FadeOut;
|
|
||||||
ch->FadeOutAmp = 32768;
|
ch->FadeOutAmp = 32768;
|
||||||
|
|
||||||
if (ch->InstrSeg.VibDepth)
|
if (ch->InstrSeg.VibDepth != 0)
|
||||||
{
|
{
|
||||||
ch->EVibPos = 0;
|
ch->EVibPos = 0;
|
||||||
|
|
||||||
if (ch->InstrSeg.VibSweep)
|
if (ch->InstrSeg.VibSweep != 0)
|
||||||
{
|
{
|
||||||
ch->EVibAmp = 0;
|
ch->EVibAmp = 0;
|
||||||
ch->EVibSweep = ((uint16_t)(ch->InstrSeg.VibDepth) << 8) / ch->InstrSeg.VibSweep;
|
ch->EVibSweep = ((uint16_t)(ch->InstrSeg.VibDepth) << 8) / ch->InstrSeg.VibSweep;
|
||||||
|
@ -564,7 +565,7 @@ static void KeyOff(StmTyp *ch)
|
||||||
{
|
{
|
||||||
ch->RealVol = 0;
|
ch->RealVol = 0;
|
||||||
ch->OutVol = 0;
|
ch->OutVol = 0;
|
||||||
ch->Status |= IS_Vol;
|
ch->Status |= (IS_Vol + IS_QuickVol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,7 +660,7 @@ static void StartTone(PLAYER *p, uint8_t Ton, uint8_t EffTyp, uint8_t Eff, StmTy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ch->Status |= (IS_Period + IS_Vol + IS_Pan + IS_NyTon);
|
ch->Status |= (IS_Period + IS_Vol + IS_Pan + IS_NyTon + IS_QuickVol);
|
||||||
|
|
||||||
if (EffTyp == 9)
|
if (EffTyp == 9)
|
||||||
{
|
{
|
||||||
|
@ -747,7 +748,7 @@ static void CheckEffects(PLAYER *p, StmTyp *ch)
|
||||||
ch->OutVol = ch->VolKolVol - 0x10;
|
ch->OutVol = ch->VolKolVol - 0x10;
|
||||||
ch->RealVol = ch->OutVol;
|
ch->RealVol = ch->OutVol;
|
||||||
|
|
||||||
ch->Status |= IS_Vol;
|
ch->Status |= (IS_Vol + IS_QuickVol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fine volume slide down */
|
/* fine volume slide down */
|
||||||
|
@ -810,7 +811,7 @@ static void CheckEffects(PLAYER *p, StmTyp *ch)
|
||||||
if (ch->RealVol > 64) ch->RealVol = 64;
|
if (ch->RealVol > 64) ch->RealVol = 64;
|
||||||
|
|
||||||
ch->OutVol = ch->RealVol;
|
ch->OutVol = ch->RealVol;
|
||||||
ch->Status |= IS_Vol;
|
ch->Status |= (IS_Vol + IS_QuickVol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dxx - pattern break
|
// Dxx - pattern break
|
||||||
|
@ -970,7 +971,7 @@ static void CheckEffects(PLAYER *p, StmTyp *ch)
|
||||||
if (ch->Eff >= 32)
|
if (ch->Eff >= 32)
|
||||||
{
|
{
|
||||||
p->Song.Speed = ch->Eff;
|
p->Song.Speed = ch->Eff;
|
||||||
setSamplesPerFrame(p, (p->outputFreq * 5UL) / 2 / p->Song.Speed);
|
setSamplesPerFrame(p, ((p->outputFreq * 5) / 2) / p->Song.Speed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -985,7 +986,7 @@ static void CheckEffects(PLAYER *p, StmTyp *ch)
|
||||||
|
|
||||||
p->Song.PBreakPos = 0;
|
p->Song.PBreakPos = 0;
|
||||||
p->Song.PosJumpFlag = 1;
|
p->Song.PosJumpFlag = 1;
|
||||||
p->Song.SongPos = p->Song.startOrder-1;
|
p->Song.SongPos = p->Song.startOrder - 1;
|
||||||
p->Song.Timer = 1;
|
p->Song.Timer = 1;
|
||||||
p->Song.Speed = p->Song.InitSpeed;
|
p->Song.Speed = p->Song.InitSpeed;
|
||||||
p->Song.Tempo = p->Song.InitTempo;
|
p->Song.Tempo = p->Song.InitTempo;
|
||||||
|
@ -1191,7 +1192,6 @@ static void CheckEffects(PLAYER *p, StmTyp *ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't inline this */
|
|
||||||
static void fixTonePorta(PLAYER *pl, StmTyp *ch, TonTyp *p, uint8_t inst)
|
static void fixTonePorta(PLAYER *pl, StmTyp *ch, TonTyp *p, uint8_t inst)
|
||||||
{
|
{
|
||||||
uint16_t portaTmp;
|
uint16_t portaTmp;
|
||||||
|
@ -1347,27 +1347,25 @@ static inline void GetNewNote(PLAYER *pl, StmTyp *ch, TonTyp *p)
|
||||||
|
|
||||||
static void FixaEnvelopeVibrato(PLAYER *p, StmTyp *ch)
|
static void FixaEnvelopeVibrato(PLAYER *p, StmTyp *ch)
|
||||||
{
|
{
|
||||||
uint16_t envVal;
|
int8_t envInterpolateFlag, envDidInterpolate;
|
||||||
uint8_t envPos;
|
uint8_t envPos;
|
||||||
int8_t envInterpolateFlag;
|
int16_t autoVibVal, autoVibAmp, tmpPeriod, panTmp;
|
||||||
int8_t envDidInterpolate;
|
uint16_t envVal;
|
||||||
int16_t autoVibVal;
|
|
||||||
int16_t autoVibAmp;
|
|
||||||
int16_t tmpPeriod;
|
|
||||||
|
|
||||||
/* *** FADEOUT *** */
|
/* *** FADEOUT *** */
|
||||||
if (!ch->EnvSustainActive)
|
if (!ch->EnvSustainActive)
|
||||||
{
|
{
|
||||||
ch->Status |= IS_Vol;
|
ch->Status |= IS_Vol;
|
||||||
|
|
||||||
if (ch->FadeOutSpeed > 0)
|
/* unsigned clamp + reset */
|
||||||
|
if (ch->FadeOutAmp >= ch->FadeOutSpeed)
|
||||||
{
|
{
|
||||||
ch->FadeOutAmp -= ch->FadeOutSpeed;
|
ch->FadeOutAmp -= ch->FadeOutSpeed;
|
||||||
if (ch->FadeOutAmp <= 0)
|
}
|
||||||
{
|
else
|
||||||
ch->FadeOutAmp = 0;
|
{
|
||||||
ch->FadeOutSpeed = 0;
|
ch->FadeOutAmp = 0;
|
||||||
}
|
ch->FadeOutSpeed = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1421,6 +1419,7 @@ static void FixaEnvelopeVibrato(PLAYER *p, StmTyp *ch)
|
||||||
{
|
{
|
||||||
ch->EnvVPos = envPos;
|
ch->EnvVPos = envPos;
|
||||||
|
|
||||||
|
ch->EnvVIPValue = 0;
|
||||||
if (ch->InstrSeg.EnvVP[envPos][0] > ch->InstrSeg.EnvVP[envPos - 1][0])
|
if (ch->InstrSeg.EnvVP[envPos][0] > ch->InstrSeg.EnvVP[envPos - 1][0])
|
||||||
{
|
{
|
||||||
ch->EnvVIPValue = ((ch->InstrSeg.EnvVP[envPos][1] - ch->InstrSeg.EnvVP[envPos - 1][1]) & 0x00FF) << 8;
|
ch->EnvVIPValue = ((ch->InstrSeg.EnvVP[envPos][1] - ch->InstrSeg.EnvVP[envPos - 1][1]) & 0x00FF) << 8;
|
||||||
|
@ -1453,22 +1452,19 @@ static void FixaEnvelopeVibrato(PLAYER *p, StmTyp *ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ch->FinalVol = (float)(ch->OutVol) / 64.0f;
|
envVal >>= 8;
|
||||||
ch->FinalVol *= (float)(ch->FadeOutAmp) / 65536.0f;
|
|
||||||
ch->FinalVol *= (float)(envVal >> 8) / 64.0f;
|
ch->FinalVol = (p->Song.GlobVol * (1.0f / 64.0f)) * (envVal * (1.0f / 64.0f)) * (ch->OutVol * (1.0f / 64.0f)) * (ch->FadeOutAmp * (1.0f / 32768.0f));
|
||||||
ch->FinalVol *= (float)(p->Song.GlobVol) / 64.0f;
|
|
||||||
ch->Status |= IS_Vol;
|
ch->Status |= IS_Vol;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ch->FinalVol = (float)(ch->OutVol) / 64.0f;
|
ch->FinalVol = (p->Song.GlobVol * (1.0f / 64.0f)) * (ch->OutVol * (1.0f / 64.0f)) * (ch->FadeOutAmp * (1.0f / 32768.0f));
|
||||||
ch->FinalVol *= (float)(ch->FadeOutAmp) / 65536.0f;
|
|
||||||
ch->FinalVol *= (float)(p->Song.GlobVol) / 64.0f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ch->FinalVol = 0;
|
ch->FinalVol = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *** PANNING ENVELOPE *** */
|
/* *** PANNING ENVELOPE *** */
|
||||||
|
@ -1519,6 +1515,7 @@ static void FixaEnvelopeVibrato(PLAYER *p, StmTyp *ch)
|
||||||
{
|
{
|
||||||
ch->EnvPPos = envPos;
|
ch->EnvPPos = envPos;
|
||||||
|
|
||||||
|
ch->EnvPIPValue = 0;
|
||||||
if (ch->InstrSeg.EnvPP[envPos][0] > ch->InstrSeg.EnvPP[envPos - 1][0])
|
if (ch->InstrSeg.EnvPP[envPos][0] > ch->InstrSeg.EnvPP[envPos - 1][0])
|
||||||
{
|
{
|
||||||
ch->EnvPIPValue = ((ch->InstrSeg.EnvPP[envPos][1] - ch->InstrSeg.EnvPP[envPos - 1][1]) & 0x00FF) << 8;
|
ch->EnvPIPValue = ((ch->InstrSeg.EnvPP[envPos][1] - ch->InstrSeg.EnvPP[envPos - 1][1]) & 0x00FF) << 8;
|
||||||
|
@ -1551,19 +1548,27 @@ static void FixaEnvelopeVibrato(PLAYER *p, StmTyp *ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ch->FinalPan = (uint8_t)(ch->OutPan);
|
/* panning calculated exactly like FT2 */
|
||||||
ch->FinalPan += (uint8_t)((((envVal >> 8) - 32) * (128 - abs(ch->OutPan - 128)) / 32));
|
panTmp = ch->OutPan - 128;
|
||||||
ch->Status |= IS_Pan;
|
if (panTmp > 0)
|
||||||
|
panTmp = 0 - panTmp;
|
||||||
|
panTmp += 128;
|
||||||
|
|
||||||
|
envVal -= (32 * 256);
|
||||||
|
|
||||||
|
ch->FinalPan = ch->OutPan + (int8_t)((((int16_t)(envVal) * (panTmp << 3)) >> 16) & 0xFF);
|
||||||
|
|
||||||
|
ch->Status |= IS_Pan;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ch->FinalPan = (uint8_t)(ch->OutPan);
|
ch->FinalPan = ch->OutPan;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *** AUTO VIBRATO *** */
|
/* *** AUTO VIBRATO *** */
|
||||||
if (ch->InstrSeg.VibDepth)
|
if (ch->InstrSeg.VibDepth != 0)
|
||||||
{
|
{
|
||||||
if (ch->EVibSweep)
|
if (ch->EVibSweep != 0)
|
||||||
{
|
{
|
||||||
autoVibAmp = ch->EVibSweep;
|
autoVibAmp = ch->EVibSweep;
|
||||||
if (ch->EnvSustainActive)
|
if (ch->EnvSustainActive)
|
||||||
|
@ -1615,69 +1620,37 @@ static void FixaEnvelopeVibrato(PLAYER *p, StmTyp *ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16_t RelocateTon(PLAYER *p, int16_t inPeriod, int8_t addNote, StmTyp *ch)
|
static int16_t RelocateTon(PLAYER *p, int16_t period, int8_t relativeNote, StmTyp *ch)
|
||||||
{
|
{
|
||||||
// This *should* be more accurate now, but slower. Stupid routine!
|
int8_t i, fineTune;
|
||||||
|
int32_t loPeriod, hiPeriod, tmpPeriod, tableIndex;
|
||||||
|
|
||||||
int8_t i;
|
fineTune = (ch->FineTune >> 3) + 16; /* MUST use >> 3 here (sar cl,3) - safe for x86/x86_64 */
|
||||||
int8_t fineTune;
|
hiPeriod = 8 * 12 * 16;
|
||||||
|
loPeriod = 0;
|
||||||
int16_t oldPeriod;
|
|
||||||
int16_t addPeriod;
|
|
||||||
|
|
||||||
int32_t outPeriod;
|
|
||||||
|
|
||||||
oldPeriod = 0;
|
|
||||||
addPeriod = (8 * 12 * 16) * 2;
|
|
||||||
|
|
||||||
// safe signed 8-bit >>3 (FT2 exact even on non-x86 platforms)
|
|
||||||
if (ch->FineTune >= 0)
|
|
||||||
fineTune = ch->FineTune / (1 << 3);
|
|
||||||
else
|
|
||||||
fineTune = 0xE0 | ((uint8_t)(ch->FineTune) >> 3); /* 0xE0 = 2^8 - 2^(8-3) */
|
|
||||||
|
|
||||||
fineTune += 16;
|
|
||||||
fineTune += fineTune;
|
|
||||||
|
|
||||||
for (i = 0; i < 8; ++i)
|
for (i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
outPeriod = (((oldPeriod + addPeriod) >> 1) & 0xFFE0) + fineTune;
|
tmpPeriod = (((loPeriod + hiPeriod) / 2) & ~15) + fineTune;
|
||||||
if (outPeriod < fineTune)
|
|
||||||
outPeriod += (1 << 8);
|
|
||||||
|
|
||||||
if (outPeriod < 16)
|
tableIndex = tmpPeriod - 8;
|
||||||
outPeriod = 16;
|
if (tableIndex < 0) /* added security check */
|
||||||
|
tableIndex = 0;
|
||||||
|
|
||||||
if (inPeriod >= p->Note2Period[(outPeriod - 16) >> 1])
|
if (period >= p->Note2Period[tableIndex])
|
||||||
{
|
hiPeriod = tmpPeriod - fineTune;
|
||||||
outPeriod -= fineTune;
|
|
||||||
if (outPeriod & 0x00010000)
|
|
||||||
outPeriod = (outPeriod - (1 << 8)) & 0x0000FFE0;
|
|
||||||
|
|
||||||
addPeriod = (int16_t)(outPeriod);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
loPeriod = tmpPeriod - fineTune;
|
||||||
outPeriod -= fineTune;
|
|
||||||
if (outPeriod & 0x00010000)
|
|
||||||
outPeriod = (outPeriod - (1 << 8)) & 0x0000FFE0;
|
|
||||||
|
|
||||||
oldPeriod = (int16_t)(outPeriod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outPeriod = oldPeriod + fineTune;
|
tmpPeriod = loPeriod + fineTune + (relativeNote * 16);
|
||||||
if (outPeriod < fineTune)
|
if (tmpPeriod < 0) /* added security check */
|
||||||
outPeriod += (1 << 8);
|
tmpPeriod = 0;
|
||||||
|
|
||||||
if (outPeriod < 0)
|
if (tmpPeriod >= ((8 * 12 * 16) + 15) - 1) /* FT2 bug: stupid off-by-one edge case */
|
||||||
outPeriod = 0;
|
tmpPeriod = (8 * 12 * 16) + 15;
|
||||||
|
|
||||||
outPeriod += ((int16_t)(addNote) << 5);
|
return (p->Note2Period[tmpPeriod]);
|
||||||
if (outPeriod >= ((((8 * 12 * 16) + 15) * 2) - 1))
|
|
||||||
outPeriod = ((8 * 12 * 16) + 15) * 2;
|
|
||||||
|
|
||||||
return (p->Note2Period[outPeriod >> 1]); // 16-bit look-up, shift it down
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TonePorta(PLAYER *p, StmTyp *ch)
|
static void TonePorta(PLAYER *p, StmTyp *ch)
|
||||||
|
@ -1825,8 +1798,11 @@ static inline void DoEffects(PLAYER *p, StmTyp *ch)
|
||||||
/* pan slide left */
|
/* pan slide left */
|
||||||
else if ((ch->VolKolVol & 0xF0) == 0xD0)
|
else if ((ch->VolKolVol & 0xF0) == 0xD0)
|
||||||
{
|
{
|
||||||
ch->OutPan -= (ch->VolKolVol & 0x0F);
|
/* unsigned clamp + a bug when the parameter is 0 */
|
||||||
if (ch->OutPan < 0) ch->OutPan = 0;
|
if (((ch->VolKolVol & 0x0F) == 0) || (ch->OutPan < (ch->VolKolVol & 0x0F)))
|
||||||
|
ch->OutPan = 0;
|
||||||
|
else
|
||||||
|
ch->OutPan -= (ch->VolKolVol & 0x0F);
|
||||||
|
|
||||||
ch->Status |= IS_Pan;
|
ch->Status |= IS_Pan;
|
||||||
}
|
}
|
||||||
|
@ -2000,7 +1976,7 @@ static inline void DoEffects(PLAYER *p, StmTyp *ch)
|
||||||
{
|
{
|
||||||
ch->OutVol = 0;
|
ch->OutVol = 0;
|
||||||
ch->RealVol = 0;
|
ch->RealVol = 0;
|
||||||
ch->Status |= IS_Vol;
|
ch->Status |= (IS_Vol + IS_QuickVol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2067,15 +2043,23 @@ static inline void DoEffects(PLAYER *p, StmTyp *ch)
|
||||||
|
|
||||||
ch->PanningSlideSpeed = tmpEff;
|
ch->PanningSlideSpeed = tmpEff;
|
||||||
|
|
||||||
if (!(ch->Eff & 0xF0))
|
if ((tmpEff & 0xF0) == 0)
|
||||||
{
|
{
|
||||||
ch->OutPan += (ch->Eff >> 4);
|
/* unsigned clamp */
|
||||||
if (ch->OutPan > 255) ch->OutPan = 255;
|
if (ch->OutPan >= tmpEff)
|
||||||
|
ch->OutPan -= tmpEff;
|
||||||
|
else
|
||||||
|
ch->OutPan = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ch->OutPan -= (ch->Eff & 0x0F);
|
tmpEff >>= 4;
|
||||||
if (ch->OutPan < 0) ch->OutPan = 0;
|
|
||||||
|
/* unsigned clamp */
|
||||||
|
if (ch->OutPan <= (255 - tmpEff))
|
||||||
|
ch->OutPan += tmpEff;
|
||||||
|
else
|
||||||
|
ch->OutPan = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
ch->Status |= IS_Pan;
|
ch->Status |= IS_Pan;
|
||||||
|
@ -2113,7 +2097,7 @@ static inline void DoEffects(PLAYER *p, StmTyp *ch)
|
||||||
ch->TremorPos = tremorData | tremorSign;
|
ch->TremorPos = tremorData | tremorSign;
|
||||||
|
|
||||||
ch->OutVol = tremorSign ? ch->RealVol : 0;
|
ch->OutVol = tremorSign ? ch->RealVol : 0;
|
||||||
ch->Status |= IS_Vol;
|
ch->Status |= (IS_Vol + IS_QuickVol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2257,7 +2241,7 @@ static void MainPlayer(PLAYER *p) /* periodically called from mixer */
|
||||||
|
|
||||||
p->voice[SPARE_OFFSET + ChNr].faderDest = 0.0f;
|
p->voice[SPARE_OFFSET + ChNr].faderDest = 0.0f;
|
||||||
p->voice[SPARE_OFFSET + ChNr].faderDelta =
|
p->voice[SPARE_OFFSET + ChNr].faderDelta =
|
||||||
(p->voice[SPARE_OFFSET + ChNr].faderDest - p->voice[SPARE_OFFSET + ChNr].fader) * p->f_samplesPerFrame010;
|
(p->voice[SPARE_OFFSET + ChNr].faderDest - p->voice[SPARE_OFFSET + ChNr].fader) * p->quickVolRampMul_f;
|
||||||
|
|
||||||
resampler_dup_inplace(p->resampler[SPARE_OFFSET + ChNr], p->resampler[ChNr]);
|
resampler_dup_inplace(p->resampler[SPARE_OFFSET + ChNr], p->resampler[ChNr]);
|
||||||
resampler_dup_inplace(p->resampler[TOTAL_VOICES + SPARE_OFFSET + ChNr], p->resampler[TOTAL_VOICES + ChNr]);
|
resampler_dup_inplace(p->resampler[TOTAL_VOICES + SPARE_OFFSET + ChNr], p->resampler[TOTAL_VOICES + ChNr]);
|
||||||
|
@ -2274,13 +2258,13 @@ static void MainPlayer(PLAYER *p) /* periodically called from mixer */
|
||||||
{
|
{
|
||||||
p->voice[ch->Nr].fader = 0.0f;
|
p->voice[ch->Nr].fader = 0.0f;
|
||||||
p->voice[ch->Nr].faderDest = 1.0f;
|
p->voice[ch->Nr].faderDest = 1.0f;
|
||||||
p->voice[ch->Nr].faderDelta = (p->voice[ch->Nr].faderDest - p->voice[ch->Nr].fader) * p->f_samplesPerFrame005;
|
p->voice[ch->Nr].faderDelta = (p->voice[ch->Nr].faderDest - p->voice[ch->Nr].fader) * p->quickVolRampMul_f;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch->Status & (IS_Vol|IS_Pan))
|
if (ch->Status & (IS_Vol | IS_Pan))
|
||||||
voiceSetVolume(p, ch->Nr, ch->FinalVol, ch->FinalPan, ch->Status & IS_NyTon);
|
voiceSetVolume(p, ch->Nr, ch->FinalVol, ch->FinalPan, ch->Status);
|
||||||
|
|
||||||
if (ch->Status & IS_Period)
|
if (ch->Status & IS_Period)
|
||||||
voiceSetSamplingFrequency(p, ch->Nr, GetFrequenceValue(p, ch->FinalPeriod));
|
voiceSetSamplingFrequency(p, ch->Nr, GetFrequenceValue(p, ch->FinalPeriod));
|
||||||
|
@ -2943,7 +2927,8 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size)
|
||||||
|
|
||||||
static void setSamplesPerFrame(PLAYER *p, uint32_t val)
|
static void setSamplesPerFrame(PLAYER *p, uint32_t val)
|
||||||
{
|
{
|
||||||
p->samplesPerFrame = val;
|
p->samplesPerFrame = val;
|
||||||
|
p->tickVolRampMul_f = 1.0f / val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setSamplingInterpolation(PLAYER *p, int8_t value)
|
static void setSamplingInterpolation(PLAYER *p, int8_t value)
|
||||||
|
@ -3001,18 +2986,23 @@ static inline void voiceSetSamplePosition(PLAYER *p, uint8_t i, uint16_t value)
|
||||||
v->interpolating = 1;
|
v->interpolating = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t pan, uint8_t note_on)
|
static inline void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t pan, uint8_t status)
|
||||||
{
|
{
|
||||||
|
float deltaMul_f;
|
||||||
VOICE *v;
|
VOICE *v;
|
||||||
|
|
||||||
v = &p->voice[i];
|
v = &p->voice[i];
|
||||||
|
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
if (!note_on && p->rampStyle > 1)
|
if (!(status & IS_NyTon) && (p->rampStyle > 1))
|
||||||
{
|
{
|
||||||
v->targetVolL = vol * p->PanningTab[256 - pan];
|
v->targetVolL = vol * p->PanningTab[256 - pan];
|
||||||
v->targetVolR = vol * p->PanningTab[pan];
|
v->targetVolR = vol * p->PanningTab[pan];
|
||||||
v->volDeltaL = (v->targetVolL - v->volumeL) * p->f_samplesPerFrame005;
|
|
||||||
v->volDeltaR = (v->targetVolR - v->volumeR) * p->f_samplesPerFrame005;
|
deltaMul_f = (status & IS_QuickVol) ? p->quickVolRampMul_f : p->tickVolRampMul_f;
|
||||||
|
|
||||||
|
v->volDeltaL = (v->targetVolL - v->volumeL) * deltaMul_f;
|
||||||
|
v->volDeltaR = (v->targetVolR - v->volumeR) * deltaMul_f;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3029,7 +3019,8 @@ static inline void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t pan,
|
||||||
|
|
||||||
static inline void voiceSetSamplingFrequency(PLAYER *p, uint8_t i, uint32_t samplingFrequency)
|
static inline void voiceSetSamplingFrequency(PLAYER *p, uint8_t i, uint32_t samplingFrequency)
|
||||||
{
|
{
|
||||||
p->voice[i].incRate = (float)(samplingFrequency) / p->f_outputFreq;
|
if (p->f_outputFreq > 0.0f)
|
||||||
|
p->voice[i].incRate = (float)(samplingFrequency) / p->f_outputFreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
|
static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
|
@ -3882,14 +3873,13 @@ void * ft2play_Alloc(uint32_t _samplingFrequency, int8_t interpolation, int8_t r
|
||||||
if ( !p )
|
if ( !p )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
p->samplesPerFrame = 882;
|
p->numChannels = MAX_VOICES;
|
||||||
p->numChannels = MAX_VOICES;
|
|
||||||
|
|
||||||
p->outputFreq = _samplingFrequency;
|
p->outputFreq = _samplingFrequency;
|
||||||
p->f_outputFreq = (float)(p->outputFreq);
|
p->f_outputFreq = (float)(p->outputFreq);
|
||||||
|
p->samplesPerFrame = ((p->outputFreq * 5) / 2) / 125;
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
p->f_samplesPerFrame010= 1.0f / (p->f_outputFreq * 0.010f);
|
p->tickVolRampMul_f = 1.0f / p->samplesPerFrame;
|
||||||
p->f_samplesPerFrame005= 1.0f / (p->f_outputFreq * 0.005f);
|
p->quickVolRampMul_f = 1.0f / (p->outputFreq / 200); // yes, truncate here
|
||||||
#endif
|
#endif
|
||||||
p->soundBufferSize = _soundBufferSize;
|
p->soundBufferSize = _soundBufferSize;
|
||||||
|
|
||||||
|
@ -4043,7 +4033,7 @@ void ft2play_PlaySong(void *_p, int32_t startOrder)
|
||||||
p->numChannels = p->Song.AntChn;
|
p->numChannels = p->Song.AntChn;
|
||||||
p->Playing = 1;
|
p->Playing = 1;
|
||||||
|
|
||||||
setSamplesPerFrame(p, ((p->outputFreq * 5UL) / 2 / p->Song.Speed));
|
setSamplesPerFrame(p, (((p->outputFreq * 5) / 2) / p->Song.Speed));
|
||||||
|
|
||||||
SetPos(p, (int16_t)startOrder, 0);
|
SetPos(p, (int16_t)startOrder, 0);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue