From ae7382f7a96077576a0f75e8d391fc84cbd7b024 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 19 Nov 2022 18:13:17 -0500 Subject: [PATCH] new ins format, part 1 --- papers/newIns.md | 310 +++++++++++++++++++++++++++++++++++++- src/engine/instrument.cpp | 294 ++++++++++++++++++++++++++---------- src/engine/instrument.h | 7 +- 3 files changed, 519 insertions(+), 92 deletions(-) diff --git a/papers/newIns.md b/papers/newIns.md index 425d39ea..8152bd84 100644 --- a/papers/newIns.md +++ b/papers/newIns.md @@ -48,20 +48,34 @@ the following feature codes are recognized: - `SU`: Sound Unit ins data - `ES`: ES5506 ins data - `X1`: X1-010 ins data +- `EN`: end of features + - if you find this feature code, stop reading the instrument. + - it will usually appear only when there sample/wave lists. + +# instrument name (NA) + +``` +size | description +-----|------------------------------------ + STR | instrument name +``` # FM data (FM) ``` size | description -----|------------------------------------ - 1 | operator count + 1 | flags + | - bit 4-7: op enabled + | - op order from 4 to 7: 0, 2, 1, 3 + | - 2-op instruments: 0, 1, x, x + | - bit 0-3: op count -----|------------------------------------ | **base data** | /7 6 5 4 3 2 1 0| 1 | |x| ALG |x| FB | 1 | |FMS2 |AMS| FMS | 1 | |AM2|4| LLPatch | - 1 | |KV4|KV3|KV2|KV1| -----|------------------------------------ | **operator data × opCount** | /7 6 5 4 3 2 1 0| @@ -73,11 +87,11 @@ size | description | \- VIB 1 | |A|KSL| D R | | \- AM - 1 | |e|x| D2R | + 1 | |e|KVS| D2R | | \- EGT 1 | | S L | R R | 1 | | DVB | SSG | - 1 | | DAM | W S | + 1 | | DAM |DT2| W S | ``` # macro data (MA) @@ -113,8 +127,8 @@ size | description | - 15: ex4 | - 16: ex5 | - 17: ex6 - | - 17: ex7 - | - 18: ex8 + | - 18: ex7 + | - 19: ex8 | - 255: stop reading and move on 1 | macro length 1 | macro loop @@ -137,3 +151,287 @@ size | description | - length: macro length × word sizs ``` +# C64 data (64) + +``` +size | description +-----|------------------------------------ + 1 | flags 1 + | - bit 7: dutyIsAbs + | - bit 6: initFter + | - bit 5: volIsCutoff + | - bit 4: toFilter + | - bit 3: noise on + | - bit 2: pulse on + | - bit 1: saw on + | - bit 0: triangle on + 1 | flags 2 + | - bit 7: oscSync + | - bit 6: ringMod + | - bit 5: noTest + | - bit 4: filterIsAbs + | - bit 3: ch3off + | - bit 2: band pass + | - bit 1: high pass + | - bit 0: low pass + 1 | attack/decay + | - bit 4-7: attack + | - bit 0-3: decay + 1 | sustain release + | - bit 4-7: sustain + | - bit 0-3: release + 2 | duty + 2 | cutoff/resonance + | - bit 12-15: resonance + | - bit 0-10: cutoff +``` + +# Game Boy data (GB) + +``` +size | description +-----|------------------------------------ + 1 | envelope params + | - bit 5-7: length + | - bit 4: direction + | - bit 0-3: volume + 1 | sound length + | - 64 is infinity + 1 | flags + | - bit 1: always init envelope + | - bit 0: software envelope (zombie mode) + 1 | hardware sequence length + ??? | hardware sequence... + | - length: 3*hwSeqLen +``` + +a value in the hardware sequence has the following format: + +``` +size | description +-----|------------------------------------ + 1 | command + | - 0: set envelope + | - 1: set sweep + | - 2: wait + | - 3: wait for release + | - 4: loop + | - 5: loop until release + 2 | data + | - for set envelope: + | - 1 byte: parameter + | - bit 4-7: volume + | - bit 3: direction + | - bit 0-2: length + | - 1 byte: sound length + | - for set sweep: + | - 1 byte: parameter + | - bit 4-6: length + | - bit 3: direction + | - bit 0-2: shift + | - 1 byte: nothing + | - for wait: + | - 1 byte: length (in ticks) + | - 1 byte: nothing + | - for wait for release: + | - 2 bytes: nothing + | - for loop/loop until release: + | - 2 bytes: position +``` + +# sample ins data (SM) + +``` +size | description +-----|------------------------------------ + 2 | initial sample + 1 | flags + | - bit 2: use wave + | - bit 1: use sample + | - bit 0: use sample map + 1 | waveform length + 4?? | sample map... (120 entries) + | - only read if sample map is enabled +``` + +the sample map format: + +``` +size | description +-----|------------------------------------ + 2 | note to play + 2 | sample to play +``` + +# operator macro data (O1, O2, O3 and O4) + +similar to macro data, but using these macro codes: + +- 0: AM +- 1: AR +- 2: DR +- 3: MULT +- 4: RR +- 5: SL +- 6: TL +- 7: DT2 +- 8: RS +- 9: DT +- 10: D2R +- 11: SSG-EG +- 12: DAM +- 13: DVB +- 14: EGT +- 15: KSL +- 16: SUS +- 17: VIB +- 18: WS +- 19: KSR + +# OPL drums mode data (LD) + +``` +size | description +-----|------------------------------------ + 1 | fixed frequency mode + 2 | kick freq + 2 | snare/hat freq + 2 | tom/top freq +``` + +# SNES data (SN) + +``` +size | description +-----|------------------------------------ + 1 | attack/decay + | - bit 4-6: decay + | - bit 0-3: attack + 1 | sustain/release + | - bit 5-6: sustain + | - bit 0-4: release + 1 | flags + | - bit 4: envelope on + | - bit 3: make sustain effective + | - bit 0-2: gain mode + | - 0: direct + | - 4: dec + | - 5: exp + | - 6: inc + | - 7: bent + 1 | gain +``` + +# Namco 163 data (N1) + +``` +size | description +-----|------------------------------------ + 4 | waveform + 1 | wave pos + 1 | wave len + 1 | wave mode +``` + +# FDS/Virtual Boy data (FD) + +``` +size | description +-----|------------------------------------ + 4 | mod speed + 4 | mod depth + 1 | init mod table with first wave + 1?? | modulation table (32 entries) +``` + +# wavetable synth data (WS) + +``` +size | description +-----|------------------------------------ + 4 | first wave + 4 | second wave + 1 | rate divider + 1 | effect + | - bit 7: single or dual effect + 1 | enabled + 1 | global + 1 | speed (+1) + 1 | parameter 1 + 1 | parameter 2 + 1 | parameter 3 + 1 | parameter 4 +``` + +# list of samples (SL) + +``` +size | description +-----|------------------------------------ + 1 | number of samples + 4?? | pointers to samples... + | - these use the Furnace sample format. +``` + +# list of wavetables (WL) + +``` +size | description +-----|------------------------------------ + 1 | number of wavetables + 4?? | pointers to wavetables... + | - these use the Furnace wavetable format. +``` + +# MultiPCM data (MP) + +``` +size | description +-----|------------------------------------ + 1 | attack rate + 1 | decay 1 rate + 1 | decay level + 1 | decay 2 rate + 1 | release rate + 1 | rate correction + 1 | LFO rate + 1 | vibrato depth + 1 | AM depth +``` + +# Sound Unit data (SU) + +``` +size | description +-----|------------------------------------ + 1 | switch roles of phase reset timer and frequency +``` + +# ES5506 data (ES) + +``` +size | description +-----|------------------------------------ + 1 | filter mode + | - 0: HPK2_HPK2 + | - 1: HPK2_LPK1 + | - 2: LPK2_LPK2 + | - 3: LPK2_LPK1 + 2 | K1 + 2 | K2 + 2 | envelope count + 1 | left volume ramp + 1 | right volume ramp + 1 | K1 ramp + 1 | K2 ramp + 1 | K1 slow + 1 | K2 slow +``` + +# X1-010 data (X1) + +``` +size | description +-----|------------------------------------ + 4 | bank slot +``` diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index af672171..9815370a 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -25,78 +25,6 @@ const DivInstrument defaultIns; -void DivInstrument::writeFeatureNA(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureFM(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureMA(SafeWriter* w) { - -} - -void DivInstrument::writeFeature64(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureGB(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureSM(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureOx(SafeWriter* w, int op) { - -} - -void DivInstrument::writeFeatureLD(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureSN(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureN1(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureFD(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureWS(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureSL(SafeWriter* w, const DivSong* song) { - -} - -void DivInstrument::writeFeatureWL(SafeWriter* w, const DivSong* song) { - -} - -void DivInstrument::writeFeatureMP(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureSU(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureES(SafeWriter* w) { - -} - -void DivInstrument::writeFeatureX1(SafeWriter* w) { - -} - #define _C(x) x==other.x bool DivInstrumentFM::operator==(const DivInstrumentFM& other) { @@ -282,8 +210,212 @@ bool DivInstrumentSNES::operator==(const DivInstrumentSNES& other) { ); } +#undef _C + +#define FEATURE_BEGIN(x) \ + w->write(x,2); \ + size_t featStartSeek=w->tell(); \ + w->writeS(0); + +#define FEATURE_END \ + size_t featEndSeek=w->tell(); \ + w->seek(featStartSeek,SEEK_SET); \ + w->writeS(featEndSeek-featStartSeek-2); \ + w->seek(featEndSeek,SEEK_SET); + +void DivInstrument::writeFeatureNA(SafeWriter* w) { + FEATURE_BEGIN("NA"); + + w->writeString(name,false); + + FEATURE_END; +} + +void DivInstrument::writeFeatureFM(SafeWriter* w, bool fui) { + FEATURE_BEGIN("FM"); + + int opCount=4; + if (fui) { + if (type==DIV_INS_OPLL) { + opCount=2; + } else if (type==DIV_INS_OPL) { + opCount=(fm.ops==4)?4:2; + } + } + + w->writeC( + (fm.op[3].enable?128:0)| + (fm.op[2].enable?64:0)| + (fm.op[1].enable?32:0)| + (fm.op[0].enable?16:0)| + opCount + ); + + // base data + w->writeC(((fm.alg&7)<<4)|(fm.fb&7)); + w->writeC(((fm.fms2&7)<<5)|((fm.ams&3)<<3)|(fm.fms&7)); + w->writeC(((fm.ams2&3)<<6)|((fm.ops==4)?32:0)|(fm.opllPreset&31)); + + // operator data + for (int i=0; iwriteC((op.ksr?128:0)|((op.dt&7)<<4)|(op.mult&15)); + w->writeC((op.sus?128:0)|(op.tl&127)); + w->writeC(((op.rs&3)<<6)|(op.vib?32:0)|(op.ar&31)); + w->writeC((op.am?128:0)|((op.ksl&3)<<5)|(op.dr&31)); + w->writeC((op.egt?128:0)|((op.kvs&3)<<5)|(op.d2r&31)); + w->writeC(((op.sl&15)<<4)|(op.rr&15)); + w->writeC(((op.dvb&15)<<4)|(op.ssgEnv&15)); + w->writeC(((op.dam&7)<<5)|((op.dt2&3)<<3)|(op.ws&7)); + } + + FEATURE_END; +} + +void DivInstrument::writeMacro(SafeWriter* w, const DivInstrumentMacro& m, unsigned char macroCode) { + if (!m.len) return; + + // determine word size + int macroMin=0x7fffffff; + int macroMax=0x80000000; + for (int i=0; imacroMax) macroMax=m.val[i]; + } + + unsigned char wordSize=192; // 32-bit + + if (macroMin>=0 && macroMax<=255) { + wordSize=0; // 8-bit unsigned + } else if (macroMin>=-128 && macroMax<=127) { + wordSize=64; // 8-bit signed + } else if (macroMin>=-32768 && macroMax<=32767) { + wordSize=128; // 16-bit signed + } else { + wordSize=192; // 32-bit signed + } + + w->writeC(macroCode); + w->writeC(m.len); + w->writeC(m.loop); + w->writeC(m.rel); + w->writeC(m.mode); + w->writeC(m.open|wordSize); + w->writeC(m.delay); + w->writeC(m.speed); + + switch (wordSize) { + case 0: + for (int i=0; iwriteC((unsigned char)m.val[i]); + } + break; + case 64: + for (int i=0; iwriteC((signed char)m.val[i]); + } + break; + case 128: + for (int i=0; iwriteS((short)m.val[i]); + } + break; + default: // 192 + for (int i=0; iwriteI(m.val[i]); + } + break; + } +} + +void DivInstrument::writeFeatureMA(SafeWriter* w) { + FEATURE_BEGIN("MA"); + + // if you update the macro header, please update this value as well. + // it's the length. + w->writeS(8); + + // write macros + writeMacro(w,std.volMacro,0); + writeMacro(w,std.arpMacro,1); + writeMacro(w,std.dutyMacro,2); + writeMacro(w,std.waveMacro,3); + writeMacro(w,std.pitchMacro,4); + writeMacro(w,std.ex1Macro,5); + writeMacro(w,std.ex2Macro,6); + writeMacro(w,std.ex3Macro,7); + writeMacro(w,std.algMacro,8); + writeMacro(w,std.fbMacro,9); + writeMacro(w,std.fmsMacro,10); + writeMacro(w,std.amsMacro,11); + writeMacro(w,std.panLMacro,12); + writeMacro(w,std.panRMacro,13); + writeMacro(w,std.phaseResetMacro,14); + writeMacro(w,std.ex4Macro,15); + writeMacro(w,std.ex5Macro,16); + writeMacro(w,std.ex6Macro,17); + writeMacro(w,std.ex7Macro,18); + writeMacro(w,std.ex8Macro,19); + + // "stop reading" code + w->writeC(255); + + FEATURE_END; +} + +void DivInstrument::writeFeature64(SafeWriter* w) { + FEATURE_BEGIN("64"); + + FEATURE_END; +} + +void DivInstrument::writeFeatureGB(SafeWriter* w) { +} + +void DivInstrument::writeFeatureSM(SafeWriter* w) { +} + +void DivInstrument::writeFeatureOx(SafeWriter* w, int op) { +} + +void DivInstrument::writeFeatureLD(SafeWriter* w) { +} + +void DivInstrument::writeFeatureSN(SafeWriter* w) { +} + +void DivInstrument::writeFeatureN1(SafeWriter* w) { +} + +void DivInstrument::writeFeatureFD(SafeWriter* w) { +} + +void DivInstrument::writeFeatureWS(SafeWriter* w) { +} + +void DivInstrument::writeFeatureSL(SafeWriter* w, std::vector& list, const DivSong* song) { +} + +void DivInstrument::writeFeatureWL(SafeWriter* w, std::vector& list, const DivSong* song) { +} + +void DivInstrument::writeFeatureMP(SafeWriter* w) { +} + +void DivInstrument::writeFeatureSU(SafeWriter* w) { +} + +void DivInstrument::writeFeatureES(SafeWriter* w) { +} + +void DivInstrument::writeFeatureX1(SafeWriter* w) { +} + void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { size_t blockStartSeek, blockEndSeek; + std::vector waveList; + std::vector sampleList; if (fui) { w->write("FINS",4); @@ -609,7 +741,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { writeFeatureNA(w); } if (featureFM) { - writeFeatureFM(w); + writeFeatureFM(w,fui); } if (featureMA) { writeFeatureMA(w); @@ -644,10 +776,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { writeFeatureWS(w); } if (featureSL) { - writeFeatureSL(w,song); + writeFeatureSL(w,sampleList,song); } if (featureWL) { - writeFeatureWL(w,song); + writeFeatureWL(w,waveList,song); } if (featureMP) { writeFeatureMP(w); @@ -661,14 +793,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { if (featureX1) { writeFeatureX1(w); } - if (featureNA) { - writeFeatureNA(w); - } - if (featureNA) { - writeFeatureNA(w); - } - if (featureNA) { - writeFeatureNA(w); + + if (fui && (featureSL || featureWL)) { + w->write("EN",2); + // TODO: write wave/sample data here } blockEndSeek=w->tell(); diff --git a/src/engine/instrument.h b/src/engine/instrument.h index feab69c1..3cf65b63 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -641,8 +641,9 @@ struct DivInstrument { /** * these are internal functions. */ + void writeMacro(SafeWriter* w, const DivInstrumentMacro& m, unsigned char macroCode); void writeFeatureNA(SafeWriter* w); - void writeFeatureFM(SafeWriter* w); + void writeFeatureFM(SafeWriter* w, bool fui); void writeFeatureMA(SafeWriter* w); void writeFeature64(SafeWriter* w); void writeFeatureGB(SafeWriter* w); @@ -653,8 +654,8 @@ struct DivInstrument { void writeFeatureN1(SafeWriter* w); void writeFeatureFD(SafeWriter* w); void writeFeatureWS(SafeWriter* w); - void writeFeatureSL(SafeWriter* w, const DivSong* song); - void writeFeatureWL(SafeWriter* w, const DivSong* song); + void writeFeatureSL(SafeWriter* w, std::vector& list, const DivSong* song); + void writeFeatureWL(SafeWriter* w, std::vector& list, const DivSong* song); void writeFeatureMP(SafeWriter* w); void writeFeatureSU(SafeWriter* w); void writeFeatureES(SafeWriter* w);