furnace/src/engine/engine.h

473 lines
10 KiB
C
Raw Normal View History

#ifndef _ENGINE_H
#define _ENGINE_H
#include "song.h"
#include "dispatch.h"
#include "safeWriter.h"
#include "../audio/taAudio.h"
#include "blip_buf.h"
2021-12-11 08:34:43 +00:00
#include <mutex>
2021-12-19 21:52:04 +00:00
#include <map>
2021-12-28 23:23:57 +00:00
#include <queue>
2022-01-16 09:23:23 +00:00
#define DIV_VERSION "0.4"
#define DIV_ENGINE_VERSION 20
2021-12-16 07:21:43 +00:00
enum DivStatusView {
DIV_STATUS_NOTHING=0,
DIV_STATUS_PATTERN,
DIV_STATUS_COMMANDS
};
2021-06-09 08:33:03 +00:00
enum DivAudioEngines {
DIV_AUDIO_JACK=0,
2022-01-16 22:25:43 +00:00
DIV_AUDIO_SDL=1
2021-06-09 08:33:03 +00:00
};
struct DivChannelState {
std::vector<DivDelayedCommand> delayed;
int note, oldNote, pitch, portaSpeed, portaNote;
int volume, volSpeed, cut, rowDelay, volMax;
int delayOrder, delayRow;
2021-05-18 08:02:47 +00:00
int vibratoDepth, vibratoRate, vibratoPos, vibratoDir, vibratoFine;
int tremoloDepth, tremoloRate, tremoloPos;
2021-05-18 07:53:59 +00:00
unsigned char arp, arpStage, arpTicks;
2021-12-19 05:27:04 +00:00
bool doNote, legato, portaStop, keyOn, nowYouCanStop, stopOnOff, arpYield, delayLocked, inPorta;
2021-05-14 08:23:40 +00:00
DivChannelState():
note(-1),
oldNote(-1),
2021-05-14 08:23:40 +00:00
pitch(0),
portaSpeed(-1),
portaNote(-1),
volume(0x7f00),
volSpeed(0),
cut(-1),
rowDelay(0),
2021-12-16 20:51:19 +00:00
volMax(0),
delayOrder(0),
delayRow(0),
2021-05-14 08:23:40 +00:00
vibratoDepth(0),
vibratoRate(0),
vibratoPos(0),
vibratoDir(0),
2021-05-18 08:02:47 +00:00
vibratoFine(15),
2021-05-14 08:23:40 +00:00
tremoloDepth(0),
tremoloRate(0),
tremoloPos(0),
arp(0),
arpStage(-1),
2021-05-18 07:53:59 +00:00
arpTicks(1),
doNote(false),
legato(false),
portaStop(false),
keyOn(false),
nowYouCanStop(true),
stopOnOff(false),
arpYield(false),
2021-12-19 05:27:04 +00:00
delayLocked(false),
inPorta(false) {}
};
2021-12-28 23:23:57 +00:00
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;
int temp[2], prevSample[2];
short* bbIn[2];
short* bbOut[2];
2022-01-08 21:03:32 +00:00
void setRates(double gotRate);
void acquire(size_t offset, size_t count);
void fillBuf(size_t runtotal, size_t size);
2022-01-08 21:03:32 +00:00
void clear();
void init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, bool pal);
void quit();
DivDispatchContainer():
dispatch(NULL),
bb{NULL,NULL},
bbInLen(0),
temp{0,0},
prevSample{0,0},
bbIn{NULL,NULL},
bbOut{NULL,NULL} {}
};
class DivEngine {
2022-01-08 21:03:32 +00:00
DivDispatchContainer disCont[32];
TAAudio* output;
TAAudioDesc want, got;
int chans;
bool active;
bool playing;
2021-12-28 23:23:57 +00:00
bool freelance;
bool speedAB;
bool endOfSong;
bool consoleMode;
bool extValuePresent;
bool repeatPattern;
2022-01-04 05:02:41 +00:00
bool metronome;
int ticks, curRow, curOrder, remainingLoops, nextSpeed, divider;
int cycles, clockDrift;
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
unsigned char extValue;
2021-12-21 07:30:09 +00:00
unsigned char speed1, speed2;
DivStatusView view;
2022-01-08 06:57:37 +00:00
DivChannelState chan[DIV_MAX_CHANS];
2021-06-09 08:33:03 +00:00
DivAudioEngines audioEngine;
2021-12-19 21:52:04 +00:00
std::map<String,String> conf;
2021-12-28 23:23:57 +00:00
std::queue<DivNoteEvent> pendingNotes;
2022-01-08 06:57:37 +00:00
bool isMuted[DIV_MAX_CHANS];
2022-01-08 21:03:32 +00:00
DivSystem sysOfChan[DIV_MAX_CHANS];
int dispatchOfChan[DIV_MAX_CHANS];
int dispatchChanOfChan[DIV_MAX_CHANS];
2021-12-11 08:34:43 +00:00
std::mutex isBusy;
2021-12-19 08:16:24 +00:00
String configPath;
2021-12-19 21:52:04 +00:00
String configFile;
String lastError;
struct SamplePreview {
int sample;
unsigned int pos;
SamplePreview():
sample(-1),
pos(0) {}
} sPreview;
short vibTable[64];
2022-01-08 21:03:32 +00:00
blip_buffer_t* samp_bb;
size_t samp_bbInLen;
int samp_temp, samp_prevSample;
short* samp_bbIn;
short* samp_bbOut;
2022-01-04 05:02:41 +00:00
unsigned char* metroTick;
size_t metroTickLen;
2022-01-04 05:29:59 +00:00
float metroFreq, metroPos;
2022-01-04 05:02:41 +00:00
float metroAmp;
2021-12-08 07:57:41 +00:00
size_t totalProcessed;
2021-12-10 09:22:13 +00:00
private: int* jediTable;
int dispatchCmd(DivCommand c);
void processRow(int i, bool afterDelay);
void nextOrder();
void nextRow();
// returns true if end of song.
2021-12-21 07:30:09 +00:00
bool nextTick(bool noAccum=false);
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
2022-01-08 21:03:32 +00:00
void recalcChans();
void renderSamples();
void reset();
2021-12-21 07:02:25 +00:00
void playSub(bool preserveDrift);
bool loadDMF(unsigned char* file, size_t len);
bool loadFur(unsigned char* file, size_t len);
public:
2021-05-12 22:19:18 +00:00
DivSong song;
void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size);
DivInstrument* getIns(int index);
DivWavetable* getWave(int index);
2021-12-24 23:23:01 +00:00
// start fresh
void createNew();
// load a file.
2021-12-16 07:21:43 +00:00
bool load(unsigned char* f, size_t length);
// save as .dmf.
SafeWriter* saveDMF();
// save as .fur.
SafeWriter* saveFur();
2021-12-19 21:52:04 +00: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);
// 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 frequency/period
int calcFreq(int base, int pitch, bool period=false);
// play
void play();
2021-12-11 08:34:43 +00:00
// stop
void stop();
// reset playback state
void syncReset();
// trigger sample preview
void previewSample(int sample);
2021-12-19 08:16:24 +00:00
// get config path
String getConfigPath();
// get sys channel count
int getChannelCount(DivSystem sys);
2022-01-08 06:57:37 +00:00
// get channel count
int getTotalChannelCount();
2021-12-23 22:09:33 +00:00
// get channel type
// - 0: FM
// - 1: pulse
// - 2: noise
// - 3: wave/other
// - 4: PCM
// - 5: FM operator
int getChannelType(int ch);
2022-01-16 03:11:40 +00:00
// get preferred instrument type
DivInstrumentType getPreferInsType(int ch);
2021-12-15 22:32:08 +00:00
// get sys name
const char* getSystemName(DivSystem sys);
// convert sample rate format
int fileToDivRate(int frate);
int divToFileRate(int drate);
// get effective sample rate
int getEffectiveSampleRate(int rate);
2021-12-15 22:32:08 +00:00
// is FM system
bool isFMSystem(DivSystem sys);
2021-12-18 03:14:41 +00:00
// is STD system
bool isSTDSystem(DivSystem sys);
2021-12-18 08:25:42 +00: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);
2021-12-13 18:10:56 +00:00
// get channel name
const char* getChannelName(int chan);
// get channel short name
const char* getChannelShortName(int chan);
2021-12-13 22:09:46 +00:00
// get channel max volume
int getMaxVolumeChan(int chan);
2021-12-11 08:34:43 +00:00
// get current order
unsigned char getOrder();
2021-12-13 22:09:46 +00:00
// get current row
int getRow();
2021-12-21 07:30:09 +00:00
// get speed 1
unsigned char getSpeed1();
// get speed 2
unsigned char getSpeed2();
// get Hz
int getHz();
// get current Hz
int getCurHz();
2021-12-21 07:30:09 +00:00
// get time
int getTotalTicks(); // 1/1000000th of a second
int getTotalSeconds();
2021-12-21 07:30:09 +00:00
// get repeat pattern
bool getRepeatPattern();
// set repeat pattern
void setRepeatPattern(bool value);
// has ext value
bool hasExtValue();
// get ext value
unsigned char getExtValue();
2021-12-13 22:09:46 +00:00
// is playing
bool isPlaying();
// add instrument
2022-01-10 04:50:26 +00:00
int addInstrument(int refChan=0);
// delete instrument
void delInstrument(int index);
// add wavetable
int addWave();
2022-01-11 21:25:55 +00:00
// add wavetable from file
bool addWaveFromFile(const char* path);
// delete wavetable
void delWave(int index);
// add sample
int addSample();
// add sample from file
bool addSampleFromFile(const char* path);
// delete sample
void delSample(int index);
2021-12-22 22:39:16 +00:00
// add order
void addOrder(bool duplicate, 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);
2021-12-28 23:23:57 +00:00
// play note
void noteOn(int chan, int ins, int note, int vol=-1);
// stop note
void noteOff(int chan);
2021-12-11 08:34:43 +00:00
// go to order
void setOrder(unsigned char order);
2021-12-15 22:32:08 +00:00
// set Hz
void setSongRate(int hz, bool pal);
// set remaining loops. -1 means loop forever.
void setLoops(int loops);
2021-06-09 08:33:03 +00:00
// set the audio system.
void setAudio(DivAudioEngines which);
// set the view mode.
void setView(DivStatusView which);
// set the console mode.
void setConsoleMode(bool enable);
2022-01-04 05:02:41 +00:00
// get metronome
bool getMetronome();
// set metronome
void setMetronome(bool enable);
// public render samples
void renderSamplesP();
2021-12-18 03:14:41 +00:00
// change system
2022-01-08 21:03:32 +00:00
void changeSystem(int index, DivSystem which);
// add system
2022-01-08 23:18:23 +00:00
bool addSystem(DivSystem which);
2022-01-08 21:03:32 +00:00
// remove system
2022-01-08 23:18:23 +00:00
bool removeSystem(int index);
2021-12-18 03:14:41 +00:00
// get last error
String getLastError();
2021-12-13 19:51:35 +00:00
// init dispatch
void initDispatch();
// quit dispatch
void quitDispatch();
2021-12-07 09:32:42 +00:00
// initialize the engine. optionally provide an output file name.
bool init(String outName="");
2021-12-13 22:09:46 +00:00
// terminate the engine.
bool quit();
2021-12-11 04:41:00 +00:00
unsigned char* adpcmMem;
DivEngine():
chans(0),
active(false),
playing(false),
2021-12-28 23:23:57 +00:00
freelance(false),
speedAB(false),
endOfSong(false),
consoleMode(false),
extValuePresent(false),
repeatPattern(false),
2022-01-04 05:02:41 +00:00
metronome(false),
ticks(0),
curRow(0),
curOrder(0),
remainingLoops(-1),
nextSpeed(3),
divider(60),
cycles(0),
clockDrift(0),
changeOrd(-1),
changePos(0),
totalSeconds(0),
totalTicks(0),
totalTicksR(0),
totalCmds(0),
lastCmds(0),
cmdsPerSecond(0),
extValue(0),
2021-12-21 07:30:09 +00:00
speed1(3),
speed2(3),
2021-12-13 22:09:46 +00:00
view(DIV_STATUS_NOTHING),
2021-06-09 08:33:03 +00:00
audioEngine(DIV_AUDIO_SDL),
2022-01-08 21:03:32 +00:00
samp_bbInLen(0),
samp_temp(0),
samp_prevSample(0),
2022-01-04 05:02:41 +00:00
metroTick(NULL),
metroTickLen(0),
2022-01-04 05:29:59 +00:00
metroFreq(0),
2022-01-04 05:02:41 +00:00
metroPos(0),
metroAmp(0.0f),
2021-12-10 09:22:13 +00:00
totalProcessed(0),
2021-12-11 04:41:00 +00:00
jediTable(NULL),
adpcmMem(NULL) {}
};
#endif