mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-02 09:17:26 +00:00
1850968def
thanks LTVA
972 lines
24 KiB
C++
972 lines
24 KiB
C++
/**
|
|
* Furnace Tracker - multi-system chiptune tracker
|
|
* Copyright (C) 2021-2024 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
|
|
#include "safeWriter.h"
|
|
#include "dataErrors.h"
|
|
#include "../ta-utils.h"
|
|
#include "../pch.h"
|
|
|
|
struct DivSong;
|
|
|
|
// NOTICE!
|
|
// before adding new instrument types to this struct, please ask me first.
|
|
// absolutely zero support granted to conflicting formats.
|
|
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,
|
|
DIV_INS_AY=6,
|
|
DIV_INS_AY8930=7,
|
|
DIV_INS_TIA=8,
|
|
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,
|
|
DIV_INS_MIKEY=23,
|
|
DIV_INS_VERA=24,
|
|
DIV_INS_X1_010=25,
|
|
DIV_INS_VRC6_SAW=26,
|
|
DIV_INS_ES5506=27,
|
|
DIV_INS_MULTIPCM=28,
|
|
DIV_INS_SNES=29,
|
|
DIV_INS_SU=30,
|
|
DIV_INS_NAMCO=31,
|
|
DIV_INS_OPL_DRUMS=32,
|
|
DIV_INS_OPM=33,
|
|
DIV_INS_NES=34,
|
|
DIV_INS_MSM6258=35,
|
|
DIV_INS_MSM6295=36,
|
|
DIV_INS_ADPCMA=37,
|
|
DIV_INS_ADPCMB=38,
|
|
DIV_INS_SEGAPCM=39,
|
|
DIV_INS_QSOUND=40,
|
|
DIV_INS_YMZ280B=41,
|
|
DIV_INS_RF5C68=42,
|
|
DIV_INS_MSM5232=43,
|
|
DIV_INS_T6W28=44,
|
|
DIV_INS_K007232=45,
|
|
DIV_INS_GA20=46,
|
|
DIV_INS_POKEMINI=47,
|
|
DIV_INS_SM8521=48,
|
|
DIV_INS_PV1000=49,
|
|
DIV_INS_K053260=50,
|
|
// DIV_INS_YMF292=51,
|
|
DIV_INS_TED=52,
|
|
DIV_INS_C140=53,
|
|
DIV_INS_C219=54,
|
|
DIV_INS_ESFM=55,
|
|
DIV_INS_POWERNOISE=56,
|
|
DIV_INS_POWERNOISE_SLOPE=57,
|
|
DIV_INS_DAVE=58,
|
|
DIV_INS_NDS=59,
|
|
DIV_INS_GBA_DMA=60,
|
|
DIV_INS_GBA_MINMOD=61,
|
|
DIV_INS_BIFURCATOR=62,
|
|
DIV_INS_SID2=63, // coincidence!
|
|
DIV_INS_MAX,
|
|
DIV_INS_NULL
|
|
};
|
|
|
|
enum DivMacroType: unsigned char {
|
|
DIV_MACRO_VOL=0,
|
|
DIV_MACRO_ARP,
|
|
DIV_MACRO_DUTY,
|
|
DIV_MACRO_WAVE,
|
|
DIV_MACRO_PITCH,
|
|
DIV_MACRO_EX1,
|
|
DIV_MACRO_EX2,
|
|
DIV_MACRO_EX3,
|
|
DIV_MACRO_ALG,
|
|
DIV_MACRO_FB,
|
|
DIV_MACRO_FMS,
|
|
DIV_MACRO_AMS,
|
|
DIV_MACRO_PAN_LEFT,
|
|
DIV_MACRO_PAN_RIGHT,
|
|
DIV_MACRO_PHASE_RESET,
|
|
DIV_MACRO_EX4,
|
|
DIV_MACRO_EX5,
|
|
DIV_MACRO_EX6,
|
|
DIV_MACRO_EX7,
|
|
DIV_MACRO_EX8
|
|
};
|
|
|
|
enum DivMacroTypeOp: unsigned char {
|
|
DIV_MACRO_OP_AM=32,
|
|
DIV_MACRO_OP_AR,
|
|
DIV_MACRO_OP_DR,
|
|
DIV_MACRO_OP_MULT,
|
|
DIV_MACRO_OP_RR,
|
|
DIV_MACRO_OP_SL,
|
|
DIV_MACRO_OP_TL,
|
|
DIV_MACRO_OP_DT2,
|
|
DIV_MACRO_OP_RS,
|
|
DIV_MACRO_OP_DT,
|
|
DIV_MACRO_OP_D2R,
|
|
DIV_MACRO_OP_SSG,
|
|
DIV_MACRO_OP_DAM,
|
|
DIV_MACRO_OP_DVB,
|
|
DIV_MACRO_OP_EGT,
|
|
DIV_MACRO_OP_KSL,
|
|
DIV_MACRO_OP_SUS,
|
|
DIV_MACRO_OP_VIB,
|
|
DIV_MACRO_OP_WS,
|
|
DIV_MACRO_OP_KSR,
|
|
};
|
|
|
|
// 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:
|
|
// - AM, AR, DR, MULT (CRS), RR, SL, TL, DT2, RS, DT, D2R
|
|
// - WS, DVB = MULT (FINE), DAM = REV, KSL = EGShift, EGT = Fixed
|
|
|
|
struct DivInstrumentFM {
|
|
unsigned char alg, fb, fms, ams, fms2, ams2, ops, opllPreset;
|
|
bool fixedDrums;
|
|
unsigned short kickFreq, snareHatFreq, tomTopFreq;
|
|
|
|
bool operator==(const DivInstrumentFM& other);
|
|
bool operator!=(const DivInstrumentFM& other) {
|
|
return !(*this==other);
|
|
}
|
|
struct Operator {
|
|
bool enable;
|
|
unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
|
|
unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ
|
|
unsigned char kvs;
|
|
|
|
bool operator==(const Operator& other);
|
|
bool operator!=(const Operator& other) {
|
|
return !(*this==other);
|
|
}
|
|
Operator():
|
|
enable(true),
|
|
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),
|
|
kvs(2) {}
|
|
} op[4];
|
|
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) {
|
|
// default instrument
|
|
fb=4;
|
|
op[0].tl=42;
|
|
op[0].ar=31;
|
|
op[0].dr=8;
|
|
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;
|
|
op[1].ar=31;
|
|
op[1].dr=4;
|
|
op[1].sl=11;
|
|
op[1].rr=1;
|
|
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
|
|
struct DivInstrumentMacro {
|
|
int val[256];
|
|
unsigned int mode;
|
|
unsigned char open;
|
|
unsigned char len, delay, speed, loop, rel;
|
|
// 0-31: normal
|
|
// 32+: operator (top 3 bits select operator, starting from 1)
|
|
unsigned char macroType;
|
|
|
|
// the following variables are used by the GUI and not saved in the file
|
|
int vScroll, vZoom;
|
|
int typeMemory[16];
|
|
unsigned char lenMemory;
|
|
|
|
explicit DivInstrumentMacro(unsigned char initType, bool initOpen=false):
|
|
mode(0),
|
|
open(initOpen),
|
|
len(0),
|
|
delay(0),
|
|
speed(1),
|
|
loop(255),
|
|
rel(255),
|
|
macroType(initType),
|
|
vScroll(0),
|
|
vZoom(-1),
|
|
lenMemory(0) {
|
|
memset(val,0,256*sizeof(int));
|
|
memset(typeMemory,0,16*sizeof(int));
|
|
}
|
|
};
|
|
|
|
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 amsMacro;
|
|
DivInstrumentMacro panLMacro;
|
|
DivInstrumentMacro panRMacro;
|
|
DivInstrumentMacro phaseResetMacro;
|
|
DivInstrumentMacro ex4Macro;
|
|
DivInstrumentMacro ex5Macro;
|
|
DivInstrumentMacro ex6Macro;
|
|
DivInstrumentMacro ex7Macro;
|
|
DivInstrumentMacro ex8Macro;
|
|
|
|
struct OpMacro {
|
|
// ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
|
|
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;
|
|
OpMacro():
|
|
amMacro(DIV_MACRO_OP_AM), arMacro(DIV_MACRO_OP_AR), drMacro(DIV_MACRO_OP_DR), multMacro(DIV_MACRO_OP_MULT),
|
|
rrMacro(DIV_MACRO_OP_RR), slMacro(DIV_MACRO_OP_SL), tlMacro(DIV_MACRO_OP_TL,true), dt2Macro(DIV_MACRO_OP_DT2),
|
|
rsMacro(DIV_MACRO_OP_RS), dtMacro(DIV_MACRO_OP_DT), d2rMacro(DIV_MACRO_OP_D2R), ssgMacro(DIV_MACRO_OP_SSG),
|
|
damMacro(DIV_MACRO_OP_DAM), dvbMacro(DIV_MACRO_OP_DVB), egtMacro(DIV_MACRO_OP_EGT), kslMacro(DIV_MACRO_OP_KSL),
|
|
susMacro(DIV_MACRO_OP_SUS), vibMacro(DIV_MACRO_OP_VIB), wsMacro(DIV_MACRO_OP_WS), ksrMacro(DIV_MACRO_OP_KSR) {}
|
|
} opMacros[4];
|
|
|
|
DivInstrumentMacro* macroByType(DivMacroType type);
|
|
|
|
DivInstrumentSTD():
|
|
volMacro(DIV_MACRO_VOL,true),
|
|
arpMacro(DIV_MACRO_ARP),
|
|
dutyMacro(DIV_MACRO_DUTY),
|
|
waveMacro(DIV_MACRO_WAVE),
|
|
pitchMacro(DIV_MACRO_PITCH),
|
|
ex1Macro(DIV_MACRO_EX1),
|
|
ex2Macro(DIV_MACRO_EX2),
|
|
ex3Macro(DIV_MACRO_EX3),
|
|
algMacro(DIV_MACRO_ALG),
|
|
fbMacro(DIV_MACRO_FB),
|
|
fmsMacro(DIV_MACRO_FMS),
|
|
amsMacro(DIV_MACRO_AMS),
|
|
panLMacro(DIV_MACRO_PAN_LEFT),
|
|
panRMacro(DIV_MACRO_PAN_RIGHT),
|
|
phaseResetMacro(DIV_MACRO_PHASE_RESET),
|
|
ex4Macro(DIV_MACRO_EX4),
|
|
ex5Macro(DIV_MACRO_EX5),
|
|
ex6Macro(DIV_MACRO_EX6),
|
|
ex7Macro(DIV_MACRO_EX7),
|
|
ex8Macro(DIV_MACRO_EX8) {
|
|
for (int i=0; i<4; i++) {
|
|
opMacros[i].amMacro.macroType=DIV_MACRO_OP_AM+(i<<5);
|
|
opMacros[i].arMacro.macroType=DIV_MACRO_OP_AR+(i<<5);
|
|
opMacros[i].drMacro.macroType=DIV_MACRO_OP_DR+(i<<5);
|
|
opMacros[i].multMacro.macroType=DIV_MACRO_OP_MULT+(i<<5);
|
|
opMacros[i].rrMacro.macroType=DIV_MACRO_OP_RR+(i<<5);
|
|
opMacros[i].slMacro.macroType=DIV_MACRO_OP_SL+(i<<5);
|
|
opMacros[i].tlMacro.macroType=DIV_MACRO_OP_TL+(i<<5);
|
|
opMacros[i].dt2Macro.macroType=DIV_MACRO_OP_DT2+(i<<5);
|
|
opMacros[i].rsMacro.macroType=DIV_MACRO_OP_RS+(i<<5);
|
|
opMacros[i].dtMacro.macroType=DIV_MACRO_OP_DT+(i<<5);
|
|
opMacros[i].d2rMacro.macroType=DIV_MACRO_OP_D2R+(i<<5);
|
|
opMacros[i].ssgMacro.macroType=DIV_MACRO_OP_SSG+(i<<5);
|
|
|
|
opMacros[i].damMacro.macroType=DIV_MACRO_OP_DAM+(i<<5);
|
|
opMacros[i].dvbMacro.macroType=DIV_MACRO_OP_DVB+(i<<5);
|
|
opMacros[i].egtMacro.macroType=DIV_MACRO_OP_EGT+(i<<5);
|
|
opMacros[i].kslMacro.macroType=DIV_MACRO_OP_KSL+(i<<5);
|
|
opMacros[i].susMacro.macroType=DIV_MACRO_OP_SUS+(i<<5);
|
|
opMacros[i].vibMacro.macroType=DIV_MACRO_OP_VIB+(i<<5);
|
|
opMacros[i].wsMacro.macroType=DIV_MACRO_OP_WS+(i<<5);
|
|
opMacros[i].ksrMacro.macroType=DIV_MACRO_OP_KSR+(i<<5);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct DivInstrumentGB {
|
|
unsigned char envVol, envDir, envLen, soundLen, hwSeqLen;
|
|
bool softEnv, alwaysInit, doubleWave;
|
|
enum HWSeqCommands: unsigned char {
|
|
DIV_GB_HWCMD_ENVELOPE=0,
|
|
DIV_GB_HWCMD_SWEEP,
|
|
DIV_GB_HWCMD_WAIT,
|
|
DIV_GB_HWCMD_WAIT_REL,
|
|
DIV_GB_HWCMD_LOOP,
|
|
DIV_GB_HWCMD_LOOP_REL,
|
|
|
|
DIV_GB_HWCMD_MAX
|
|
};
|
|
struct HWSeqCommandGB {
|
|
unsigned char cmd;
|
|
unsigned short data;
|
|
} hwSeq[256];
|
|
|
|
bool operator==(const DivInstrumentGB& other);
|
|
bool operator!=(const DivInstrumentGB& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentGB():
|
|
envVol(15),
|
|
envDir(0),
|
|
envLen(2),
|
|
soundLen(64),
|
|
hwSeqLen(0),
|
|
softEnv(false),
|
|
alwaysInit(false),
|
|
doubleWave(false) {
|
|
memset(hwSeq,0,256*sizeof(HWSeqCommandGB));
|
|
}
|
|
};
|
|
|
|
struct DivInstrumentC64 {
|
|
bool triOn, sawOn, pulseOn, noiseOn;
|
|
unsigned char a, d, s, r;
|
|
unsigned short duty;
|
|
unsigned char ringMod, oscSync;
|
|
bool toFilter, initFilter, dutyIsAbs, filterIsAbs, noTest;
|
|
unsigned char res;
|
|
unsigned short cut;
|
|
bool hp, lp, bp, ch3off;
|
|
|
|
bool operator==(const DivInstrumentC64& other);
|
|
bool operator!=(const DivInstrumentC64& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentC64():
|
|
triOn(false),
|
|
sawOn(true),
|
|
pulseOn(false),
|
|
noiseOn(false),
|
|
a(0),
|
|
d(8),
|
|
s(0),
|
|
r(0),
|
|
duty(2048),
|
|
ringMod(0),
|
|
oscSync(0),
|
|
toFilter(false),
|
|
initFilter(false),
|
|
dutyIsAbs(false),
|
|
filterIsAbs(false),
|
|
noTest(false),
|
|
res(0),
|
|
cut(0),
|
|
hp(false),
|
|
lp(false),
|
|
bp(false),
|
|
ch3off(false) {}
|
|
};
|
|
|
|
struct DivInstrumentAmiga {
|
|
struct SampleMap {
|
|
int freq;
|
|
short map;
|
|
signed char dpcmFreq;
|
|
signed char dpcmDelta;
|
|
SampleMap(int f=0, short m=-1, signed char df=15, signed char dd=-1):
|
|
freq(f),
|
|
map(m),
|
|
dpcmFreq(df),
|
|
dpcmDelta(dd) {}
|
|
};
|
|
short initSample;
|
|
bool useNoteMap;
|
|
bool useSample;
|
|
bool useWave;
|
|
unsigned char waveLen;
|
|
SampleMap noteMap[120];
|
|
|
|
bool operator==(const DivInstrumentAmiga& other);
|
|
bool operator!=(const DivInstrumentAmiga& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
/**
|
|
* get the sample at specified note.
|
|
* @return the sample.
|
|
*/
|
|
inline short getSample(int note) {
|
|
if (useNoteMap) {
|
|
if (note<0) note=0;
|
|
if (note>119) note=119;
|
|
return noteMap[note].map;
|
|
}
|
|
return initSample;
|
|
}
|
|
|
|
/**
|
|
* get the sample playback note at specified note.
|
|
* @return the note, or -1 if not using note map.
|
|
*/
|
|
inline int getFreq(int note) {
|
|
if (useNoteMap) {
|
|
if (note<0) note=0;
|
|
if (note>119) note=119;
|
|
return noteMap[note].freq;
|
|
}
|
|
return note;
|
|
}
|
|
|
|
/**
|
|
* get the DPCM pitch at specified note.
|
|
* @return the pitch, or -1 if not using note map.
|
|
*/
|
|
inline signed char getDPCMFreq(int note) {
|
|
if (useNoteMap) {
|
|
if (note<0) note=0;
|
|
if (note>119) note=119;
|
|
return noteMap[note].dpcmFreq;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* get the DPCM delta counter value at specified note.
|
|
* @return the delta counter value, or -1 if not using note map.
|
|
*/
|
|
inline signed char getDPCMDelta(int note) {
|
|
if (useNoteMap) {
|
|
if (note<0) note=0;
|
|
if (note>119) note=119;
|
|
return noteMap[note].dpcmDelta;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
DivInstrumentAmiga():
|
|
initSample(0),
|
|
useNoteMap(false),
|
|
useSample(false),
|
|
useWave(false),
|
|
waveLen(31) {
|
|
for (int i=0; i<120; i++) {
|
|
noteMap[i].map=-1;
|
|
noteMap[i].freq=i;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct DivInstrumentX1_010 {
|
|
int bankSlot;
|
|
|
|
bool operator==(const DivInstrumentX1_010& other);
|
|
bool operator!=(const DivInstrumentX1_010& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentX1_010():
|
|
bankSlot(0) {}
|
|
};
|
|
|
|
struct DivInstrumentN163 {
|
|
int wave, wavePos, waveLen;
|
|
unsigned char waveMode;
|
|
bool perChanPos;
|
|
int wavePosCh[8];
|
|
int waveLenCh[8];
|
|
|
|
bool operator==(const DivInstrumentN163& other);
|
|
bool operator!=(const DivInstrumentN163& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentN163():
|
|
wave(-1),
|
|
wavePos(0),
|
|
waveLen(32),
|
|
waveMode(3),
|
|
perChanPos(false) {
|
|
for (int i=0; i<8; i++) {
|
|
wavePosCh[i]=(i&3)<<5;
|
|
waveLenCh[i]=32;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct DivInstrumentFDS {
|
|
signed char modTable[32];
|
|
int modSpeed, modDepth;
|
|
// this is here for compatibility.
|
|
bool initModTableWithFirstWave;
|
|
|
|
bool operator==(const DivInstrumentFDS& other);
|
|
bool operator!=(const DivInstrumentFDS& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentFDS():
|
|
modSpeed(0),
|
|
modDepth(0),
|
|
initModTableWithFirstWave(false) {
|
|
memset(modTable,0,32);
|
|
}
|
|
};
|
|
|
|
struct DivInstrumentMultiPCM {
|
|
unsigned char ar, d1r, dl, d2r, rr, rc;
|
|
unsigned char lfo, vib, am;
|
|
|
|
bool operator==(const DivInstrumentMultiPCM& other);
|
|
bool operator!=(const DivInstrumentMultiPCM& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentMultiPCM():
|
|
ar(15), d1r(15), dl(0), d2r(0), rr(15), rc(15),
|
|
lfo(0), vib(0), am(0) {
|
|
}
|
|
};
|
|
|
|
enum DivWaveSynthEffects {
|
|
DIV_WS_NONE=0,
|
|
// one waveform effects
|
|
DIV_WS_INVERT,
|
|
DIV_WS_ADD,
|
|
DIV_WS_SUBTRACT,
|
|
DIV_WS_AVERAGE,
|
|
DIV_WS_PHASE,
|
|
DIV_WS_CHORUS,
|
|
|
|
DIV_WS_SINGLE_MAX,
|
|
|
|
// 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_SLIDE,
|
|
DIV_WS_MIX,
|
|
DIV_WS_PHASE_MOD,
|
|
|
|
DIV_WS_DUAL_MAX
|
|
};
|
|
|
|
struct DivInstrumentWaveSynth {
|
|
int wave1, wave2;
|
|
unsigned char rateDivider;
|
|
unsigned char effect;
|
|
bool oneShot, enabled, global;
|
|
unsigned char speed, param1, param2, param3, param4;
|
|
|
|
bool operator==(const DivInstrumentWaveSynth& other);
|
|
bool operator!=(const DivInstrumentWaveSynth& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentWaveSynth():
|
|
wave1(0),
|
|
wave2(0),
|
|
rateDivider(1),
|
|
effect(DIV_WS_NONE),
|
|
oneShot(false),
|
|
enabled(false),
|
|
global(false),
|
|
speed(0),
|
|
param1(0),
|
|
param2(0),
|
|
param3(0),
|
|
param4(0) {}
|
|
};
|
|
|
|
struct DivInstrumentSoundUnit {
|
|
bool switchRoles;
|
|
unsigned char hwSeqLen;
|
|
enum HWSeqCommands: unsigned char {
|
|
DIV_SU_HWCMD_VOL=0,
|
|
DIV_SU_HWCMD_PITCH,
|
|
DIV_SU_HWCMD_CUT,
|
|
DIV_SU_HWCMD_WAIT,
|
|
DIV_SU_HWCMD_WAIT_REL,
|
|
DIV_SU_HWCMD_LOOP,
|
|
DIV_SU_HWCMD_LOOP_REL,
|
|
|
|
DIV_SU_HWCMD_MAX
|
|
};
|
|
struct HWSeqCommandSU {
|
|
unsigned char cmd;
|
|
unsigned char bound;
|
|
unsigned char val;
|
|
unsigned short speed;
|
|
unsigned short padding;
|
|
} hwSeq[256];
|
|
|
|
bool operator==(const DivInstrumentSoundUnit& other);
|
|
bool operator!=(const DivInstrumentSoundUnit& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentSoundUnit():
|
|
switchRoles(false),
|
|
hwSeqLen(0) {
|
|
memset(hwSeq,0,256*sizeof(HWSeqCommandSU));
|
|
}
|
|
};
|
|
|
|
struct DivInstrumentES5506 {
|
|
struct Filter {
|
|
enum FilterMode: unsigned char { // filter mode for pole 4,3
|
|
FILTER_MODE_HPK2_HPK2=0,
|
|
FILTER_MODE_HPK2_LPK1,
|
|
FILTER_MODE_LPK2_LPK2,
|
|
FILTER_MODE_LPK2_LPK1,
|
|
};
|
|
FilterMode mode;
|
|
unsigned short k1, k2;
|
|
Filter():
|
|
mode(FILTER_MODE_LPK2_LPK1),
|
|
k1(0xffff),
|
|
k2(0xffff) {}
|
|
};
|
|
struct Envelope {
|
|
unsigned short ecount;
|
|
signed char lVRamp, rVRamp;
|
|
signed char k1Ramp, k2Ramp;
|
|
bool k1Slow, k2Slow;
|
|
Envelope():
|
|
ecount(0),
|
|
lVRamp(0),
|
|
rVRamp(0),
|
|
k1Ramp(0),
|
|
k2Ramp(0),
|
|
k1Slow(false),
|
|
k2Slow(false) {}
|
|
};
|
|
Filter filter;
|
|
Envelope envelope;
|
|
|
|
bool operator==(const DivInstrumentES5506& other);
|
|
bool operator!=(const DivInstrumentES5506& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentES5506():
|
|
filter(Filter()),
|
|
envelope(Envelope()) {}
|
|
};
|
|
|
|
struct DivInstrumentSNES {
|
|
enum GainMode: unsigned char {
|
|
GAIN_MODE_DIRECT=0,
|
|
GAIN_MODE_DEC_LINEAR=4,
|
|
GAIN_MODE_DEC_LOG=5,
|
|
GAIN_MODE_INC_LINEAR=6,
|
|
GAIN_MODE_INC_INVLOG=7
|
|
};
|
|
bool useEnv;
|
|
// 0: no sustain (key off = cut)
|
|
// 1: sustain (R = d2; key off = dec linear to r)
|
|
// 2: sustain (R = d2; key off = dec exponential to r)
|
|
// 3: sustain (R = d2; key off = R to r)
|
|
unsigned char sus;
|
|
GainMode gainMode;
|
|
unsigned char gain;
|
|
unsigned char a, d, s, r, d2;
|
|
|
|
bool operator==(const DivInstrumentSNES& other);
|
|
bool operator!=(const DivInstrumentSNES& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
DivInstrumentSNES():
|
|
useEnv(true),
|
|
sus(0),
|
|
gainMode(GAIN_MODE_DIRECT),
|
|
gain(127),
|
|
a(15),
|
|
d(7),
|
|
s(7),
|
|
r(0),
|
|
d2(0) {}
|
|
};
|
|
|
|
// ESFM operator structure:
|
|
// - DELAY, OUT, MOD, L, R, NOISE
|
|
// - Virtual: CT, DT, FIXED
|
|
// - In FM struct: AM, DAM, AR, DR, MULT, RR, SL, TL
|
|
// - In FM struct: KSL, VIB, DVB, WS, SUS, KSR
|
|
// - Not in struct: FNUML, FNUMH, BLOCK
|
|
|
|
struct DivInstrumentESFM {
|
|
bool operator==(const DivInstrumentESFM& other);
|
|
bool operator!=(const DivInstrumentESFM& other) {
|
|
return !(*this==other);
|
|
}
|
|
|
|
// Only works on OP4, so putting it outside the Operator struct instead
|
|
unsigned char noise;
|
|
struct Operator {
|
|
unsigned char delay, outLvl, modIn, left, right, fixed;
|
|
signed char ct, dt;
|
|
|
|
bool operator==(const Operator& other);
|
|
bool operator!=(const Operator& other) {
|
|
return !(*this==other);
|
|
}
|
|
Operator():
|
|
delay(0),
|
|
outLvl(0),
|
|
modIn(0),
|
|
left(1),
|
|
right(1),
|
|
fixed(0),
|
|
ct(0),
|
|
dt(0) {}
|
|
} op[4];
|
|
DivInstrumentESFM():
|
|
noise(0)
|
|
{
|
|
op[0].modIn=4;
|
|
op[0].outLvl=0;
|
|
|
|
op[1].modIn=7;
|
|
op[1].outLvl=0;
|
|
|
|
op[2].modIn=7;
|
|
op[2].outLvl=0;
|
|
|
|
op[3].modIn=7;
|
|
op[3].outLvl=7;
|
|
}
|
|
};
|
|
|
|
struct DivInstrumentPowerNoise {
|
|
unsigned char octave;
|
|
|
|
bool operator==(const DivInstrumentPowerNoise& other);
|
|
bool operator!=(const DivInstrumentPowerNoise& other) {
|
|
return !(*this==other);
|
|
}
|
|
DivInstrumentPowerNoise():
|
|
octave(0) {}
|
|
};
|
|
|
|
struct DivInstrumentSID2 {
|
|
unsigned char volume;
|
|
unsigned char mixMode;
|
|
unsigned char noiseMode;
|
|
|
|
bool operator==(const DivInstrumentSID2& other);
|
|
bool operator!=(const DivInstrumentSID2& other) {
|
|
return !(*this==other);
|
|
}
|
|
DivInstrumentSID2():
|
|
volume(15),
|
|
mixMode(0),
|
|
noiseMode(0) {}
|
|
};
|
|
|
|
struct DivInstrument {
|
|
String name;
|
|
DivInstrumentType type;
|
|
DivInstrumentFM fm;
|
|
DivInstrumentSTD std;
|
|
DivInstrumentGB gb;
|
|
DivInstrumentC64 c64;
|
|
DivInstrumentAmiga amiga;
|
|
DivInstrumentX1_010 x1_010;
|
|
DivInstrumentN163 n163;
|
|
DivInstrumentFDS fds;
|
|
DivInstrumentMultiPCM multipcm;
|
|
DivInstrumentWaveSynth ws;
|
|
DivInstrumentSoundUnit su;
|
|
DivInstrumentES5506 es5506;
|
|
DivInstrumentSNES snes;
|
|
DivInstrumentESFM esfm;
|
|
DivInstrumentPowerNoise powernoise;
|
|
DivInstrumentSID2 sid2;
|
|
|
|
/**
|
|
* these are internal functions.
|
|
*/
|
|
void writeMacro(SafeWriter* w, const DivInstrumentMacro& m);
|
|
void writeFeatureNA(SafeWriter* w);
|
|
void writeFeatureFM(SafeWriter* w, bool fui);
|
|
void writeFeatureMA(SafeWriter* w);
|
|
void writeFeature64(SafeWriter* w);
|
|
void writeFeatureGB(SafeWriter* w);
|
|
void writeFeatureSM(SafeWriter* w);
|
|
void writeFeatureOx(SafeWriter* w, int op);
|
|
void writeFeatureLD(SafeWriter* w);
|
|
void writeFeatureSN(SafeWriter* w);
|
|
void writeFeatureN1(SafeWriter* w);
|
|
void writeFeatureFD(SafeWriter* w);
|
|
void writeFeatureWS(SafeWriter* w);
|
|
size_t writeFeatureSL(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
|
size_t writeFeatureWL(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
|
void writeFeatureMP(SafeWriter* w);
|
|
void writeFeatureSU(SafeWriter* w);
|
|
void writeFeatureES(SafeWriter* w);
|
|
void writeFeatureX1(SafeWriter* w);
|
|
void writeFeatureNE(SafeWriter* w);
|
|
void writeFeatureEF(SafeWriter* w);
|
|
void writeFeaturePN(SafeWriter* w);
|
|
void writeFeatureS2(SafeWriter* w);
|
|
|
|
void readFeatureNA(SafeReader& reader, short version);
|
|
void readFeatureFM(SafeReader& reader, short version);
|
|
void readFeatureMA(SafeReader& reader, short version);
|
|
void readFeature64(SafeReader& reader, bool& volIsCutoff, short version);
|
|
void readFeatureGB(SafeReader& reader, short version);
|
|
void readFeatureSM(SafeReader& reader, short version);
|
|
void readFeatureOx(SafeReader& reader, int op, short version);
|
|
void readFeatureLD(SafeReader& reader, short version);
|
|
void readFeatureSN(SafeReader& reader, short version);
|
|
void readFeatureN1(SafeReader& reader, short version);
|
|
void readFeatureFD(SafeReader& reader, short version);
|
|
void readFeatureWS(SafeReader& reader, short version);
|
|
void readFeatureSL(SafeReader& reader, DivSong* song, short version);
|
|
void readFeatureWL(SafeReader& reader, DivSong* song, short version);
|
|
void readFeatureMP(SafeReader& reader, short version);
|
|
void readFeatureSU(SafeReader& reader, short version);
|
|
void readFeatureES(SafeReader& reader, short version);
|
|
void readFeatureX1(SafeReader& reader, short version);
|
|
void readFeatureNE(SafeReader& reader, short version);
|
|
void readFeatureEF(SafeReader& reader, short version);
|
|
void readFeaturePN(SafeReader& reader, short version);
|
|
void readFeatureS2(SafeReader& reader, short version);
|
|
|
|
DivDataErrors readInsDataOld(SafeReader& reader, short version);
|
|
DivDataErrors readInsDataNew(SafeReader& reader, short version, bool fui, DivSong* song);
|
|
|
|
void convertC64SpecialMacro();
|
|
|
|
/**
|
|
* save the instrument to a SafeWriter.
|
|
* @param w the SafeWriter in question.
|
|
*/
|
|
void putInsData2(SafeWriter* w, bool fui=false, const DivSong* song=NULL, bool insName=true);
|
|
|
|
/**
|
|
* read instrument data in .fui format.
|
|
* @param reader the reader.
|
|
* @param version the format version.
|
|
* @return a DivDataErrors.
|
|
*/
|
|
DivDataErrors readInsData(SafeReader& reader, short version, DivSong* song=NULL);
|
|
|
|
/**
|
|
* save this instrument to a file.
|
|
* @param path file path.
|
|
* @param song if new format, a DivSong to read wavetables and samples.
|
|
* @param writeInsName whether to write the instrument name or not. ignored if old format.
|
|
* @return whether it was successful.
|
|
*/
|
|
bool save(const char* path, DivSong* song=NULL, bool writeInsName=true);
|
|
|
|
/**
|
|
* save this instrument to a file in .dmp format.
|
|
* @param path file path.
|
|
* @return whether it was successful.
|
|
*/
|
|
bool saveDMP(const char* path);
|
|
DivInstrument():
|
|
name(""),
|
|
type(DIV_INS_FM) {
|
|
}
|
|
};
|
|
#endif
|