ref: 0f13e15d79d27124d3f1dbba1ea17d60a8b1b47d
dir: /src/ft2_replayer.h/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "ft2_unicode.h"
#include "mixer/ft2_cubic_spline.h"
#include "mixer/ft2_windowed_sinc.h"
enum
{
// voice flags
IS_Vol = 1, // set volume
IS_Period = 2, // set resampling rate
IS_Trigger = 4, // trigger sample
IS_Pan = 8, // set panning
IS_QuickVol = 16, // 5ms volramp instead of tick ms
LOOP_DISABLED = 0,
LOOP_FORWARD = 1,
LOOP_PINGPONG = 2,
// tracker playback modes
PLAYMODE_IDLE = 0,
PLAYMODE_EDIT = 1,
PLAYMODE_SONG = 2,
PLAYMODE_PATT = 3,
PLAYMODE_RECSONG = 4,
PLAYMODE_RECPATT = 5,
// note cursor positions
CURSOR_NOTE = 0,
CURSOR_INST1 = 1,
CURSOR_INST2 = 2,
CURSOR_VOL1 = 3,
CURSOR_VOL2 = 4,
CURSOR_EFX0 = 5,
CURSOR_EFX1 = 6,
CURSOR_EFX2 = 7
};
// do not touch these!
#define MIN_BPM 32
#define MAX_BPM 255
#define MAX_SPEED 31
#define MAX_CHANNELS 32
#define TRACK_WIDTH (5 * MAX_CHANNELS)
#define C4_FREQ 8363
#define NOTE_C4 (4*12)
#define NOTE_OFF 97
#define MAX_NOTES (10*12*16+16)
#define MAX_PATTERNS 256
#define MAX_PATT_LEN 256
#define MAX_INST 128
#define MAX_SMP_PER_INST 16
#define MAX_ORDERS 256
#define STD_ENV_SIZE ((6*2*12*2*2) + (6*8*2) + (6*5*2) + (6*2*2))
#define INSTR_HEADER_SIZE 263
#define INSTR_XI_HEADER_SIZE 298
#define MAX_SAMPLE_LEN 0x3FFFFFFF
#define FT2_QUICKRAMP_SAMPLES 200
#define PROG_NAME_STR "Fasttracker II clone"
enum // sample flags
{
LOOP_OFF = 0,
LOOP_FWD = 1,
LOOP_BIDI = 2,
SAMPLE_16BIT = 16,
SAMPLE_STEREO = 32,
SAMPLE_ADPCM = 64, // not an existing flag, but used by loader
};
enum // envelope flags
{
ENV_ENABLED = 1,
ENV_SUSTAIN = 2,
ENV_LOOP = 4
};
#define GET_LOOPTYPE(smpFlags) ((smpFlags) & (LOOP_FWD | LOOP_BIDI))
#define DISABLE_LOOP(smpFlags) ((smpFlags) &= ~(LOOP_FWD | LOOP_BIDI))
#define SAMPLE_LENGTH_BYTES(smp) (smp->length << !!(smp->flags & SAMPLE_16BIT))
#define FINETUNE_MOD2XM(f) (((uint8_t)(f) & 0x0F) << 4)
#define FINETUNE_XM2MOD(f) ((uint8_t)(f) >> 4)
/* Some of the following structs MUST be packed!
** Please do NOT edit these structs unless you
** absolutely know what you are doing!
*/
#ifdef _MSC_VER
#pragma pack(push)
#pragma pack(1)
#endif
typedef struct xmHdr_t
{
char ID[17], name[20], x1A, progName[20];
uint16_t version;
int32_t headerSize;
uint16_t numOrders, songLoopStart, numChannels, numPatterns;
uint16_t numInstr, flags, speed, BPM;
uint8_t orders[256];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
xmHdr_t;
typedef struct xmPatHdr_t
{
int32_t headerSize;
uint8_t type;
int16_t numRows;
uint16_t dataSize;
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
xmPatHdr_t;
typedef struct modSmpHdr_t
{
char name[22];
uint16_t length;
uint8_t finetune, volume;
uint16_t loopStart, loopLength;
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
modSmpHdr_t;
typedef struct modHdr_t
{
char name[20];
modSmpHdr_t smp[31];
uint8_t numOrders, songLoopStart, orders[128];
char ID[4];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
modHdr_t;
typedef struct xmSmpHdr_t
{
uint32_t length, loopStart, loopLength;
uint8_t volume;
int8_t finetune;
uint8_t flags, panning;
int8_t relativeNote;
uint8_t nameLength; // only handled before saving (ignored under load)
char name[22];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
xmSmpHdr_t;
typedef struct xmInsHdr_t
{
uint32_t instrSize;
char name[22];
uint8_t type;
int16_t numSamples;
int32_t sampleSize;
uint8_t note2SampleLUT[96];
int16_t volEnvPoints[12][2], panEnvPoints[12][2];
uint8_t volEnvLength, panEnvLength;
uint8_t volEnvSustain, volEnvLoopStart, volEnvLoopEnd;
uint8_t panEnvSustain, panEnvLoopStart, panEnvLoopEnd;
uint8_t volEnvFlags, panEnvFlags;
uint8_t vibType, vibSweep, vibDepth, vibRate;
uint16_t fadeout;
uint8_t midiOn, midiChannel;
int16_t midiProgram, midiBend;
int8_t mute;
uint8_t junk[15];
xmSmpHdr_t smp[16];
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
xmInsHdr_t;
typedef struct pattNote_t // must be packed!
{
uint8_t note, instr, vol, efx, efxData;
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
note_t;
typedef struct syncedChannel_t // used for audio/video sync queue (pack to save RAM)
{
uint8_t status, pianoNoteNum, smpNum, instrNum;
int32_t smpStartPos;
uint8_t scopeVolume;
uint64_t scopeDelta;
}
#ifdef __GNUC__
__attribute__ ((packed))
#endif
syncedChannel_t;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
typedef struct sample_t
{
char name[22+1];
bool isFixed;
int8_t finetune, relativeNote, *dataPtr, *origDataPtr;
uint8_t volume, flags, panning;
int32_t length, loopStart, loopLength;
// fix for resampling interpolation taps
int8_t leftEdgeTapSamples8[MAX_TAPS*2];
int16_t leftEdgeTapSamples16[MAX_TAPS*2];
int16_t fixedSmp[MAX_TAPS*2];
int32_t fixedPos;
} sample_t;
typedef struct instr_t
{
bool midiOn, mute;
uint8_t midiChannel, note2SampleLUT[96];
uint8_t volEnvLength, panEnvLength;
uint8_t volEnvSustain, volEnvLoopStart, volEnvLoopEnd;
uint8_t panEnvSustain, panEnvLoopStart, panEnvLoopEnd;
uint8_t volEnvFlags, panEnvFlags;
uint8_t autoVibType, autoVibSweep, autoVibDepth, autoVibRate;
uint16_t fadeout;
int16_t volEnvPoints[12][2], panEnvPoints[12][2], midiProgram, midiBend;
int16_t numSamples; // used by loader only
sample_t smp[16];
} instr_t;
typedef struct channel_t
{
bool keyOff, channelOff, mute, portaSemitoneSlides;
volatile uint8_t status, tmpStatus;
int8_t relativeNote, finetune;
uint8_t smpNum, instrNum, efxData, efx, sampleOffset, tremorParam, tremorPos;
uint8_t globVolSlideSpeed, panningSlideSpeed, vibTremCtrl, portamentoDirection;
uint8_t vibratoPos, tremoloPos, vibratoSpeed, vibratoDepth, tremoloSpeed, tremoloDepth;
uint8_t patternLoopStartRow, patternLoopCounter, volSlideSpeed, fVolSlideUpSpeed, fVolSlideDownSpeed;
uint8_t fPitchSlideUpSpeed, fPitchSlideDownSpeed, efPitchSlideUpSpeed, efPitchSlideDownSpeed;
uint8_t pitchSlideUpSpeed, pitchSlideDownSpeed, noteRetrigSpeed, noteRetrigCounter, noteRetrigVol;
uint8_t volColumnVol, noteNum, panEnvPos, autoVibPos, volEnvPos, realVol, oldVol, outVol;
uint8_t oldPan, outPan, finalPan;
int16_t midiPitch;
uint16_t outPeriod, realPeriod, finalPeriod, copyOfInstrAndNote, portamentoTargetPeriod, portamentoSpeed;
uint16_t volEnvTick, panEnvTick, autoVibAmp, autoVibSweep;
uint16_t midiVibDepth;
int32_t fadeoutVol, fadeoutSpeed;
int32_t oldFinalPeriod, smpStartPos;
float fFinalVol, fVolEnvDelta, fPanEnvDelta, fVolEnvValue, fPanEnvValue;
sample_t *smpPtr;
instr_t *instrPtr;
} channel_t;
typedef struct song_t
{
bool pBreakFlag, posJumpFlag, isModified;
char name[20+1], instrName[1+MAX_INST][22+1];
uint8_t curReplayerTick, curReplayerRow, curReplayerSongPos, curReplayerPattNum; // used for audio/video sync queue
uint8_t pattDelTime, pattDelTime2, pBreakPos, orders[MAX_ORDERS];
int16_t songPos, pattNum, row, currNumRows;
uint16_t songLength, songLoopStart, BPM, speed, initialSpeed, globalVolume, tick;
int32_t numChannels;
uint32_t playbackSeconds;
uint64_t playbackSecondsFrac;
} song_t;
double getSampleC4Rate(sample_t *s);
void setNewSongPos(int32_t pos);
void fixString(char *str, int32_t lastChrPos); // removes leading spaces and 0x1A chars
void fixSongName(void);
void fixInstrAndSampleNames(int16_t insNum);
void calcReplayerVars(int32_t rate);
// used on external sample load and during sample loading in some module formats
void tuneSample(sample_t *s, const int32_t midCFreq, bool linearPeriodsFlag);
void calcReplayerLogTab(void); // for linear period -> hz calculation
double dLinearPeriod2Hz(int32_t period);
double dAmigaPeriod2Hz(int32_t period);
double dPeriod2Hz(int32_t period);
int32_t getPianoKey(uint16_t period, int8_t finetune, int8_t relativeNote); // for piano in Instr. Ed.
bool allocateInstr(int16_t insNum);
void freeInstr(int32_t insNum);
void freeAllInstr(void);
void freeSample(int16_t insNum, int16_t smpNum);
void freeAllPatterns(void);
void updateChanNums(void);
bool setupReplayer(void);
void closeReplayer(void);
void resetMusic(void);
void startPlaying(int8_t mode, int16_t row);
void stopPlaying(void);
void stopVoices(void);
void setPos(int16_t songPos, int16_t row, bool resetTimer);
void pauseMusic(void); // stops reading pattern data
void resumeMusic(void); // starts reading pattern data
void setSongModifiedFlag(void);
void removeSongModifiedFlag(void);
void playTone(uint8_t chNum, uint8_t insNum, uint8_t note, int8_t vol, uint16_t midiVibDepth, uint16_t midiPitch);
void playSample(uint8_t chNum, uint8_t insNum, uint8_t smpNum, uint8_t note, uint16_t midiVibDepth, uint16_t midiPitch);
void playRange(uint8_t chNum, uint8_t insNum, uint8_t smpNum, uint8_t note, uint16_t midiVibDepth, uint16_t midiPitch, int32_t smpOffset, int32_t length);
void keyOff(channel_t *ch);
void conv8BitSample(int8_t *p, int32_t length, bool stereo); // changes sample sign
void conv16BitSample(int8_t *p, int32_t length, bool stereo); // changes sample sign
void delta2Samp(int8_t *p, int32_t length, uint8_t smpFlags);
void samp2Delta(int8_t *p, int32_t length, uint8_t smpFlags);
void setPatternLen(uint16_t pattNum, int16_t numRows);
void setLinearPeriods(bool linearPeriodsFlag);
void tickReplayer(void); // periodically called from audio callback
void resetChannels(void);
bool patternEmpty(uint16_t pattNum);
int16_t getUsedSamples(int16_t smpNum);
int16_t getRealUsedSamples(int16_t smpNum);
void setStdEnvelope(instr_t *ins, int16_t i, uint8_t type);
void setNoEnvelope(instr_t *ins);
void setSyncedReplayerVars(void);
void decSongPos(void);
void incSongPos(void);
void decCurIns(void);
void incCurIns(void);
void decCurSmp(void);
void incCurSmp(void);
void pbPlaySong(void);
void pbPlayPtn(void);
void pbRecSng(void);
void pbRecPtn(void);
// ft2_replayer.c
extern int8_t playMode;
extern bool songPlaying, audioPaused, musicPaused;
extern volatile bool replayerBusy;
extern const uint16_t *note2Period;
extern int16_t patternNumRows[MAX_PATTERNS];
extern channel_t channel[MAX_CHANNELS];
extern song_t song;
extern instr_t *instr[128+4];
extern note_t *pattern[MAX_PATTERNS];