furnace/src/engine/instrument.h
cam900 028adf2c8e Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
* 'master' of https://github.com/tildearrow/furnace: (70 commits)
  whoops
  GUI: AY8930 credits
  GUI: fix inability to close subsongs
  BANK
  OPN: wire up ExtCh system
  fix build failure
  dev95 - multiple songs in a single file (READ)
  DO NOT USE - THIS FAILS - WORK IN PROGRESS
  enforce asset limits
  old .dmf loading improvements
  add AICA and YMZ ADPCM formats
  allocate ID for YMZ280B
  harden .fur file saver
  Fix AY VGM output, Fix presets
  preparations for UI improvements
  GUI: add more presets
  prepare for ExtCh OPN/OPNA
  GUI: clarify that lock layout doesn't work yet
  GUI: remember last state of order edit mode
  GUI: store edit/followOrders/followPattern state
  ...

# Conflicts:
#	src/engine/fileOps.cpp
#	src/engine/platform/ym2610.cpp
#	src/engine/platform/ym2610b.cpp
#	src/engine/sample.cpp
#	src/engine/sample.h
#	src/engine/sysDef.cpp
#	src/gui/doAction.cpp
#	src/gui/sysConf.cpp
2022-05-18 03:09:55 +09:00

593 lines
13 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 _INSTRUMENT_H
#define _INSTRUMENT_H
#include <vector>
#include "sample.h"
#include "safeWriter.h"
#include "dataErrors.h"
#include "../ta-utils.h"
// 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_MAX,
DIV_INS_NULL
};
// 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;
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
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) {}
} 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 {
String name;
int val[256];
unsigned int mode;
bool open;
unsigned char len;
signed char loop;
signed char rel;
// the following variables are used by the GUI and not saved in the file
int vScroll, vZoom;
explicit DivInstrumentMacro(const String& n, bool initOpen=false):
name(n),
mode(0),
open(initOpen),
len(0),
loop(-1),
rel(-1),
vScroll(0),
vZoom(-1) {
memset(val,0,256*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("am"), arMacro("ar"), drMacro("dr"), multMacro("mult"),
rrMacro("rr"), slMacro("sl"), tlMacro("tl",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") {}
} opMacros[4];
DivInstrumentSTD():
volMacro("vol",true),
arpMacro("arp"),
dutyMacro("duty"),
waveMacro("wave"),
pitchMacro("pitch"),
ex1Macro("ex1"),
ex2Macro("ex2"),
ex3Macro("ex3"),
algMacro("alg"),
fbMacro("fb"),
fmsMacro("fms"),
amsMacro("ams"),
panLMacro("panL"),
panRMacro("panR"),
phaseResetMacro("phaseReset"),
ex4Macro("ex4"),
ex5Macro("ex5"),
ex6Macro("ex6"),
ex7Macro("ex7"),
ex8Macro("ex8") {}
};
struct DivInstrumentGB {
unsigned char envVol, envDir, envLen, soundLen;
DivInstrumentGB():
envVol(15),
envDir(0),
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, noTest;
unsigned char res;
unsigned short cut;
bool hp, lp, bp, ch3off;
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),
volIsCutoff(false),
initFilter(false),
dutyIsAbs(false),
filterIsAbs(false),
noTest(false),
res(0),
cut(0),
hp(false),
lp(false),
bp(false),
ch3off(false) {}
};
struct DivInstrumentAmiga {
struct NoteMap {
int freq;
short ind;
unsigned char reversed;
NoteMap():
freq(0),
ind(-1),
reversed(false) {}
};
struct TransWaveSlice {
// states
double sliceSize;
double sliceBound;
double sliceStart;
double sliceEnd;
// inlines
inline double updateSize(double length, double loopStart, double loopEnd) {
sliceSize=loopEnd-loopStart;
sliceBound=(length-sliceSize);
}
inline double slicePos(double slice) {
double pos=sliceBound*slice;
if (sliceStart!=pos) {
sliceStart=pos;
}
if (sliceEnd!=(sliceSize+pos)) {
sliceEnd=(sliceSize+pos);
}
return pos;
}
TransWaveSlice():
sliceSize(0),
sliceBound(0),
sliceStart(0),
sliceEnd(0) {}
};
struct TransWave: TransWaveSlice {
bool enable;
bool sliceEnable;
int ind;
unsigned short slice;
TransWave():
TransWaveSlice(),
enable(false),
sliceEnable(false),
ind(0),
slice(0) {}
};
struct TransWaveMap: TransWaveSlice {
short ind;
unsigned char reversed;
int loopStart, loopEnd;
DivSampleLoopMode loopMode;
TransWaveMap():
TransWaveSlice(),
ind(-1),
reversed(0),
loopStart(-1),
loopEnd(-1),
loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {}
};
short initSample;
bool reversed;
bool useNoteMap;
bool useWave;
unsigned char waveLen;
NoteMap noteMap[120];
TransWave transWave;
std::vector<TransWaveMap> transWaveMap;
/**
* 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].ind;
}
return initSample;
}
/**
* get the sample frequency at specified note.
* @return the frequency, 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 -1;
}
/**
* get the sample reversed flag at specified note.
* @return the reversed flag.
*/
inline bool getReversed(int note) {
if (useNoteMap) {
if (note<0) note=0;
if (note>119) note=119;
return noteMap[note].reversed;
}
return reversed;
}
DivInstrumentAmiga():
initSample(0),
reversed(false),
useNoteMap(false),
useWave(false),
waveLen(31),
transWaveMap(1) {}
};
struct DivInstrumentN163 {
int wave, wavePos, waveLen;
unsigned char waveMode;
DivInstrumentN163():
wave(-1),
wavePos(0),
waveLen(32),
waveMode(3) {}
};
struct DivInstrumentFDS {
signed char modTable[32];
int modSpeed, modDepth;
// this is here for compatibility.
bool initModTableWithFirstWave;
DivInstrumentFDS():
modSpeed(0),
modDepth(0),
initModTableWithFirstWave(false) {
memset(modTable,0,32);
}
};
struct DivInstrumentES5506 {
struct Filter {
enum FilterMode: unsigned char { // filter mode for pole 4,3
FILTER_MODE_HPK2_HPK2,
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) {}
};
signed int lVol, rVol;
Filter filter;
Envelope envelope;
DivInstrumentES5506():
lVol(0xffff),
rVol(0xffff) {}
};
struct DivInstrumentMultiPCM {
unsigned char ar, d1r, dl, d2r, rr, rc;
unsigned char lfo, vib, am;
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_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_PHASE_DUAL,
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;
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 DivInstrument {
String name;
bool mode;
DivInstrumentType type;
DivInstrumentFM fm;
DivInstrumentSTD std;
DivInstrumentGB gb;
DivInstrumentC64 c64;
DivInstrumentAmiga amiga;
DivInstrumentN163 n163;
DivInstrumentFDS fds;
DivInstrumentES5506 es5506;
DivInstrumentMultiPCM multipcm;
DivInstrumentWaveSynth ws;
/**
* save the instrument to a SafeWriter.
* @param w the SafeWriter in question.
*/
void putInsData(SafeWriter* w);
/**
* read instrument data in .fui format.
* @param reader the reader.
* @param version the format version.
* @return a DivDataErrors.
*/
DivDataErrors readInsData(SafeReader& reader, short version);
/**
* save this instrument to a file.
* @param path file path.
* @return whether it was successful.
*/
bool save(const char* path);
DivInstrument():
name(""),
mode(false),
type(DIV_INS_FM) {
}
};
#endif