furnace/src/engine/engine.h

1469 lines
40 KiB
C
Raw Normal View History

2022-02-14 22:12:20 -05:00
/**
* Furnace Tracker - multi-system chiptune tracker
2024-01-16 21:26:57 -05:00
* Copyright (C) 2021-2024 tildearrow and contributors
2022-02-14 22:12:20 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _ENGINE_H
#define _ENGINE_H
#include "config.h"
#include "instrument.h"
#include "song.h"
#include "dispatch.h"
2023-05-21 05:39:36 -04:00
#include "effect.h"
2023-03-13 05:20:54 -04:00
#include "export.h"
#include "dataErrors.h"
#include "safeWriter.h"
#include "cmdStream.h"
#include "../audio/taAudio.h"
#include "blip_buf.h"
2022-03-19 04:42:44 -04:00
#include <functional>
#include <initializer_list>
#include <thread>
2023-09-13 03:46:02 -04:00
#include "../fixedQueue.h"
class DivWorkPool;
2022-02-18 12:58:36 -05:00
#define addWarning(x) \
if (warnings.empty()) { \
warnings+=x; \
} else { \
warnings+=(String("\n")+x); \
}
#define BUSY_BEGIN softLocked=false; isBusy.lock();
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
#define BUSY_END isBusy.unlock(); softLocked=false;
2023-03-13 21:01:01 -04:00
#define EXTERN_BUSY_BEGIN e->softLocked=false; e->isBusy.lock();
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
//#define DIV_UNSTABLE
#define DIV_VERSION "0.6.4"
#define DIV_ENGINE_VERSION 212
2022-03-14 18:16:43 -04:00
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
2023-03-12 20:11:05 -04:00
#define DIV_VERSION_S3M 0xff03
#define DIV_VERSION_FTM 0xff04
2022-03-14 18:16:43 -04:00
enum DivStatusView {
DIV_STATUS_NOTHING=0,
DIV_STATUS_PATTERN,
DIV_STATUS_COMMANDS
};
2021-06-09 04:33:03 -04:00
enum DivAudioEngines {
DIV_AUDIO_JACK=0,
2022-01-22 23:50:49 -05:00
DIV_AUDIO_SDL=1,
DIV_AUDIO_PORTAUDIO=2,
DIV_AUDIO_PIPE=3,
2022-08-16 12:24:18 -04:00
DIV_AUDIO_NULL=126,
DIV_AUDIO_DUMMY=127
2021-06-09 04:33:03 -04:00
};
enum DivAudioExportModes {
DIV_EXPORT_MODE_ONE=0,
DIV_EXPORT_MODE_MANY_SYS,
DIV_EXPORT_MODE_MANY_CHAN
};
2022-02-03 18:38:57 -05:00
enum DivHaltPositions {
DIV_HALT_NONE=0,
DIV_HALT_TICK,
DIV_HALT_ROW,
DIV_HALT_PATTERN,
DIV_HALT_BREAKPOINT
};
2022-09-26 02:27:36 -04:00
enum DivMIDIModes {
DIV_MIDI_MODE_OFF=0,
DIV_MIDI_MODE_NOTE,
DIV_MIDI_MODE_LIGHT_SHOW
};
2024-05-11 15:25:53 -04:00
enum DivAudioExportFormats {
DIV_EXPORT_FORMAT_S16=0,
DIV_EXPORT_FORMAT_F32
};
struct DivAudioExportOptions {
DivAudioExportModes mode;
2024-05-11 15:25:53 -04:00
DivAudioExportFormats format;
int sampleRate;
int chans;
int loops;
double fadeOut;
int orderBegin, orderEnd;
bool channelMask[DIV_MAX_CHANS];
DivAudioExportOptions():
mode(DIV_EXPORT_MODE_ONE),
2024-05-11 15:25:53 -04:00
format(DIV_EXPORT_FORMAT_S16),
sampleRate(44100),
chans(2),
loops(0),
fadeOut(0.0),
orderBegin(-1),
orderEnd(-1) {
for (int i=0; i<DIV_MAX_CHANS; i++) {
channelMask[i]=true;
}
}
};
struct DivChannelState {
std::vector<DivDelayedCommand> delayed;
2022-03-14 02:23:31 -04:00
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
2024-03-16 20:41:08 -04:00
int volume, volSpeed, cut, legatoDelay, legatoTarget, rowDelay, volMax;
int delayOrder, delayRow, retrigSpeed, retrigTick;
2022-06-14 05:41:31 -04:00
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine;
int tremoloDepth, tremoloRate, tremoloPos;
int sampleOff;
unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta, cutType;
2023-10-03 05:38:28 -04:00
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff, releasing;
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp, sampleOffSet;
bool wentThroughNote, goneThroughNote;
2021-05-14 04:23:40 -04:00
2022-04-09 02:50:44 -04:00
int midiNote, curMidiNote, midiPitch;
size_t midiAge;
2022-04-09 02:50:44 -04:00
bool midiAftertouch;
2021-05-14 04:23:40 -04:00
DivChannelState():
note(-1),
oldNote(-1),
2022-03-14 02:23:31 -04:00
lastIns(-1),
2021-05-14 04:23:40 -04:00
pitch(0),
portaSpeed(-1),
portaNote(-1),
volume(0x7f00),
volSpeed(0),
cut(-1),
2024-03-16 20:41:08 -04:00
legatoDelay(-1),
legatoTarget(0),
rowDelay(0),
2021-12-16 15:51:19 -05:00
volMax(0),
delayOrder(0),
delayRow(0),
retrigSpeed(0),
retrigTick(0),
2021-05-14 04:23:40 -04:00
vibratoDepth(0),
vibratoRate(0),
vibratoPos(0),
2022-06-14 05:41:31 -04:00
vibratoPosGiant(0),
vibratoDir(0),
2021-05-18 04:02:47 -04:00
vibratoFine(15),
2021-05-14 04:23:40 -04:00
tremoloDepth(0),
tremoloRate(0),
tremoloPos(0),
sampleOff(0),
arp(0),
arpStage(-1),
2021-05-18 03:53:59 -04:00
arpTicks(1),
2022-04-30 00:41:14 -04:00
panL(255),
panR(255),
2023-01-05 03:08:57 -05:00
panRL(0),
panRR(0),
2023-04-30 14:46:09 -04:00
lastVibrato(0),
lastPorta(0),
cutType(0),
doNote(false),
legato(false),
portaStop(false),
keyOn(false),
2022-01-19 01:36:20 -05:00
keyOff(false),
nowYouCanStop(true),
stopOnOff(false),
2023-10-03 05:38:28 -04:00
releasing(false),
arpYield(false),
2021-12-19 00:27:04 -05:00
delayLocked(false),
2022-01-19 01:27:32 -05:00
inPorta(false),
2022-02-03 01:30:03 -05:00
scheduledSlideReset(false),
shorthandPorta(false),
wasShorthandPorta(false),
noteOnInhibit(false),
resetArp(false),
sampleOffSet(false),
wentThroughNote(false),
goneThroughNote(false),
2022-03-31 04:33:05 -04:00
midiNote(-1),
2022-04-09 02:50:44 -04:00
curMidiNote(-1),
midiPitch(-1),
midiAge(0),
2022-04-09 02:50:44 -04:00
midiAftertouch(false) {}
};
2021-12-28 18:23:57 -05:00
struct DivNoteEvent {
signed char channel;
2024-01-20 02:34:21 -05:00
short ins;
signed char note, volume;
bool on, nop, insChange, fromMIDI;
DivNoteEvent(int c, int i, int n, int v, bool o, bool ic=false, bool fm=false):
2021-12-28 18:23:57 -05:00
channel(c),
ins(i),
note(n),
volume(v),
on(o),
nop(false),
insChange(ic),
fromMIDI(fm) {}
DivNoteEvent():
channel(-1),
ins(0),
note(0),
2023-12-13 20:44:32 -05:00
volume(-1),
on(false),
nop(true),
insChange(false),
fromMIDI(false) {}
2021-12-28 18:23:57 -05:00
};
struct DivDispatchContainer {
DivDispatch* dispatch;
blip_buffer_t* bb[DIV_MAX_OUTPUTS];
size_t bbInLen, runtotal, runLeft, runPos, lastAvail;
int temp[DIV_MAX_OUTPUTS], prevSample[DIV_MAX_OUTPUTS];
short* bbInMapped[DIV_MAX_OUTPUTS];
short* bbIn[DIV_MAX_OUTPUTS];
short* bbOut[DIV_MAX_OUTPUTS];
bool lowQuality, dcOffCompensation, hiPass;
2023-01-03 14:39:31 -05:00
double rateMemory;
2022-01-08 16:03:32 -05:00
// used in multi-thread
int cycles;
unsigned int size;
2022-01-08 16:03:32 -05:00
void setRates(double gotRate);
void setQuality(bool lowQual, bool dcHiPass);
2023-01-04 17:01:14 -05:00
void grow(size_t size);
void acquire(size_t offset, size_t count);
void flush(size_t count);
void fillBuf(size_t runtotal, size_t offset, size_t size);
2022-01-08 16:03:32 -05:00
void clear();
2023-08-18 02:40:18 -04:00
void init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, const DivConfig& flags, bool isRender=false);
2024-03-14 03:06:36 -04:00
void quit();
2022-01-08 16:03:32 -05:00
DivDispatchContainer():
dispatch(NULL),
bbInLen(0),
2022-08-07 18:32:39 -04:00
runtotal(0),
runLeft(0),
runPos(0),
lastAvail(0),
2022-04-09 19:25:25 -04:00
lowQuality(false),
2023-01-03 14:39:31 -05:00
dcOffCompensation(false),
hiPass(true),
rateMemory(0.0),
cycles(0),
size(0) {
2023-01-03 01:09:46 -05:00
memset(bb,0,DIV_MAX_OUTPUTS*sizeof(blip_buffer_t*));
memset(temp,0,DIV_MAX_OUTPUTS*sizeof(int));
memset(prevSample,0,DIV_MAX_OUTPUTS*sizeof(int));
2023-01-03 01:09:46 -05:00
memset(bbIn,0,DIV_MAX_OUTPUTS*sizeof(short*));
memset(bbInMapped,0,DIV_MAX_OUTPUTS*sizeof(short*));
memset(bbOut,0,DIV_MAX_OUTPUTS*sizeof(short*));
}
};
2023-05-21 05:39:36 -04:00
struct DivEffectContainer {
DivEffect* effect;
float* in[DIV_MAX_OUTPUTS];
float* out[DIV_MAX_OUTPUTS];
size_t inLen, outLen;
void preAcquire(size_t count);
void acquire(size_t count);
bool init(DivEffectType effectType, DivEngine* eng, double rate, unsigned short version, const unsigned char* data, size_t len);
void quit();
DivEffectContainer():
effect(NULL),
inLen(0),
outLen(0) {
memset(in,0,DIV_MAX_OUTPUTS*sizeof(float*));
memset(out,0,DIV_MAX_OUTPUTS*sizeof(float*));
}
};
typedef int EffectValConversion(unsigned char,unsigned char);
struct EffectHandler {
DivDispatchCmds dispatchCmd;
const char* description;
EffectValConversion* val;
EffectValConversion* val2;
EffectHandler(
DivDispatchCmds dispatchCmd_,
const char* description_,
EffectValConversion val_=NULL,
EffectValConversion val2_=NULL
):
dispatchCmd(dispatchCmd_),
description(description_),
val(val_),
val2(val2_) {}
};
struct DivDoNotHandleEffect {
};
typedef std::unordered_map<unsigned char,const EffectHandler> EffectHandlerMap;
struct DivSysDef {
const char* name;
const char* nameJ;
const char* description;
unsigned char id;
unsigned char id_DMF;
int channels;
bool isFM, isSTD, isCompound;
// width 0: variable
// height 0: no wavetable support
unsigned short waveWidth, waveHeight;
unsigned int vgmVersion;
unsigned int sampleFormatMask;
const char* chanNames[DIV_MAX_CHANS];
const char* chanShortNames[DIV_MAX_CHANS];
int chanTypes[DIV_MAX_CHANS];
// 0: primary
// 1: alternate (usually PCM)
DivInstrumentType chanInsType[DIV_MAX_CHANS][2];
const EffectHandlerMap effectHandlers;
const EffectHandlerMap postEffectHandlers;
const EffectHandlerMap preEffectHandlers;
DivSysDef(
const char* sysName, const char* sysNameJ, unsigned char fileID, unsigned char fileID_DMF, int chans,
bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, unsigned int formatMask, unsigned short waveWid, unsigned short waveHei,
const char* desc,
std::initializer_list<const char*> chNames,
std::initializer_list<const char*> chShortNames,
std::initializer_list<int> chTypes,
std::initializer_list<DivInstrumentType> chInsType1,
std::initializer_list<DivInstrumentType> chInsType2={},
const EffectHandlerMap fxHandlers_={},
const EffectHandlerMap postFxHandlers_={},
const EffectHandlerMap preFxHandlers_={}):
name(sysName),
nameJ(sysNameJ),
description(desc),
id(fileID),
id_DMF(fileID_DMF),
channels(chans),
isFM(isFMChip),
isSTD(isSTDChip),
isCompound(compound),
waveWidth(waveWid),
waveHeight(waveHei),
vgmVersion(vgmVer),
sampleFormatMask(formatMask),
effectHandlers(fxHandlers_),
postEffectHandlers(postFxHandlers_),
preEffectHandlers(preFxHandlers_) {
memset(chanNames,0,DIV_MAX_CHANS*sizeof(void*));
memset(chanShortNames,0,DIV_MAX_CHANS*sizeof(void*));
memset(chanTypes,0,DIV_MAX_CHANS*sizeof(int));
for (int i=0; i<DIV_MAX_CHANS; i++) {
chanInsType[i][0]=DIV_INS_NULL;
chanInsType[i][1]=DIV_INS_NULL;
}
int index=0;
for (const char* i: chNames) {
chanNames[index++]=i;
if (index>=DIV_MAX_CHANS) break;
}
index=0;
for (const char* i: chShortNames) {
chanShortNames[index++]=i;
if (index>=DIV_MAX_CHANS) break;
}
index=0;
for (int i: chTypes) {
chanTypes[index++]=i;
if (index>=DIV_MAX_CHANS) break;
}
index=0;
for (DivInstrumentType i: chInsType1) {
chanInsType[index++][0]=i;
if (index>=DIV_MAX_CHANS) break;
}
index=0;
for (DivInstrumentType i: chInsType2) {
chanInsType[index++][1]=i;
if (index>=DIV_MAX_CHANS) break;
}
}
};
enum DivChanTypes {
DIV_CH_FM=0,
DIV_CH_PULSE=1,
DIV_CH_NOISE=2,
DIV_CH_WAVE=3,
DIV_CH_PCM=4,
DIV_CH_OP=5
};
2022-08-04 01:51:47 -04:00
extern const char* cmdName[];
class DivEngine {
DivDispatchContainer disCont[DIV_MAX_CHIPS];
TAAudio* output;
TAAudioDesc want, got;
String exportPath;
std::thread* exportThread;
int chans;
bool configLoaded;
bool active;
2022-01-17 01:42:26 -05:00
bool lowQuality;
bool dcHiPass;
bool playing;
2021-12-28 18:23:57 -05:00
bool freelance;
2022-10-22 04:46:39 -04:00
bool shallStop, shallStopSched;
bool endOfSong;
bool consoleMode;
bool disableStatusOut;
bool extValuePresent;
bool repeatPattern;
2022-01-04 00:02:41 -05:00
bool metronome;
bool exporting;
bool stopExport;
2022-02-03 18:38:57 -05:00
bool halted;
bool forceMono;
2022-07-25 19:41:47 -04:00
bool clampSamples;
bool cmdStreamEnabled;
bool softLocked;
bool firstTick;
2022-03-31 04:33:05 -04:00
bool skipping;
2022-04-01 03:21:10 -04:00
bool midiIsDirect;
bool midiIsDirectProgram;
bool lowLatency;
bool systemsRegistered;
bool hasLoadedSomething;
2022-09-26 02:27:36 -04:00
bool midiOutClock;
2023-05-10 03:57:59 -04:00
bool midiOutTime;
bool midiOutProgramChange;
2022-09-26 02:27:36 -04:00
int midiOutMode;
2023-05-10 03:57:59 -04:00
int midiOutTimeRate;
float midiVolExp;
2022-03-23 23:05:09 -04:00
int softLockCount;
2023-02-05 02:56:39 -05:00
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats, curSpeed;
size_t curSubSongIndex;
2023-01-03 01:09:46 -05:00
size_t bufferPos;
2022-03-16 00:30:15 -04:00
double divider;
int cycles;
double clockDrift;
2023-05-09 06:05:53 -04:00
int midiClockCycles;
double midiClockDrift;
int midiTimeCycles;
double midiTimeDrift;
2022-03-16 00:30:15 -04:00
int stepPlay;
2023-05-09 23:12:14 -04:00
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, curMidiClock, curMidiTime, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
2023-05-10 03:57:59 -04:00
int curMidiTimePiece, curMidiTimeCode;
2022-11-09 23:52:10 -05:00
unsigned char extValue, pendingMetroTick;
2023-02-05 02:56:39 -05:00
DivGroovePattern speeds;
2024-03-15 15:56:55 -04:00
short virtualTempoN, virtualTempoD;
2022-05-18 01:05:25 -04:00
short tempoAccum;
DivStatusView view;
2022-02-03 18:38:57 -05:00
DivHaltPositions haltOn;
2022-01-08 01:57:37 -05:00
DivChannelState chan[DIV_MAX_CHANS];
2021-06-09 04:33:03 -04:00
DivAudioEngines audioEngine;
DivAudioExportModes exportMode;
2024-05-11 15:25:53 -04:00
DivAudioExportFormats exportFormat;
2022-06-06 04:05:55 -04:00
double exportFadeOut;
int exportOutputs;
2024-05-11 15:25:53 -04:00
bool exportChannelMask[DIV_MAX_CHANS];
DivConfig conf;
FixedQueue<DivNoteEvent,8192> pendingNotes;
2022-09-10 02:39:42 -04:00
// bitfield
unsigned char walked[8192];
2022-01-08 01:57:37 -05:00
bool isMuted[DIV_MAX_CHANS];
2023-09-16 16:04:11 -04:00
std::mutex isBusy, saveLock, playPosLock;
2021-12-19 03:16:24 -05:00
String configPath;
2021-12-19 16:52:04 -05:00
String configFile;
String lastError;
2022-01-29 01:22:32 -05:00
String warnings;
2022-02-13 21:42:57 -05:00
std::vector<String> audioDevs;
std::vector<String> midiIns;
std::vector<String> midiOuts;
std::vector<DivCommand> cmdStream;
std::vector<DivInstrumentType> possibleInsTypes;
2023-05-21 05:39:36 -04:00
std::vector<DivEffectContainer> effectInst;
static DivSysDef* sysDefs[DIV_MAX_CHIP_DEFS];
static DivSystem sysFileMapFur[DIV_MAX_CHIP_DEFS];
static DivSystem sysFileMapDMF[DIV_MAX_CHIP_DEFS];
DivCSPlayer* cmdStreamInt;
struct SamplePreview {
2022-09-30 18:47:17 -04:00
double rate;
int sample;
int wave;
int pos;
int pBegin, pEnd;
int rateMul, posSub;
bool dir;
SamplePreview():
2022-09-30 18:47:17 -04:00
rate(0.0),
sample(-1),
wave(-1),
pos(0),
pBegin(-1),
pEnd(-1),
rateMul(1),
posSub(0),
dir(false) {}
} sPreview;
short vibTable[64];
2023-02-04 16:08:20 -05:00
short tremTable[128];
int reversePitchTable[4096];
int pitchTable[4096];
2023-05-21 05:39:36 -04:00
short effectSlotMap[4096];
int midiBaseChan;
2022-06-03 19:05:07 -04:00
bool midiPoly;
2024-01-25 15:29:37 -05:00
bool midiDebug;
size_t midiAgeCounter;
2022-01-08 16:03:32 -05:00
blip_buffer_t* samp_bb;
size_t samp_bbInLen;
int samp_temp, samp_prevSample;
short* samp_bbIn;
short* samp_bbOut;
2022-01-04 00:02:41 -05:00
unsigned char* metroTick;
size_t metroTickLen;
float* metroBuf;
size_t metroBufLen;
2022-01-04 00:29:59 -05:00
float metroFreq, metroPos;
2022-01-04 00:02:41 -05:00
float metroAmp;
2022-04-13 03:29:07 -04:00
float metroVol;
float previewVol;
2021-12-08 02:57:41 -05:00
size_t totalProcessed;
2023-09-06 15:23:47 -04:00
unsigned int renderPoolThreads;
DivWorkPool* renderPool;
2022-03-28 19:19:47 -04:00
// MIDI stuff
2022-04-01 02:50:01 -04:00
std::function<int(const TAMidiMessage&)> midiCallback=[](const TAMidiMessage&) -> int {return -2;};
2022-03-28 16:24:09 -04:00
void processRowPre(int i);
void processRow(int i, bool afterDelay);
void nextOrder();
void nextRow();
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream);
// returns true if end of song.
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
bool perSystemPreEffect(int ch, unsigned char effect, unsigned char effectVal);
2022-01-08 16:03:32 -05:00
void recalcChans();
void reset();
void playSub(bool preserveDrift, int goalRow=0);
2023-05-10 04:30:05 -04:00
void runMidiClock(int totalCycles=1);
void runMidiTime(int totalCycles=1);
2023-08-21 15:14:09 -04:00
bool shallSwitchCores();
2023-03-13 15:17:05 -04:00
void testFunction();
bool loadDMF(unsigned char* file, size_t len);
2024-03-14 18:58:55 -04:00
bool loadFur(unsigned char* file, size_t len, int variantID=0);
2022-03-14 10:50:52 -04:00
bool loadMod(unsigned char* file, size_t len);
2023-03-12 20:11:05 -04:00
bool loadS3M(unsigned char* file, size_t len);
bool loadXM(unsigned char* file, size_t len);
bool loadIT(unsigned char* file, size_t len);
2024-03-16 04:45:35 -04:00
bool loadFTM(unsigned char* file, size_t len, bool dnft, bool dnftSig, bool eft);
bool loadFC(unsigned char* file, size_t len);
2024-04-13 02:43:37 -04:00
bool loadTFMv1(unsigned char* file, size_t len);
bool loadTFMv2(unsigned char* file, size_t len);
2022-04-03 14:53:34 -04:00
void loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadTFI(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadVGI(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadS3I(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadSBI(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadOPLI(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadOPNI(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadY12(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
2022-04-14 07:33:20 -04:00
void loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadGYB(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
2022-04-03 14:53:34 -04:00
void loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
2022-04-10 08:16:33 -04:00
void loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
2022-05-09 03:49:56 -04:00
void loadWOPL(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadWOPN(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
2022-04-03 14:53:34 -04:00
int loadSampleROM(String path, ssize_t expectedSize, unsigned char*& ret);
bool initAudioBackend();
bool deinitAudioBackend(bool dueToSwitchMaster=false);
void registerSystems();
void initSongWithDesc(const char* description, bool inBase64=true, bool oldVol=false);
void exchangeIns(int one, int two);
void exchangeWave(int one, int two);
void exchangeSample(int one, int two);
2022-04-28 04:36:15 -04:00
void swapChannels(int src, int dest);
void stompChannel(int ch);
2023-05-21 05:39:36 -04:00
// recalculate patchbay (UNSAFE)
void recalcPatchbay();
// change song (UNSAFE)
void changeSong(size_t songIndex);
2024-02-22 12:48:16 -05:00
void swapSystemUnsafe(int src, int dest, bool preserveOrder=true);
2023-05-16 04:04:16 -04:00
// move an asset
void moveAsset(std::vector<DivAssetDir>& dir, int before, int after);
2023-05-16 00:27:45 -04:00
// remove an asset
void removeAsset(std::vector<DivAssetDir>& dir, int entry);
2023-05-16 03:44:46 -04:00
// read/write asset dir
void putAssetDirData(SafeWriter* w, std::vector<DivAssetDir>& dir);
DivDataErrors readAssetDirData(SafeReader& reader, std::vector<DivAssetDir>& dir);
2023-03-13 15:17:05 -04:00
// add every export method here
friend class DivROMExport;
friend class DivExportAmigaValidation;
public:
2021-05-12 18:19:18 -04:00
DivSong song;
DivOrders* curOrders;
DivChannelData* curPat;
DivSubSong* curSubSong;
DivInstrument* tempIns;
2022-01-27 00:29:16 -05:00
DivSystem sysOfChan[DIV_MAX_CHANS];
int dispatchOfChan[DIV_MAX_CHANS];
int dispatchChanOfChan[DIV_MAX_CHANS];
int dispatchFirstChan[DIV_MAX_CHANS];
2022-02-10 03:15:39 -05:00
bool keyHit[DIV_MAX_CHANS];
float* oscBuf[DIV_MAX_OUTPUTS];
2022-01-27 17:49:00 -05:00
float oscSize;
int oscReadPos, oscWritePos;
int tickMult;
2023-07-06 19:29:29 -04:00
int lastNBIns, lastNBOuts, lastNBSize;
std::atomic<size_t> processTime;
2022-01-27 00:29:16 -05:00
void runExportThread();
void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size);
DivInstrument* getIns(int index, DivInstrumentType fallbackType=DIV_INS_FM);
DivWavetable* getWave(int index);
2022-02-24 22:52:20 -05:00
DivSample* getSample(int index);
DivDispatch* getDispatch(int index);
// parse old system setup description
String decodeSysDesc(String desc);
2021-12-24 18:23:01 -05:00
// start fresh
2022-11-13 16:57:47 -05:00
void createNew(const char* description, String sysName, bool inBase64=true);
2023-02-23 05:56:48 -05:00
void createNewFromDefaults();
// load a file.
2024-03-16 13:16:09 -04:00
bool load(unsigned char* f, size_t length, const char* nameHint=NULL);
// play a binary command stream.
bool playStream(unsigned char* f, size_t length);
2024-03-08 17:53:37 -05:00
// get the playing stream.
DivCSPlayer* getStreamPlayer();
// destroy command stream player.
bool killStream();
// save as .dmf.
SafeWriter* saveDMF(unsigned char version);
// save as .fur.
2022-03-21 15:11:28 -04:00
// if notPrimary is true then the song will not be altered
2023-05-26 02:29:49 -04:00
SafeWriter* saveFur(bool notPrimary=false, bool newPatternFormat=true);
2022-01-16 23:21:27 -05:00
// build a ROM file (TODO).
// specify system to build ROM for.
2023-03-13 15:17:05 -04:00
std::vector<DivROMExportOutput> buildROM(DivROMExportOptions sys);
// dump to VGM.
// set trailingTicks to:
// - 0 to add one tick of trailing
// - x to add x+1 ticks of trailing
// - -1 to auto-determine trailing
// - -2 to add a whole loop of trailing
SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false, bool directStream=false, int trailingTicks=-1);
2022-05-26 01:24:21 -04:00
// dump to ZSM.
2023-08-11 16:03:37 -04:00
SafeWriter* saveZSM(unsigned int zsmrate=60, bool loop=true, bool optimize=true);
// dump command stream.
SafeWriter* saveCommand();
2023-12-04 04:17:30 -05:00
// export to text
SafeWriter* saveText(bool separatePatterns=true);
// export to an audio file
bool saveAudio(const char* path, DivAudioExportOptions options);
// wait for audio export to finish
void waitAudioFile();
// stop audio file export
bool haltAudioFile();
2023-08-21 15:14:09 -04:00
// return back to playback cores if necessary
void finishAudioFile();
2022-01-17 23:59:52 -05:00
// notify instrument parameter change
void notifyInsChange(int ins);
2022-01-18 00:25:10 -05:00
// notify wavetable change
void notifyWaveChange(int wave);
// dispatch a command
int dispatchCmd(DivCommand c);
// get system IDs
2022-11-13 15:41:40 -05:00
static DivSystem systemFromFileFur(unsigned char val);
static unsigned char systemToFileFur(DivSystem val);
static DivSystem systemFromFileDMF(unsigned char val);
static unsigned char systemToFileDMF(DivSystem val);
2022-11-13 16:25:50 -05:00
// convert old flags
static void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys);
2023-05-16 05:29:26 -04:00
// check whether an asset directory is complete (UNSAFE)
void checkAssetDir(std::vector<DivAssetDir>& dir, size_t entries);
2022-11-13 16:25:50 -05:00
2022-07-19 18:01:19 -04:00
// benchmark (returns time in seconds)
double benchmarkPlayback();
double benchmarkSeek();
// returns the minimum VGM version which may carry the specified system, or 0 if none.
int minVGMVersion(DivSystem which);
// determine and setup config dir
void initConfDir();
2021-12-19 16:52:04 -05:00
// save config
bool saveConf();
// load config
bool loadConf();
// get a config value
bool getConfBool(String key, bool fallback);
int getConfInt(String key, int fallback);
float getConfFloat(String key, float fallback);
double getConfDouble(String key, double fallback);
String getConfString(String key, String fallback);
// get config object
DivConfig& getConfObject();
2021-12-19 16:52:04 -05:00
// set a config value
void setConf(String key, bool value);
void setConf(String key, int value);
void setConf(String key, float value);
void setConf(String key, double value);
2022-09-10 19:53:27 -04:00
void setConf(String key, const char* value);
2021-12-19 16:52:04 -05:00
void setConf(String key, String value);
2023-02-06 18:52:51 -05:00
// get whether config value exists
bool hasConf(String key);
2024-05-18 17:01:47 -04:00
// reset all settings
void factoryReset();
// calculate base frequency/period
double calcBaseFreq(double clock, double divider, int note, bool period);
2022-04-24 23:45:59 -04:00
// calculate base frequency in f-num/block format
int calcBaseFreqFNumBlock(double clock, double divider, int note, int bits);
2022-04-24 23:45:59 -04:00
// calculate frequency/period
2022-12-17 02:07:24 -05:00
int calcFreq(int base, int pitch, int arp, bool arpFixed, bool period=false, int octave=0, int pitch2=0, double clock=1.0, double divider=1.0, int blockBits=0);
// calculate arpeggio
int calcArp(int note, int arp, int offset=0);
// convert panning formats
int convertPanSplitToLinear(unsigned int val, unsigned char bits, int range);
2022-04-30 00:41:14 -04:00
int convertPanSplitToLinearLR(unsigned char left, unsigned char right, int range);
unsigned int convertPanLinearToSplit(int val, unsigned char bits, int range);
2022-01-25 15:06:29 -05:00
// find song loop position
2022-01-27 01:04:26 -05:00
void walkSong(int& loopOrder, int& loopRow, int& loopEnd);
2022-01-25 15:06:29 -05:00
2023-09-09 18:12:49 -04:00
// play (returns whether successful)
bool play();
2023-09-09 18:12:49 -04:00
// play to row (returns whether successful)
bool playToRow(int row);
2022-02-06 00:42:07 -05:00
// play by one row
void stepOne(int row);
2021-12-11 03:34:43 -05:00
// stop
void stop();
// reset playback state
void syncReset();
2022-09-30 18:47:17 -04:00
// sample preview query
bool isPreviewingSample();
int getSamplePreviewSample();
2022-09-30 18:47:17 -04:00
int getSamplePreviewPos();
double getSamplePreviewRate();
// set sample preview volume (1.0 = 100%)
void setSamplePreviewVol(float vol);
// trigger sample preview
void previewSample(int sample, int note=-1, int pStart=-1, int pEnd=-1);
2022-01-20 16:51:31 -05:00
void stopSamplePreview();
// trigger wave preview
void previewWave(int wave, int note);
void stopWavePreview();
2022-11-06 02:06:51 -05:00
// trigger sample preview
void previewSampleNoLock(int sample, int note=-1, int pStart=-1, int pEnd=-1);
void stopSamplePreviewNoLock();
// trigger wave preview
void previewWaveNoLock(int wave, int note);
void stopWavePreviewNoLock();
2021-12-19 03:16:24 -05:00
// get config path
String getConfigPath();
// get sys channel count
int getChannelCount(DivSystem sys);
2022-01-08 01:57:37 -05:00
// get channel count
int getTotalChannelCount();
// get instrument types available for use
std::vector<DivInstrumentType>& getPossibleInsTypes();
2022-01-20 13:48:20 -05:00
// get effect description
2022-04-19 19:44:05 -04:00
const char* getEffectDesc(unsigned char effect, int chan, bool notNull=false);
2022-01-20 13:48:20 -05:00
2021-12-23 17:09:33 -05:00
// get channel type
// - 0: FM
// - 1: pulse
// - 2: noise
// - 3: wave/other
// - 4: PCM
// - 5: FM operator
int getChannelType(int ch);
2022-01-15 22:11:40 -05:00
// get preferred instrument type
DivInstrumentType getPreferInsType(int ch);
// get alternate instrument type
DivInstrumentType getPreferInsSecondType(int ch);
// get song system name
String getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAcceptable=true);
2021-12-15 17:32:08 -05:00
// get sys name
const char* getSystemName(DivSystem sys);
// get japanese system name
const char* getSystemNameJ(DivSystem sys);
2022-08-16 12:24:18 -04:00
2022-08-26 20:30:13 -04:00
// get sys definition
const DivSysDef* getSystemDef(DivSystem sys);
2022-08-28 11:54:20 -04:00
// convert sample rate format
int fileToDivRate(int frate);
int divToFileRate(int drate);
// get effective sample rate
int getEffectiveSampleRate(int rate);
2021-12-15 17:32:08 -05:00
// is FM system
bool isFMSystem(DivSystem sys);
2021-12-17 22:14:41 -05:00
// is STD system
bool isSTDSystem(DivSystem sys);
2021-12-18 03:25:42 -05:00
// is channel muted
bool isChannelMuted(int chan);
// toggle mute
void toggleMute(int chan);
// toggle solo
void toggleSolo(int chan);
// set mute status
void muteChannel(int chan, bool mute);
// unmute all
void unmuteAll();
2021-12-13 13:10:56 -05:00
// get channel name
const char* getChannelName(int chan);
// get channel short name
const char* getChannelShortName(int chan);
2021-12-13 17:09:46 -05:00
// get channel max volume
int getMaxVolumeChan(int chan);
2023-12-17 15:08:52 -05:00
// map MIDI velocity to volume
int mapVelocity(int ch, float vel);
2021-12-11 03:34:43 -05:00
// get current order
unsigned char getOrder();
2021-12-13 17:09:46 -05:00
// get current row
int getRow();
2023-09-16 16:04:11 -04:00
// synchronous get order/row
void getPlayPos(int& order, int& row);
2022-11-10 01:26:59 -05:00
// get beat/bar
int getElapsedBars();
int getElapsedBeats();
// get current subsong
size_t getCurrentSubSong();
2023-02-05 02:56:39 -05:00
// get speeds
const DivGroovePattern& getSpeeds();
2021-12-21 02:30:09 -05:00
// get Hz
2022-03-16 00:30:15 -04:00
float getHz();
2021-12-21 02:30:09 -05:00
// get current Hz
2022-03-16 00:30:15 -04:00
float getCurHz();
2024-03-15 15:56:55 -04:00
// get virtual tempo
short getVirtualTempoN();
short getVirtualTempoD();
// tell engine about virtual tempo changes
void virtualTempoChanged();
2021-12-21 02:30:09 -05:00
// get time
int getTotalTicks(); // 1/1000000th of a second
int getTotalSeconds();
2021-12-21 02:30:09 -05:00
// get repeat pattern
bool getRepeatPattern();
// set repeat pattern
void setRepeatPattern(bool value);
// has ext value
bool hasExtValue();
// get ext value
unsigned char getExtValue();
// dump song info to stdout
void dumpSongInfo();
2021-12-13 17:09:46 -05:00
// is playing
bool isPlaying();
2022-08-16 12:24:18 -04:00
// is running
bool isRunning();
2021-12-13 17:09:46 -05:00
2022-02-06 00:42:07 -05:00
// is stepping
bool isStepping();
// is exporting
bool isExporting();
// add instrument
int addInstrument(int refChan=0, DivInstrumentType fallbackType=DIV_INS_STD);
// add instrument from pointer
int addInstrumentPtr(DivInstrument* which);
// get instrument from file
// if the returned vector is empty then there was an error.
std::vector<DivInstrument*> instrumentFromFile(const char* path, bool loadAssets=true, bool readInsName=true);
2022-01-19 02:59:44 -05:00
// load temporary instrument
void loadTempIns(DivInstrument* which);
// delete instrument
void delInstrument(int index);
2023-09-08 03:52:15 -04:00
void delInstrumentUnsafe(int index);
// add wavetable
int addWave();
// add wavetable from pointer
int addWavePtr(DivWavetable* which);
// get wavetable from file
DivWavetable* waveFromFile(const char* path, bool loadRaw=true);
2022-01-11 16:25:55 -05:00
// delete wavetable
void delWave(int index);
2023-09-08 03:52:15 -04:00
void delWaveUnsafe(int index);
// add sample
int addSample();
// add sample from pointer
int addSamplePtr(DivSample* which);
// get sample from file
DivSample* sampleFromFile(const char* path);
// get raw sample
DivSample* sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian, bool unsign, bool swapNibbles, int rate);
// delete sample
void delSample(int index);
2023-09-08 03:52:15 -04:00
void delSampleUnsafe(int index, bool render=true);
2021-12-22 17:39:16 -05:00
// add order
void addOrder(int pos, bool duplicate, bool where);
2021-12-22 17:39:16 -05:00
2022-02-12 03:59:05 -05:00
// deep clone orders
void deepCloneOrder(int pos, bool where);
2022-02-12 03:59:05 -05:00
2021-12-22 17:39:16 -05:00
// delete order
void deleteOrder(int pos);
2021-12-22 17:39:16 -05:00
// move order up
void moveOrderUp(int& pos);
2021-12-22 17:39:16 -05:00
// move order down
void moveOrderDown(int& pos);
2021-12-22 17:39:16 -05:00
// move thing up
bool moveInsUp(int which);
bool moveWaveUp(int which);
bool moveSampleUp(int which);
// move thing down
bool moveInsDown(int which);
bool moveWaveDown(int which);
bool moveSampleDown(int which);
2023-01-06 18:44:20 -05:00
// automatic patchbay
void autoPatchbay();
2023-01-10 15:58:15 -05:00
void autoPatchbayP();
2023-01-06 18:44:20 -05:00
2023-01-08 19:23:17 -05:00
// connect in patchbay
// returns false if connection already made
bool patchConnect(unsigned int src, unsigned int dest);
// disconnect in patchbay
// returns false if connection doesn't exist
bool patchDisconnect(unsigned int src, unsigned int dest);
2023-01-12 03:56:18 -05:00
// disconnect all in patchbay
void patchDisconnectAll(unsigned int portSet);
2021-12-28 18:23:57 -05:00
// play note
void noteOn(int chan, int ins, int note, int vol=-1);
// stop note
void noteOff(int chan);
// returns whether it could
bool autoNoteOn(int chan, int ins, int note, int vol=-1);
void autoNoteOff(int chan, int note, int vol=-1);
2022-04-16 01:10:52 -04:00
void autoNoteOffAll();
2022-08-16 12:24:18 -04:00
2022-06-03 19:05:07 -04:00
// set whether autoNoteIn is mono or poly
void setAutoNotePoly(bool poly);
2021-12-11 03:34:43 -05:00
// go to order
void setOrder(unsigned char order);
// update system flags
2023-10-11 03:48:39 -04:00
void updateSysFlags(int system, bool restart, bool render);
2022-01-28 18:12:56 -05:00
2021-12-15 17:32:08 -05:00
// set Hz
2023-06-11 19:57:32 -04:00
void setSongRate(float hz);
2021-12-15 17:32:08 -05:00
// set remaining loops. -1 means loop forever.
void setLoops(int loops);
2022-01-27 00:29:16 -05:00
// get channel state
DivChannelState* getChanState(int chan);
// get dispatch channel state
void* getDispatchChanState(int chan);
2022-08-16 12:24:18 -04:00
// get channel pairs
DivChannelPair getChanPaired(int chan);
2023-10-26 20:03:45 -04:00
// get channel mode hints
DivChannelModeHints getChanModeHints(int chan);
// get register pool
2022-02-22 04:01:57 -05:00
unsigned char* getRegisterPool(int sys, int& size, int& depth);
2022-01-27 00:29:16 -05:00
// get macro interpreter
DivMacroInt* getMacroInt(int chan);
2023-08-24 04:25:38 -04:00
// get channel panning
unsigned short getChanPan(int chan);
// get sample position
DivSamplePos getSamplePos(int chan);
// get osc buffer
DivDispatchOscBuffer* getOscBuffer(int chan);
// enable command stream dumping
void enableCommandStream(bool enable);
// get command stream
void getCommandStream(std::vector<DivCommand>& where);
2021-06-09 04:33:03 -04:00
// set the audio system.
void setAudio(DivAudioEngines which);
// set the view mode.
void setView(DivStatusView which);
2022-02-13 21:42:57 -05:00
// get available audio devices
std::vector<String>& getAudioDevices();
// get available MIDI inputs
std::vector<String>& getMidiIns();
// get available MIDI inputs
std::vector<String>& getMidiOuts();
2022-02-13 21:42:57 -05:00
// rescan audio devices
void rescanAudioDevices();
/** rescan midi devices */
void rescanMidiDevices();
// set the console mode.
void setConsoleMode(bool enable, bool statusOut=true);
2022-08-16 12:24:18 -04:00
2022-01-04 00:02:41 -05:00
// get metronome
bool getMetronome();
// set metronome
void setMetronome(bool enable);
2022-04-13 03:29:07 -04:00
// set metronome volume (1.0 = 100%)
void setMetronomeVol(float vol);
2023-01-03 01:09:46 -05:00
// get buffer position
int getBufferPos();
2022-02-03 18:38:57 -05:00
// halt now
void halt();
// resume from halt
void resume();
// halt on next something
void haltWhen(DivHaltPositions when);
// is engine halted
bool isHalted();
// get register cheatsheet
const char** getRegisterSheet(int sys);
// load sample ROMs
int loadSampleROMs();
// get the sample format mask
unsigned int getSampleFormatMask();
2022-03-19 04:42:44 -04:00
// UNSAFE render samples - only execute when locked
void renderSamples(int whichSample=-1);
2022-03-19 04:42:44 -04:00
// public render samples
// values for whichSample
// -2: don't render anything - just update chip sample memory
// -1: render all samples
// >=0: render specific sample
void renderSamplesP(int whichSample=-1);
2022-04-28 04:36:15 -04:00
// public swap channels
void swapChannelsP(int src, int dest);
// public change song
void changeSongP(size_t index);
// add subsong
int addSubSong();
2023-07-01 00:37:22 -04:00
// duplicate subsong
int duplicateSubSong(int index);
// remove subsong
bool removeSubSong(int index);
2022-06-01 19:50:30 -04:00
// move subsong
void moveSubSongUp(size_t index);
void moveSubSongDown(size_t index);
2022-05-17 02:42:21 -04:00
// clear all subsong data
void clearSubSongs();
2023-09-08 03:52:15 -04:00
// optimize assets
void delUnusedIns();
void delUnusedWaves();
void delUnusedSamples();
2021-12-17 22:14:41 -05:00
// change system
bool changeSystem(int index, DivSystem which, bool preserveOrder=true);
2022-01-08 16:03:32 -05:00
// add system
2022-01-08 18:18:23 -05:00
bool addSystem(DivSystem which);
2022-01-08 16:03:32 -05:00
// duplicate system
bool duplicateSystem(int index, bool pat=true, bool end=false);
2022-01-08 16:03:32 -05:00
// remove system
2022-04-28 04:36:15 -04:00
bool removeSystem(int index, bool preserveOrder=true);
2022-08-19 17:25:32 -04:00
// move system
bool swapSystem(int src, int dest, bool preserveOrder=true);
2022-08-28 11:54:20 -04:00
2023-05-21 05:39:36 -04:00
// add effect
bool addEffect(DivEffectType which);
// remove effect
bool removeEffect(int index);
2022-02-01 18:08:19 -05:00
// write to register on system
void poke(int sys, unsigned int addr, unsigned short val);
// write to register on system
void poke(int sys, std::vector<DivRegWrite>& wlist);
2021-12-17 22:14:41 -05:00
// get last error
String getLastError();
2022-01-29 01:22:32 -05:00
// get warnings
String getWarnings();
2022-08-16 12:24:18 -04:00
2022-10-02 02:02:01 -04:00
// get debug info
String getPlaybackDebugInfo();
2022-01-17 01:42:26 -05:00
// switch master
bool switchMaster(bool full=false);
// set MIDI base channel
void setMidiBaseChan(int chan);
2022-04-01 03:21:10 -04:00
// set MIDI direct channel map
void setMidiDirect(bool value);
// set MIDI direct program change
void setMidiDirectProgram(bool value);
// set MIDI volume curve exponent
void setMidiVolExp(float value);
2022-03-28 16:24:09 -04:00
// set MIDI input callback
2022-03-28 19:19:47 -04:00
// if the specified function returns -2, note feedback will be inhibited.
void setMidiCallback(std::function<int(const TAMidiMessage&)> what);
2022-03-28 16:24:09 -04:00
// send MIDI message
bool sendMidiMessage(TAMidiMessage& msg);
2024-01-25 15:29:37 -05:00
// enable MIDI debug
void setMidiDebug(bool enable);
2022-03-19 04:42:44 -04:00
// perform secure/sync operation
void synchronized(const std::function<void()>& what);
// perform secure/sync song operation
void lockSave(const std::function<void()>& what);
// perform secure/sync song operation (and lock audio too)
void lockEngine(const std::function<void()>& what);
2022-02-05 21:26:24 -05:00
// get audio desc want
TAAudioDesc& getAudioDescWant();
// get audio desc
TAAudioDesc& getAudioDescGot();
2021-12-13 14:51:35 -05:00
// init dispatch
2023-08-18 02:40:18 -04:00
void initDispatch(bool isRender=false);
2021-12-13 14:51:35 -05:00
// quit dispatch
void quitDispatch();
// pre-pre-initialize the engine.
bool prePreInit();
// pre-initialize the engine. returns whether Furnace should run in safe mode.
bool preInit(bool noSafeMode=true);
2022-12-18 01:55:21 -05:00
// initialize the engine.
bool init();
// confirm that the engine is running (delete safe mode file).
void everythingOK();
2021-12-13 17:09:46 -05:00
// terminate the engine.
2024-03-14 03:06:36 -04:00
bool quit(bool saveConfig=true);
2021-12-13 17:09:46 -05:00
unsigned char* yrw801ROM;
unsigned char* tg100ROM;
unsigned char* mu5ROM;
DivEngine():
output(NULL),
exportThread(NULL),
chans(0),
configLoaded(false),
active(false),
2022-01-17 01:42:26 -05:00
lowQuality(false),
dcHiPass(true),
playing(false),
2021-12-28 18:23:57 -05:00
freelance(false),
2022-09-29 01:27:40 -04:00
shallStop(false),
2022-10-22 04:46:39 -04:00
shallStopSched(false),
endOfSong(false),
consoleMode(false),
disableStatusOut(false),
extValuePresent(false),
repeatPattern(false),
2022-01-04 00:02:41 -05:00
metronome(false),
exporting(false),
stopExport(false),
2022-02-03 18:38:57 -05:00
halted(false),
forceMono(false),
cmdStreamEnabled(false),
softLocked(false),
firstTick(false),
2022-03-31 04:33:05 -04:00
skipping(false),
2022-04-01 03:21:10 -04:00
midiIsDirect(false),
midiIsDirectProgram(false),
lowLatency(false),
systemsRegistered(false),
hasLoadedSomething(false),
2022-09-26 02:27:36 -04:00
midiOutClock(false),
2023-05-10 03:57:59 -04:00
midiOutTime(false),
midiOutProgramChange(false),
2022-09-26 02:27:36 -04:00
midiOutMode(DIV_MIDI_MODE_NOTE),
2023-05-10 03:57:59 -04:00
midiOutTimeRate(0),
midiVolExp(2.0f), // General MIDI standard
2022-03-23 23:05:09 -04:00
softLockCount(0),
subticks(0),
ticks(0),
curRow(0),
curOrder(0),
prevRow(0),
prevOrder(0),
remainingLoops(-1),
2022-06-06 04:05:55 -04:00
totalLoops(0),
lastLoopPos(0),
exportLoopCount(0),
nextSpeed(3),
2022-11-10 01:26:59 -05:00
elapsedBars(0),
elapsedBeats(0),
2023-02-05 02:56:39 -05:00
curSpeed(0),
curSubSongIndex(0),
2023-01-03 01:09:46 -05:00
bufferPos(0),
divider(60),
cycles(0),
clockDrift(0),
2023-05-09 06:05:53 -04:00
midiClockCycles(0),
midiClockDrift(0),
midiTimeCycles(0),
midiTimeDrift(0),
2022-02-06 00:42:07 -05:00
stepPlay(0),
changeOrd(-1),
changePos(0),
totalSeconds(0),
totalTicks(0),
totalTicksR(0),
2023-05-09 23:12:14 -04:00
curMidiClock(0),
curMidiTime(0),
totalCmds(0),
lastCmds(0),
cmdsPerSecond(0),
2022-04-14 19:25:59 -04:00
globalPitch(0),
2023-05-10 03:57:59 -04:00
curMidiTimePiece(0),
curMidiTimeCode(0),
extValue(0),
2022-11-09 23:52:10 -05:00
pendingMetroTick(0),
2024-03-15 15:56:55 -04:00
virtualTempoN(150),
virtualTempoD(150),
2022-05-18 01:05:25 -04:00
tempoAccum(0),
2021-12-13 17:09:46 -05:00
view(DIV_STATUS_NOTHING),
2022-02-03 18:38:57 -05:00
haltOn(DIV_HALT_NONE),
2022-01-22 23:50:49 -05:00
audioEngine(DIV_AUDIO_NULL),
2022-04-14 19:25:59 -04:00
exportMode(DIV_EXPORT_MODE_ONE),
2024-05-11 15:25:53 -04:00
exportFormat(DIV_EXPORT_FORMAT_S16),
2022-06-06 04:05:55 -04:00
exportFadeOut(0.0),
exportOutputs(2),
cmdStreamInt(NULL),
midiBaseChan(0),
2022-06-03 19:05:07 -04:00
midiPoly(true),
2024-01-25 15:29:37 -05:00
midiDebug(false),
midiAgeCounter(0),
2022-04-14 19:25:59 -04:00
samp_bb(NULL),
2022-01-08 16:03:32 -05:00
samp_bbInLen(0),
samp_temp(0),
samp_prevSample(0),
2022-04-14 19:25:59 -04:00
samp_bbIn(NULL),
samp_bbOut(NULL),
2022-01-04 00:02:41 -05:00
metroTick(NULL),
metroTickLen(0),
metroBuf(NULL),
metroBufLen(0),
2022-01-04 00:29:59 -05:00
metroFreq(0),
2022-01-04 00:02:41 -05:00
metroPos(0),
metroAmp(0.0f),
2022-04-13 03:29:07 -04:00
metroVol(1.0f),
previewVol(1.0f),
2021-12-10 04:22:13 -05:00
totalProcessed(0),
2023-09-06 15:23:47 -04:00
renderPoolThreads(0),
renderPool(NULL),
curOrders(NULL),
curPat(NULL),
tempIns(NULL),
2022-01-27 17:49:00 -05:00
oscSize(1),
oscReadPos(0),
oscWritePos(0),
tickMult(1),
2023-07-06 19:29:29 -04:00
lastNBIns(0),
lastNBOuts(0),
lastNBSize(0),
processTime(0),
yrw801ROM(NULL),
tg100ROM(NULL),
mu5ROM(NULL) {
2022-04-14 19:25:59 -04:00
memset(isMuted,0,DIV_MAX_CHANS*sizeof(bool));
memset(keyHit,0,DIV_MAX_CHANS*sizeof(bool));
memset(dispatchFirstChan,0,DIV_MAX_CHANS*sizeof(int));
2022-04-14 19:25:59 -04:00
memset(dispatchChanOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(dispatchOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(vibTable,0,64*sizeof(short));
2023-02-04 16:08:20 -05:00
memset(tremTable,0,128*sizeof(short));
2022-04-14 19:25:59 -04:00
memset(reversePitchTable,0,4096*sizeof(int));
memset(pitchTable,0,4096*sizeof(int));
2023-05-21 05:39:36 -04:00
memset(effectSlotMap,-1,4096*sizeof(short));
memset(sysDefs,0,DIV_MAX_CHIP_DEFS*sizeof(void*));
2022-09-10 02:39:42 -04:00
memset(walked,0,8192);
memset(oscBuf,0,DIV_MAX_OUTPUTS*(sizeof(float*)));
2024-05-11 15:25:53 -04:00
memset(exportChannelMask,1,DIV_MAX_CHANS*sizeof(bool));
for (int i=0; i<DIV_MAX_CHIP_DEFS; i++) {
sysFileMapFur[i]=DIV_SYSTEM_NULL;
sysFileMapDMF[i]=DIV_SYSTEM_NULL;
}
changeSong(0);
2022-04-14 19:25:59 -04:00
}
};
#endif