furnace/src/engine/instrument.h

455 lines
10 KiB
C
Raw Normal View History

2022-02-15 03:12:20 +00:00
/**
* 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 _INSTRUMENT_H
#define _INSTRUMENT_H
2022-01-19 08:28:29 +00:00
#include "safeWriter.h"
#include "dataErrors.h"
2021-05-12 22:19:18 +00:00
#include "../ta-utils.h"
// NOTICE!
// before adding new instrument types to this struct, please ask me first.
// absolutely zero support granted to conflicting formats.
2022-04-10 05:01:55 +00:00
enum DivInstrumentType : unsigned short {
DIV_INS_STD=0,
DIV_INS_FM=1,
DIV_INS_GB=2,
DIV_INS_C64=3,
DIV_INS_AMIGA=4,
DIV_INS_PCE=5,
2022-01-14 05:02:10 +00:00
DIV_INS_AY=6,
2022-01-14 20:21:57 +00:00
DIV_INS_AY8930=7,
2022-01-15 04:26:22 +00:00
DIV_INS_TIA=8,
2022-02-02 23:24:33 +00:00
DIV_INS_SAA1099=9,
DIV_INS_VIC=10,
DIV_INS_PET=11,
DIV_INS_VRC6=12,
DIV_INS_OPLL=13,
DIV_INS_OPL=14,
DIV_INS_FDS=15,
DIV_INS_VBOY=16,
DIV_INS_N163=17,
DIV_INS_SCC=18,
DIV_INS_OPZ=19,
DIV_INS_POKEY=20,
DIV_INS_BEEPER=21,
DIV_INS_SWAN=22,
2022-02-20 17:15:15 +00:00
DIV_INS_MIKEY=23,
2022-03-07 03:21:51 +00:00
DIV_INS_VERA=24,
DIV_INS_X1_010=25,
2022-03-31 20:25:58 +00:00
DIV_INS_VRC6_SAW=26,
2022-03-07 03:21:51 +00:00
DIV_INS_MAX,
};
2022-03-01 07:38:10 +00:00
// FM operator structure:
// - OPN:
// - AM, AR, DR, MULT, RR, SL, TL, RS, DT, D2R, SSG-EG
// - OPM:
// - AM, AR, DR, MULT, RR, SL, TL, DT2, RS, DT, D2R
// - OPLL:
// - AM, AR, DR, MULT, RR, SL, TL, SSG-EG&8 = EG-S
// - KSL, VIB, KSR
// - OPL:
// - AM, AR, DR, MULT, RR, SL, TL, SSG-EG&8 = EG-S
// - KSL, VIB, WS (OPL2/3), KSR
// - OPZ:
2022-03-01 07:38:10 +00:00
// - AM, AR, DR, MULT (CRS), RR, SL, TL, DT2, RS, DT, D2R
// - WS, DVB = MULT (FINE), DAM = REV, KSL = EGShift, EGT = Fixed
2022-03-01 07:38:10 +00:00
struct DivInstrumentFM {
unsigned char alg, fb, fms, ams, fms2, ams2, ops, opllPreset;
bool fixedDrums;
unsigned short kickFreq, snareHatFreq, tomTopFreq;
2021-05-12 22:19:18 +00:00
struct Operator {
2022-04-10 05:01:55 +00:00
bool enable;
2021-05-11 20:26:38 +00:00
unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
2022-03-01 07:38:10 +00:00
unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ
2021-12-12 23:19:43 +00:00
Operator():
am(0),
ar(0),
dr(0),
mult(0),
rr(0),
sl(0),
tl(0),
dt2(0),
rs(0),
dt(0),
d2r(0),
ssgEnv(0),
dam(0),
dvb(0),
egt(0),
ksl(0),
sus(0),
vib(0),
ws(0),
ksr(0) {}
} op[4];
2021-12-12 23:19:43 +00:00
DivInstrumentFM():
alg(0),
fb(0),
fms(0),
ams(0),
fms2(0),
ams2(0),
ops(2),
opllPreset(0),
fixedDrums(false),
kickFreq(0x520),
snareHatFreq(0x550),
tomTopFreq(0x1c0) {
2021-12-27 22:21:43 +00:00
// default instrument
fb=4;
op[0].tl=42;
op[0].ar=31;
op[0].dr=8;
2021-12-27 22:21:43 +00:00
op[0].sl=15;
op[0].rr=3;
op[0].mult=5;
op[0].dt=5;
op[2].tl=18;
op[2].ar=31;
op[2].dr=10;
op[2].sl=15;
op[2].rr=4;
op[2].mult=1;
op[2].dt=0;
op[1].tl=48;
2021-12-27 22:21:43 +00:00
op[1].ar=31;
op[1].dr=4;
2021-12-27 22:21:43 +00:00
op[1].sl=11;
op[1].rr=1;
2021-12-27 22:21:43 +00:00
op[1].mult=1;
op[1].dt=5;
op[3].tl=2;
op[3].ar=31;
op[3].dr=9;
op[3].sl=15;
op[3].rr=9;
op[3].mult=1;
op[3].dt=0;
}
};
// this is getting out of hand
2022-04-10 05:01:55 +00:00
struct DivInstrumentMacro {
String name;
int val[256];
int height;
unsigned int mode;
bool open;
unsigned char len;
signed char loop;
signed char rel;
DivInstrumentMacro(String n, int h=~0, bool initOpen=false):
name(n),
val{0},
height(h),
mode(0),
open(initOpen),
len(0),
loop(-1),
rel(-1) {}
};
2022-04-10 05:01:55 +00:00
struct DivInstrumentSTD {
DivInstrumentMacro volMacro;
DivInstrumentMacro arpMacro;
DivInstrumentMacro dutyMacro;
DivInstrumentMacro waveMacro;
DivInstrumentMacro pitchMacro;
DivInstrumentMacro ex1Macro;
DivInstrumentMacro ex2Macro;
DivInstrumentMacro ex3Macro;
DivInstrumentMacro algMacro;
DivInstrumentMacro fbMacro;
DivInstrumentMacro fmsMacro;
DivInstrumentMacro fms2Macro;
DivInstrumentMacro amsMacro;
DivInstrumentMacro ams2Macro;
DivInstrumentMacro panLMacro;
DivInstrumentMacro panRMacro;
DivInstrumentMacro phaseResetMacro;
DivInstrumentMacro ex4Macro;
DivInstrumentMacro ex5Macro;
DivInstrumentMacro ex6Macro;
DivInstrumentMacro ex7Macro;
DivInstrumentMacro ex8Macro;
2022-01-18 21:32:53 +00:00
struct OpMacro {
// ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
2022-04-10 05:01:55 +00:00
DivInstrumentMacro amMacro;
DivInstrumentMacro arMacro;
DivInstrumentMacro drMacro;
DivInstrumentMacro multMacro;
DivInstrumentMacro rrMacro;
DivInstrumentMacro slMacro;
DivInstrumentMacro tlMacro;
DivInstrumentMacro dt2Macro;
DivInstrumentMacro rsMacro;
DivInstrumentMacro dtMacro;
DivInstrumentMacro d2rMacro;
DivInstrumentMacro ssgMacro;
DivInstrumentMacro damMacro;
DivInstrumentMacro dvbMacro;
DivInstrumentMacro egtMacro;
DivInstrumentMacro kslMacro;
DivInstrumentMacro susMacro;
DivInstrumentMacro vibMacro;
DivInstrumentMacro wsMacro;
DivInstrumentMacro ksrMacro;
2022-01-18 21:32:53 +00:00
OpMacro():
2022-04-10 05:01:55 +00:00
amMacro("am"), arMacro("ar"), drMacro("dr"), multMacro("mult"),
rrMacro("rr"), slMacro("sl"), tlMacro("tl",~0,true), dt2Macro("dt2"),
rsMacro("rs"), dtMacro("dt"), d2rMacro("d2r"), ssgMacro("ssg"),
damMacro("dam"), dvbMacro("dvb"), egtMacro("egt"), kslMacro("ksl"),
susMacro("sus"), vibMacro("vib"), wsMacro("ws"), ksrMacro("ksr") {}
2022-01-18 21:32:53 +00:00
} opMacros[4];
2022-04-10 05:01:55 +00:00
struct WaveSynthMacro {
DivInstrumentMacro wave1Macro, wave2Macro;
DivInstrumentMacro rateDividerMacro;
DivInstrumentMacro effectMacro;
DivInstrumentMacro oneShotMacro, enabledMacro, globalMacro;
DivInstrumentMacro speedMacro, param1Macro, param2Macro, param3Macro, param4Macro;
WaveSynthMacro():
wave1Macro("wave1"),
wave2Macro("wave2"),
rateDividerMacro("rateDivider"),
effectMacro("effect"),
oneShotMacro("oneShot"),
enabledMacro("enabled"),
globalMacro("global"),
speedMacro("speed"),
param1Macro("param1"),
param2Macro("param2"),
param3Macro("param3"),
param4Macro("param4") {}
} ws;
2021-12-12 23:19:43 +00:00
DivInstrumentSTD():
2022-04-10 05:01:55 +00:00
volMacro("vol",15,true),
arpMacro("arp"),
dutyMacro("duty",3),
waveMacro("wave",63),
pitchMacro("pitch"),
ex1Macro("ex1"),
ex2Macro("ex2"),
ex3Macro("ex3"),
algMacro("alg"),
fbMacro("fb"),
fmsMacro("fms"),
fms2Macro("fms2"),
amsMacro("ams"),
ams2Macro("ams2"),
panLMacro("panL"),
panRMacro("panR"),
phaseResetMacro("phaseReset"),
ex4Macro("ex4"),
ex5Macro("ex5"),
ex6Macro("ex6"),
ex7Macro("ex7"),
ex8Macro("ex8") {}
};
struct DivInstrumentGB {
unsigned char envVol, envDir, envLen, soundLen;
2021-12-12 23:19:43 +00:00
DivInstrumentGB():
2021-12-18 03:14:41 +00:00
envVol(15),
2021-12-12 23:19:43 +00:00
envDir(0),
2021-12-18 03:14:41 +00:00
envLen(2),
soundLen(64) {}
};
struct DivInstrumentC64 {
bool triOn, sawOn, pulseOn, noiseOn;
unsigned char a, d, s, r;
unsigned short duty;
unsigned char ringMod, oscSync;
bool toFilter, volIsCutoff, initFilter, dutyIsAbs, filterIsAbs;
unsigned char res;
unsigned short cut;
bool hp, lp, bp, ch3off;
2021-12-12 23:19:43 +00:00
DivInstrumentC64():
triOn(false),
sawOn(true),
pulseOn(false),
noiseOn(false),
a(0),
d(8),
s(0),
r(0),
duty(2048),
2021-12-12 23:19:43 +00:00
ringMod(0),
oscSync(0),
toFilter(false),
volIsCutoff(false),
initFilter(false),
dutyIsAbs(false),
filterIsAbs(false),
2021-12-12 23:19:43 +00:00
res(0),
cut(0),
hp(false),
lp(false),
bp(false),
ch3off(false) {}
};
struct DivInstrumentAmiga {
short initSample;
2022-03-16 22:01:44 +00:00
bool useNoteMap;
int noteFreq[120];
short noteMap[120];
DivInstrumentAmiga():
2022-03-16 22:01:44 +00:00
initSample(0),
useNoteMap(false) {
memset(noteMap,-1,120*sizeof(short));
memset(noteFreq,0,120*sizeof(int));
}
};
struct DivInstrumentN163 {
int wave, wavePos, waveLen;
unsigned char waveMode;
DivInstrumentN163():
wave(-1),
wavePos(0),
2022-03-28 03:04:01 +00:00
waveLen(32),
waveMode(3) {}
};
2022-04-04 03:37:16 +00:00
struct DivInstrumentFDS {
signed char modTable[32];
int modSpeed, modDepth;
// this is here for compatibility.
bool initModTableWithFirstWave;
2022-04-04 03:37:16 +00:00
DivInstrumentFDS():
modSpeed(0),
modDepth(0),
initModTableWithFirstWave(false) {
2022-04-04 03:37:16 +00:00
memset(modTable,0,32);
}
};
2022-04-07 20:46:48 +00:00
enum DivWaveSynthEffects {
DIV_WS_NONE=0,
// one waveform effects
DIV_WS_INVERT,
DIV_WS_ADD,
DIV_WS_SUBTRACT,
DIV_WS_AVERAGE,
DIV_WS_PHASE,
2022-04-07 23:27:17 +00:00
DIV_WS_SINGLE_MAX,
2022-04-07 20:46:48 +00:00
// two waveform effects
DIV_WS_NONE_DUAL=128,
DIV_WS_WIPE,
DIV_WS_FADE,
DIV_WS_PING_PONG,
DIV_WS_OVERLAY,
DIV_WS_NEGATIVE_OVERLAY,
DIV_WS_PHASE_DUAL,
2022-04-07 23:27:17 +00:00
DIV_WS_DUAL_MAX
2022-04-07 20:46:48 +00:00
};
struct DivInstrumentWaveSynth {
int wave1, wave2;
unsigned char rateDivider;
2022-04-07 23:27:17 +00:00
unsigned char effect;
2022-04-07 20:46:48 +00:00
bool oneShot, enabled, global;
unsigned char speed, param1, param2, param3, param4;
DivInstrumentWaveSynth():
wave1(0),
wave2(0),
rateDivider(1),
effect(DIV_WS_NONE),
oneShot(false),
enabled(false),
global(false),
speed(0),
2022-04-07 20:46:48 +00:00
param1(0),
param2(0),
param3(0),
param4(0) {}
};
struct DivInstrument {
String name;
bool mode;
DivInstrumentType type;
DivInstrumentFM fm;
DivInstrumentSTD std;
DivInstrumentGB gb;
DivInstrumentC64 c64;
DivInstrumentAmiga amiga;
DivInstrumentN163 n163;
DivInstrumentFDS fds;
2022-04-07 20:46:48 +00:00
DivInstrumentWaveSynth ws;
2022-03-16 03:05:55 +00:00
/**
* save the instrument to a SafeWriter.
* @param w the SafeWriter in question.
*/
2022-01-19 08:28:29 +00:00
void putInsData(SafeWriter* w);
2022-03-16 03:05:55 +00:00
2022-04-10 05:01:55 +00:00
/**
* save the macro to a SafeWriter.
* @param m the macro.
* @param w the SafeWriter in question.
*/
void putMacroData(DivInstrumentMacro m, SafeWriter* w);
2022-03-16 03:05:55 +00:00
/**
* read instrument data in .fui format.
* @param reader the reader.
* @param version the format version.
* @return a DivDataErrors.
*/
DivDataErrors readInsData(SafeReader& reader, short version);
2022-03-16 03:05:55 +00:00
2022-04-10 05:01:55 +00:00
/**
* read macro data in .fui format.
* @param m the macro.
* @param reader the reader.
* @param version the format version.
* @return a DivDataErrors.
*/
DivDataErrors readMacroData(DivInstrumentMacro& m, SafeReader& reader, short version);
2022-04-10 05:01:55 +00:00
2022-03-16 03:05:55 +00:00
/**
* save this instrument to a file.
* @param path file path.
* @return whether it was successful.
*/
2022-01-19 08:28:29 +00:00
bool save(const char* path);
DivInstrument():
name(""),
mode(false),
type(DIV_INS_FM) {
}
};
#endif