furnace/src/engine/engine.h
tildearrow c009cb3536 dev112 - prepare for advanced arp macro
this new advanced arp macro offers more flexibility and reduces code duplication
it allows you to set each step of the macro to either relative or fixed mode
(instead of just one mode for the entire macro)

the UI is still a work in progress and doesn't work well

this change is big and may break things! further fixes incoming
2022-08-22 15:59:45 -05:00

1082 lines
28 KiB
C++

/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors
*
* 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 "instrument.h"
#include "song.h"
#include "dispatch.h"
#include "dataErrors.h"
#include "safeWriter.h"
#include "../audio/taAudio.h"
#include "blip_buf.h"
#include <atomic>
#include <functional>
#include <initializer_list>
#include <thread>
#include <mutex>
#include <map>
#include <unordered_map>
#include <queue>
#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;
#define DIV_VERSION "dev112"
#define DIV_ENGINE_VERSION 112
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
// "Namco C163"
#define DIV_C163_DEFAULT_NAME "Namco 163"
enum DivStatusView {
DIV_STATUS_NOTHING=0,
DIV_STATUS_PATTERN,
DIV_STATUS_COMMANDS
};
enum DivAudioEngines {
DIV_AUDIO_JACK=0,
DIV_AUDIO_SDL=1,
DIV_AUDIO_NULL=126,
DIV_AUDIO_DUMMY=127
};
enum DivAudioExportModes {
DIV_EXPORT_MODE_ONE=0,
DIV_EXPORT_MODE_MANY_SYS,
DIV_EXPORT_MODE_MANY_CHAN
};
enum DivHaltPositions {
DIV_HALT_NONE=0,
DIV_HALT_TICK,
DIV_HALT_ROW,
DIV_HALT_PATTERN,
DIV_HALT_BREAKPOINT
};
struct DivChannelState {
std::vector<DivDelayedCommand> delayed;
int note, oldNote, lastIns, pitch, portaSpeed, portaNote;
int volume, volSpeed, cut, rowDelay, volMax;
int delayOrder, delayRow, retrigSpeed, retrigTick;
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine;
int tremoloDepth, tremoloRate, tremoloPos;
unsigned char arp, arpStage, arpTicks, panL, panR;
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp;
int midiNote, curMidiNote, midiPitch;
size_t midiAge;
bool midiAftertouch;
DivChannelState():
note(-1),
oldNote(-1),
lastIns(-1),
pitch(0),
portaSpeed(-1),
portaNote(-1),
volume(0x7f00),
volSpeed(0),
cut(-1),
rowDelay(0),
volMax(0),
delayOrder(0),
delayRow(0),
retrigSpeed(0),
retrigTick(0),
vibratoDepth(0),
vibratoRate(0),
vibratoPos(0),
vibratoPosGiant(0),
vibratoDir(0),
vibratoFine(15),
tremoloDepth(0),
tremoloRate(0),
tremoloPos(0),
arp(0),
arpStage(-1),
arpTicks(1),
panL(255),
panR(255),
doNote(false),
legato(false),
portaStop(false),
keyOn(false),
keyOff(false),
nowYouCanStop(true),
stopOnOff(false),
arpYield(false),
delayLocked(false),
inPorta(false),
scheduledSlideReset(false),
shorthandPorta(false),
wasShorthandPorta(false),
noteOnInhibit(false),
resetArp(false),
midiNote(-1),
curMidiNote(-1),
midiPitch(-1),
midiAge(0),
midiAftertouch(false) {}
};
struct DivNoteEvent {
int channel, ins, note, volume;
bool on;
DivNoteEvent(int c, int i, int n, int v, bool o):
channel(c),
ins(i),
note(n),
volume(v),
on(o) {}
};
struct DivDispatchContainer {
DivDispatch* dispatch;
blip_buffer_t* bb[2];
size_t bbInLen, runtotal, runLeft, runPos, lastAvail;
int temp[2], prevSample[2];
short* bbIn[2];
short* bbOut[2];
bool lowQuality, dcOffCompensation;
void setRates(double gotRate);
void setQuality(bool lowQual);
void acquire(size_t offset, size_t count);
void flush(size_t count);
void fillBuf(size_t runtotal, size_t offset, size_t size);
void clear();
void init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, unsigned int flags);
void quit();
DivDispatchContainer():
dispatch(NULL),
bb{NULL,NULL},
bbInLen(0),
runtotal(0),
runLeft(0),
runPos(0),
lastAvail(0),
temp{0,0},
prevSample{0,0},
bbIn{NULL,NULL},
bbOut{NULL,NULL},
lowQuality(false),
dcOffCompensation(false) {}
};
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;
unsigned int vgmVersion;
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;
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, 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_={}):
name(sysName),
nameJ(sysNameJ),
description(desc),
id(fileID),
id_DMF(fileID_DMF),
channels(chans),
isFM(isFMChip),
isSTD(isSTDChip),
isCompound(compound),
vgmVersion(vgmVer),
effectHandlers(fxHandlers_),
postEffectHandlers(postFxHandlers_) {
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
};
extern const char* cmdName[];
class DivEngine {
DivDispatchContainer disCont[32];
TAAudio* output;
TAAudioDesc want, got;
String exportPath;
std::thread* exportThread;
int chans;
bool active;
bool lowQuality;
bool playing;
bool freelance;
bool speedAB;
bool endOfSong;
bool consoleMode;
bool extValuePresent;
bool repeatPattern;
bool metronome;
bool exporting;
bool stopExport;
bool halted;
bool forceMono;
bool clampSamples;
bool cmdStreamEnabled;
bool softLocked;
bool firstTick;
bool skipping;
bool midiIsDirect;
bool lowLatency;
bool systemsRegistered;
bool hasLoadedSomething;
int softLockCount;
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed;
size_t curSubSongIndex;
double divider;
int cycles;
double clockDrift;
int stepPlay;
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
unsigned char extValue;
unsigned char speed1, speed2;
short tempoAccum;
DivStatusView view;
DivHaltPositions haltOn;
DivChannelState chan[DIV_MAX_CHANS];
DivAudioEngines audioEngine;
DivAudioExportModes exportMode;
double exportFadeOut;
std::map<String,String> conf;
std::queue<DivNoteEvent> pendingNotes;
bool isMuted[DIV_MAX_CHANS];
std::mutex isBusy, saveLock;
String configPath;
String configFile;
String lastError;
String warnings;
std::vector<String> audioDevs;
std::vector<String> midiIns;
std::vector<String> midiOuts;
std::vector<DivCommand> cmdStream;
std::vector<DivInstrumentType> possibleInsTypes;
DivSysDef* sysDefs[256];
DivSystem sysFileMapFur[256];
DivSystem sysFileMapDMF[256];
struct SamplePreview {
int sample;
int wave;
unsigned int pos;
int pBegin, pEnd;
SamplePreview():
sample(-1),
wave(-1),
pos(0),
pBegin(-1),
pEnd(-1) {}
} sPreview;
short vibTable[64];
int reversePitchTable[4096];
int pitchTable[4096];
char c163NameCS[1024];
int midiBaseChan;
bool midiPoly;
size_t midiAgeCounter;
blip_buffer_t* samp_bb;
size_t samp_bbInLen;
int samp_temp, samp_prevSample;
short* samp_bbIn;
short* samp_bbOut;
unsigned char* metroTick;
size_t metroTickLen;
float metroFreq, metroPos;
float metroAmp;
float metroVol;
size_t totalProcessed;
// MIDI stuff
std::function<int(const TAMidiMessage&)> midiCallback=[](const TAMidiMessage&) -> int {return -2;};
DivSystem systemFromFileFur(unsigned char val);
unsigned char systemToFileFur(DivSystem val);
DivSystem systemFromFileDMF(unsigned char val);
unsigned char systemToFileDMF(DivSystem val);
int dispatchCmd(DivCommand c);
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);
// 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);
void recalcChans();
void reset();
void playSub(bool preserveDrift, int goalRow=0);
bool loadDMF(unsigned char* file, size_t len);
bool loadFur(unsigned char* file, size_t len);
bool loadMod(unsigned char* file, size_t len);
bool loadFTM(unsigned char* file, size_t len);
bool loadFC(unsigned char* file, size_t len);
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);
void loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadGYB(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadWOPL(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
void loadWOPN(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
int loadSampleROM(String path, ssize_t expectedSize, unsigned char*& ret);
bool initAudioBackend();
bool deinitAudioBackend();
void registerSystems();
void initSongWithDesc(const int* description);
void exchangeIns(int one, int two);
void swapChannels(int src, int dest);
void stompChannel(int ch);
// change song (UNSAFE)
void changeSong(size_t songIndex);
public:
DivSong song;
DivOrders* curOrders;
DivChannelData* curPat;
DivSubSong* curSubSong;
DivInstrument* tempIns;
DivSystem sysOfChan[DIV_MAX_CHANS];
int dispatchOfChan[DIV_MAX_CHANS];
int dispatchChanOfChan[DIV_MAX_CHANS];
bool keyHit[DIV_MAX_CHANS];
float* oscBuf[2];
float oscSize;
int oscReadPos, oscWritePos;
int tickMult;
std::atomic<size_t> processTime;
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);
DivSample* getSample(int index);
DivDispatch* getDispatch(int index);
// parse system setup description
String encodeSysDesc(std::vector<int>& desc);
std::vector<int> decodeSysDesc(String desc);
// start fresh
void createNew(const int* description, String sysName);
// load a file.
bool load(unsigned char* f, size_t length);
// save as .dmf.
SafeWriter* saveDMF(unsigned char version);
// save as .fur.
// if notPrimary is true then the song will not be altered
SafeWriter* saveFur(bool notPrimary=false);
// build a ROM file (TODO).
// specify system to build ROM for.
SafeWriter* buildROM(int sys);
// dump to VGM.
SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false);
// dump command stream.
SafeWriter* saveCommand(bool binary=false);
// export to an audio file
bool saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime=0.0);
// wait for audio export to finish
void waitAudioFile();
// stop audio file export
bool haltAudioFile();
// notify instrument parameter change
void notifyInsChange(int ins);
// notify wavetable change
void notifyWaveChange(int wave);
// 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();
// 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);
// 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);
void setConf(String key, String value);
// calculate base frequency/period
double calcBaseFreq(double clock, double divider, int note, bool period);
// calculate base frequency in f-num/block format
int calcBaseFreqFNumBlock(double clock, double divider, int note, int bits);
// calculate frequency/period
int calcFreq(int base, int pitch, 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);
int convertPanSplitToLinearLR(unsigned char left, unsigned char right, int range);
unsigned int convertPanLinearToSplit(int val, unsigned char bits, int range);
// find song loop position
void walkSong(int& loopOrder, int& loopRow, int& loopEnd);
// play
void play();
// play to row
void playToRow(int row);
// play by one row
void stepOne(int row);
// stop
void stop();
// reset playback state
void syncReset();
// trigger sample preview
void previewSample(int sample, int note=-1, int pStart=-1, int pEnd=-1);
void stopSamplePreview();
// trigger wave preview
void previewWave(int wave, int note);
void stopWavePreview();
// get config path
String getConfigPath();
// get sys channel count
int getChannelCount(DivSystem sys);
// get channel count
int getTotalChannelCount();
// get instrument types available for use
std::vector<DivInstrumentType>& getPossibleInsTypes();
// get effect description
const char* getEffectDesc(unsigned char effect, int chan, bool notNull=false);
// get channel type
// - 0: FM
// - 1: pulse
// - 2: noise
// - 3: wave/other
// - 4: PCM
// - 5: FM operator
int getChannelType(int ch);
// 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);
// get sys name
const char* getSystemName(DivSystem sys);
// get japanese system name
const char* getSystemNameJ(DivSystem sys);
// convert sample rate format
int fileToDivRate(int frate);
int divToFileRate(int drate);
// get effective sample rate
int getEffectiveSampleRate(int rate);
// is FM system
bool isFMSystem(DivSystem sys);
// is STD system
bool isSTDSystem(DivSystem sys);
// 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();
// get channel name
const char* getChannelName(int chan);
// get channel short name
const char* getChannelShortName(int chan);
// get channel max volume
int getMaxVolumeChan(int chan);
// get current order
unsigned char getOrder();
// get current row
int getRow();
// get current subsong
size_t getCurrentSubSong();
// get speed 1
unsigned char getSpeed1();
// get speed 2
unsigned char getSpeed2();
// get Hz
float getHz();
// get current Hz
float getCurHz();
// get time
int getTotalTicks(); // 1/1000000th of a second
int getTotalSeconds();
// get repeat pattern
bool getRepeatPattern();
// set repeat pattern
void setRepeatPattern(bool value);
// has ext value
bool hasExtValue();
// get ext value
unsigned char getExtValue();
// is playing
bool isPlaying();
// is running
bool isRunning();
// is stepping
bool isStepping();
// is exporting
bool isExporting();
// add instrument
int addInstrument(int refChan=0);
// 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);
// load temporary instrument
void loadTempIns(DivInstrument* which);
// delete instrument
void delInstrument(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);
// delete wavetable
void delWave(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);
// delete sample
void delSample(int index);
// add order
void addOrder(bool duplicate, bool where);
// deep clone orders
void deepCloneOrder(bool where);
// delete order
void deleteOrder();
// move order up
void moveOrderUp();
// move order down
void moveOrderDown();
// 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);
// play note
void noteOn(int chan, int ins, int note, int vol=-1);
// stop note
void noteOff(int chan);
void autoNoteOn(int chan, int ins, int note, int vol=-1);
void autoNoteOff(int chan, int note, int vol=-1);
void autoNoteOffAll();
// set whether autoNoteIn is mono or poly
void setAutoNotePoly(bool poly);
// go to order
void setOrder(unsigned char order);
// set system flags
void setSysFlags(int system, unsigned int flags, bool restart);
// set Hz
void setSongRate(float hz, bool pal);
// set remaining loops. -1 means loop forever.
void setLoops(int loops);
// get channel state
DivChannelState* getChanState(int chan);
// get dispatch channel state
void* getDispatchChanState(int chan);
// get register pool
unsigned char* getRegisterPool(int sys, int& size, int& depth);
// get macro interpreter
DivMacroInt* getMacroInt(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);
// set the audio system.
void setAudio(DivAudioEngines which);
// set the view mode.
void setView(DivStatusView which);
// get available audio devices
std::vector<String>& getAudioDevices();
// get available MIDI inputs
std::vector<String>& getMidiIns();
// get available MIDI inputs
std::vector<String>& getMidiOuts();
// rescan audio devices
void rescanAudioDevices();
// set the console mode.
void setConsoleMode(bool enable);
// get metronome
bool getMetronome();
// set metronome
void setMetronome(bool enable);
// set metronome volume (1.0 = 100%)
void setMetronomeVol(float vol);
// 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();
// UNSAFE render samples - only execute when locked
void renderSamples();
// public render samples
void renderSamplesP();
// public swap channels
void swapChannelsP(int src, int dest);
// public change song
void changeSongP(size_t index);
// add subsong
int addSubSong();
// remove subsong
bool removeSubSong(int index);
// move subsong
void moveSubSongUp(size_t index);
void moveSubSongDown(size_t index);
// clear all subsong data
void clearSubSongs();
// change system
void changeSystem(int index, DivSystem which, bool preserveOrder=true);
// add system
bool addSystem(DivSystem which);
// remove system
bool removeSystem(int index, bool preserveOrder=true);
// move system
bool swapSystem(int src, int dest, bool preserveOrder=true);
// 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);
// get last error
String getLastError();
// get warnings
String getWarnings();
// switch master
bool switchMaster();
// set MIDI base channel
void setMidiBaseChan(int chan);
// set MIDI direct channel map
void setMidiDirect(bool value);
// set MIDI input callback
// if the specified function returns -2, note feedback will be inhibited.
void setMidiCallback(std::function<int(const TAMidiMessage&)> what);
// send MIDI message
bool sendMidiMessage(TAMidiMessage& msg);
// 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);
// get audio desc want
TAAudioDesc& getAudioDescWant();
// get audio desc
TAAudioDesc& getAudioDescGot();
// init dispatch
void initDispatch();
// quit dispatch
void quitDispatch();
// initialize the engine.
bool init();
// terminate the engine.
bool quit();
unsigned char* yrw801ROM;
unsigned char* tg100ROM;
unsigned char* mu5ROM;
DivEngine():
output(NULL),
exportThread(NULL),
chans(0),
active(false),
lowQuality(false),
playing(false),
freelance(false),
speedAB(false),
endOfSong(false),
consoleMode(false),
extValuePresent(false),
repeatPattern(false),
metronome(false),
exporting(false),
stopExport(false),
halted(false),
forceMono(false),
cmdStreamEnabled(false),
softLocked(false),
firstTick(false),
skipping(false),
midiIsDirect(false),
lowLatency(false),
systemsRegistered(false),
hasLoadedSomething(false),
softLockCount(0),
subticks(0),
ticks(0),
curRow(0),
curOrder(0),
prevRow(0),
prevOrder(0),
remainingLoops(-1),
totalLoops(0),
lastLoopPos(0),
exportLoopCount(0),
nextSpeed(3),
curSubSongIndex(0),
divider(60),
cycles(0),
clockDrift(0),
stepPlay(0),
changeOrd(-1),
changePos(0),
totalSeconds(0),
totalTicks(0),
totalTicksR(0),
totalCmds(0),
lastCmds(0),
cmdsPerSecond(0),
globalPitch(0),
extValue(0),
speed1(3),
speed2(3),
tempoAccum(0),
view(DIV_STATUS_NOTHING),
haltOn(DIV_HALT_NONE),
audioEngine(DIV_AUDIO_NULL),
exportMode(DIV_EXPORT_MODE_ONE),
exportFadeOut(0.0),
midiBaseChan(0),
midiPoly(true),
midiAgeCounter(0),
samp_bb(NULL),
samp_bbInLen(0),
samp_temp(0),
samp_prevSample(0),
samp_bbIn(NULL),
samp_bbOut(NULL),
metroTick(NULL),
metroTickLen(0),
metroFreq(0),
metroPos(0),
metroAmp(0.0f),
metroVol(1.0f),
totalProcessed(0),
curOrders(NULL),
curPat(NULL),
tempIns(NULL),
oscBuf{NULL,NULL},
oscSize(1),
oscReadPos(0),
oscWritePos(0),
tickMult(1),
processTime(0),
yrw801ROM(NULL),
tg100ROM(NULL),
mu5ROM(NULL) {
memset(isMuted,0,DIV_MAX_CHANS*sizeof(bool));
memset(keyHit,0,DIV_MAX_CHANS*sizeof(bool));
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));
memset(reversePitchTable,0,4096*sizeof(int));
memset(pitchTable,0,4096*sizeof(int));
memset(sysDefs,0,256*sizeof(void*));
for (int i=0; i<256; i++) {
sysFileMapFur[i]=DIV_SYSTEM_NULL;
sysFileMapDMF[i]=DIV_SYSTEM_NULL;
}
changeSong(0);
}
};
#endif