From 42ccba822ccf1630cd7ba1462c33792bf9a36f78 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Mar 2024 15:39:52 -0500 Subject: [PATCH] why is text export in .dmf --- CMakeLists.txt | 1 + src/engine/fileOps/dmf.cpp | 352 ---------------------------------- src/engine/fileOps/text.cpp | 372 ++++++++++++++++++++++++++++++++++++ 3 files changed, 373 insertions(+), 352 deletions(-) create mode 100644 src/engine/fileOps/text.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2779c8b54..8bedba4ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -624,6 +624,7 @@ src/engine/fileOps/ftm.cpp src/engine/fileOps/fur.cpp src/engine/fileOps/mod.cpp src/engine/fileOps/s3m.cpp +src/engine/fileOps/text.cpp src/engine/blip_buf.c src/engine/brrUtils.c diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index d317aab8c..d226a54e8 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -1626,355 +1626,3 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { saveLock.unlock(); return w; } - -static const char* trueFalse[2]={ - "no", "yes" -}; - -static const char* gbEnvDir[2]={ - "down", "up" -}; - -static const char* notes[12]={ - "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" -}; - -static const char* notesNegative[12]={ - "c_", "c+", "d_", "d+", "e_", "f_", "f+", "g_", "g+", "a_", "a+", "b_" -}; - -static const char* sampleLoopModes[4]={ - "forward", "backward", "ping-pong", "invalid" -}; - -void writeTextMacro(SafeWriter* w, DivInstrumentMacro& m, const char* name, bool& wroteMacroHeader) { - if ((m.open&6)==0 && m.len<1) return; - if (!wroteMacroHeader) { - w->writeText("- macros:\n"); - wroteMacroHeader=true; - } - w->writeText(fmt::sprintf(" - %s:",name)); - int len=m.len; - switch (m.open&6) { - case 2: - len=16; - w->writeText(" [ADSR]"); - break; - case 4: - len=16; - w->writeText(" [LFO]"); - break; - } - if (m.mode) { - w->writeText(fmt::sprintf(" [MODE %d]",m.mode)); - } - if (m.delay>0) { - w->writeText(fmt::sprintf(" [DELAY %d]",m.delay)); - } - if (m.speed>1) { - w->writeText(fmt::sprintf(" [SPEED %d]",m.speed)); - } - for (int i=0; iwriteText(" |"); - } - if (i==m.rel) { - w->writeText(" /"); - } - w->writeText(fmt::sprintf(" %d",m.val[i])); - } - w->writeText("\n"); -} - -SafeWriter* DivEngine::saveText(bool separatePatterns) { - saveLock.lock(); - - SafeWriter* w=new SafeWriter; - w->init(); - - w->writeText(fmt::sprintf("# Furnace Text Export\n\ngenerated by Furnace %s (%d)\n\n# Song Information\n\n",DIV_VERSION,DIV_ENGINE_VERSION)); - w->writeText(fmt::sprintf("- name: %s\n",song.name)); - w->writeText(fmt::sprintf("- author: %s\n",song.author)); - w->writeText(fmt::sprintf("- album: %s\n",song.category)); - w->writeText(fmt::sprintf("- system: %s\n",song.systemName)); - w->writeText(fmt::sprintf("- tuning: %g\n\n",song.tuning)); - - w->writeText(fmt::sprintf("- instruments: %d\n",song.insLen)); - w->writeText(fmt::sprintf("- wavetables: %d\n",song.waveLen)); - w->writeText(fmt::sprintf("- samples: %d\n\n",song.sampleLen)); - - w->writeText("# Sound Chips\n\n"); - - for (int i=0; iwriteText(fmt::sprintf("- %s\n",getSystemName(song.system[i]))); - w->writeText(fmt::sprintf(" - id: %.2X\n",(int)song.system[i])); - w->writeText(fmt::sprintf(" - volume: %g\n",song.systemVol[i])); - w->writeText(fmt::sprintf(" - panning: %g\n",song.systemPan[i])); - w->writeText(fmt::sprintf(" - front/rear: %g\n",song.systemPanFR[i])); - - String sysFlags=song.systemFlags[i].toString(); - - if (!sysFlags.empty()) { - w->writeText(fmt::sprintf(" - flags:\n```\n%s\n```\n",sysFlags)); - } - } - - if (!song.notes.empty()) { - w->writeText("\n# Song Comments\n\n"); - w->writeText(song.notes); - } - - w->writeText("\n# Instruments\n\n"); - - for (int i=0; iwriteText(fmt::sprintf("## %.2X: %s\n\n",i,ins->name)); - - w->writeText(fmt::sprintf("- type: %d\n",(int)ins->type)); - - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPM || ins->type==DIV_INS_ESFM) { - w->writeText("- FM parameters:\n"); - w->writeText(fmt::sprintf(" - ALG: %d\n",ins->fm.alg)); - w->writeText(fmt::sprintf(" - FB: %d\n",ins->fm.fb)); - w->writeText(fmt::sprintf(" - FMS: %d\n",ins->fm.fms)); - w->writeText(fmt::sprintf(" - AMS: %d\n",ins->fm.ams)); - w->writeText(fmt::sprintf(" - FMS2: %d\n",ins->fm.fms2)); - w->writeText(fmt::sprintf(" - AMS2: %d\n",ins->fm.ams2)); - w->writeText(fmt::sprintf(" - operators: %d\n",ins->fm.ops)); - w->writeText(fmt::sprintf(" - OPLL patch: %d\n",ins->fm.opllPreset)); - w->writeText(fmt::sprintf(" - fixed drum freq: %s\n",trueFalse[ins->fm.fixedDrums?1:0])); - w->writeText(fmt::sprintf(" - kick freq: %.4X\n",ins->fm.kickFreq)); - w->writeText(fmt::sprintf(" - snare/hat freq: %.4X\n",ins->fm.snareHatFreq)); - w->writeText(fmt::sprintf(" - tom/top freq: %.4X\n",ins->fm.tomTopFreq)); - - for (int j=0; jfm.ops; j++) { - DivInstrumentFM::Operator& op=ins->fm.op[j]; - - w->writeText(fmt::sprintf(" - operator %d:\n",j)); - w->writeText(fmt::sprintf(" - enabled: %s\n",trueFalse[op.enable?1:0])); - w->writeText(fmt::sprintf(" - AM: %d\n",op.am)); - w->writeText(fmt::sprintf(" - AR: %d\n",op.ar)); - w->writeText(fmt::sprintf(" - DR: %d\n",op.dr)); - w->writeText(fmt::sprintf(" - MULT: %d\n",op.mult)); - w->writeText(fmt::sprintf(" - RR: %d\n",op.rr)); - w->writeText(fmt::sprintf(" - SL: %d\n",op.sl)); - w->writeText(fmt::sprintf(" - TL: %d\n",op.tl)); - w->writeText(fmt::sprintf(" - DT2: %d\n",op.dt2)); - w->writeText(fmt::sprintf(" - RS: %d\n",op.rs)); - w->writeText(fmt::sprintf(" - DT: %d\n",op.dt)); - w->writeText(fmt::sprintf(" - D2R: %d\n",op.d2r)); - w->writeText(fmt::sprintf(" - SSG-EG: %d\n",op.ssgEnv)); - w->writeText(fmt::sprintf(" - DAM: %d\n",op.dam)); - w->writeText(fmt::sprintf(" - DVB: %d\n",op.dvb)); - w->writeText(fmt::sprintf(" - EGT: %d\n",op.egt)); - w->writeText(fmt::sprintf(" - KSL: %d\n",op.ksl)); - w->writeText(fmt::sprintf(" - SUS: %d\n",op.sus)); - w->writeText(fmt::sprintf(" - VIB: %d\n",op.vib)); - w->writeText(fmt::sprintf(" - WS: %d\n",op.ws)); - w->writeText(fmt::sprintf(" - KSR: %d\n",op.ksr)); - w->writeText(fmt::sprintf(" - TL volume scale: %d\n",op.kvs)); - } - } - - if (ins->type==DIV_INS_ESFM) { - w->writeText("- ESFM parameters:\n"); - w->writeText(fmt::sprintf(" - noise mode: %d\n",ins->esfm.noise)); - - for (int j=0; jfm.ops; j++) { - DivInstrumentESFM::Operator& opE=ins->esfm.op[j]; - - w->writeText(fmt::sprintf(" - operator %d:\n",j)); - w->writeText(fmt::sprintf(" - DL: %d\n",opE.delay)); - w->writeText(fmt::sprintf(" - OL: %d\n",opE.outLvl)); - w->writeText(fmt::sprintf(" - MI: %d\n",opE.modIn)); - w->writeText(fmt::sprintf(" - output left: %s\n",trueFalse[opE.left?1:0])); - w->writeText(fmt::sprintf(" - output right: %s\n",trueFalse[opE.right?1:0])); - w->writeText(fmt::sprintf(" - CT: %d\n",opE.ct)); - w->writeText(fmt::sprintf(" - DT: %d\n",opE.dt)); - w->writeText(fmt::sprintf(" - fixed frequency: %s\n",trueFalse[opE.fixed?1:0])); - } - } - - if (ins->type==DIV_INS_GB) { - w->writeText("- Game Boy parameters:\n"); - w->writeText(fmt::sprintf(" - volume: %d\n",ins->gb.envVol)); - w->writeText(fmt::sprintf(" - direction: %s\n",gbEnvDir[ins->gb.envDir?1:0])); - w->writeText(fmt::sprintf(" - length: %d\n",ins->gb.envLen)); - w->writeText(fmt::sprintf(" - sound length: %d\n",ins->gb.soundLen)); - w->writeText(fmt::sprintf(" - use software envelope: %s\n",trueFalse[ins->gb.softEnv?1:0])); - w->writeText(fmt::sprintf(" - always initialize: %s\n",trueFalse[ins->gb.softEnv?1:0])); - if (ins->gb.hwSeqLen>0) { - w->writeText(" - hardware sequence:\n"); - for (int j=0; jgb.hwSeqLen; j++) { - w->writeText(fmt::sprintf(" - %d: %.2X %.4X\n",j,ins->gb.hwSeq[j].cmd,ins->gb.hwSeq[j].data)); - } - } - } - - bool header=false; - writeTextMacro(w,ins->std.volMacro,"vol",header); - writeTextMacro(w,ins->std.arpMacro,"arp",header); - writeTextMacro(w,ins->std.dutyMacro,"duty",header); - writeTextMacro(w,ins->std.waveMacro,"wave",header); - writeTextMacro(w,ins->std.pitchMacro,"pitch",header); - writeTextMacro(w,ins->std.panLMacro,"panL",header); - writeTextMacro(w,ins->std.panRMacro,"panR",header); - writeTextMacro(w,ins->std.phaseResetMacro,"phaseReset",header); - writeTextMacro(w,ins->std.ex1Macro,"ex1",header); - writeTextMacro(w,ins->std.ex2Macro,"ex2",header); - writeTextMacro(w,ins->std.ex3Macro,"ex3",header); - writeTextMacro(w,ins->std.ex4Macro,"ex4",header); - writeTextMacro(w,ins->std.ex5Macro,"ex5",header); - writeTextMacro(w,ins->std.ex6Macro,"ex6",header); - writeTextMacro(w,ins->std.ex7Macro,"ex7",header); - writeTextMacro(w,ins->std.ex8Macro,"ex8",header); - writeTextMacro(w,ins->std.algMacro,"alg",header); - writeTextMacro(w,ins->std.fbMacro,"fb",header); - writeTextMacro(w,ins->std.fmsMacro,"fms",header); - writeTextMacro(w,ins->std.amsMacro,"ams",header); - - // TODO: the rest - w->writeText("\n"); - } - - w->writeText("\n# Wavetables\n\n"); - - for (int i=0; iwriteText(fmt::sprintf("- %d (%dx%d):",i,wave->len+1,wave->max+1)); - for (int j=0; j<=wave->len; j++) { - w->writeText(fmt::sprintf(" %d",wave->data[j])); - } - w->writeText("\n"); - } - - w->writeText("\n# Samples\n\n"); - - for (int i=0; iwriteText(fmt::sprintf("## %.2X: %s\n\n",i,sample->name)); - - w->writeText(fmt::sprintf("- format: %d\n",(int)sample->depth)); - w->writeText(fmt::sprintf("- data length: %d\n",sample->getCurBufLen())); - w->writeText(fmt::sprintf("- samples: %d\n",sample->samples)); - w->writeText(fmt::sprintf("- rate: %d\n",sample->centerRate)); - w->writeText(fmt::sprintf("- compat rate: %d\n",sample->rate)); - w->writeText(fmt::sprintf("- loop: %s\n",trueFalse[sample->loop?1:0])); - if (sample->loop) { - w->writeText(fmt::sprintf(" - start: %d\n",sample->loopStart)); - w->writeText(fmt::sprintf(" - end: %d\n",sample->loopEnd)); - w->writeText(fmt::sprintf(" - mode: %s\n",sampleLoopModes[sample->loopMode&3])); - } - w->writeText(fmt::sprintf("- BRR emphasis: %s\n",trueFalse[sample->brrEmphasis?1:0])); - w->writeText(fmt::sprintf("- dither: %s\n",trueFalse[sample->dither?1:0])); - - // TODO' render matrix - unsigned char* buf=(unsigned char*)sample->getCurBuf(); - unsigned int bufLen=sample->getCurBufLen(); - w->writeText("\n```"); - for (unsigned int i=0; iwriteText(fmt::sprintf("\n%.8X:",i)); - w->writeText(fmt::sprintf(" %.2X",buf[i])); - } - w->writeText("\n```\n\n"); - } - - w->writeText("\n# Subsongs\n\n"); - - for (size_t i=0; iwriteText(fmt::sprintf("## %d: %s\n\n",(int)i,s->name)); - - w->writeText(fmt::sprintf("- tick rate: %g\n",s->hz)); - w->writeText(fmt::sprintf("- speeds:")); - for (int j=0; jspeeds.len; j++) { - w->writeText(fmt::sprintf(" %d",s->speeds.val[j])); - } - w->writeText("\n"); - w->writeText(fmt::sprintf("- virtual tempo: %d/%d\n",s->virtualTempoN,s->virtualTempoD)); - w->writeText(fmt::sprintf("- time base: %d\n",s->timeBase)); - w->writeText(fmt::sprintf("- pattern length: %d\n",s->patLen)); - w->writeText(fmt::sprintf("\norders:\n```\n")); - - for (int j=0; jordersLen; j++) { - w->writeText(fmt::sprintf("%.2X |",j)); - for (int k=0; kwriteText(fmt::sprintf(" %.2X",s->orders.ord[k][j])); - } - w->writeText("\n"); - } - w->writeText("```\n\n## Patterns\n\n"); - - if (separatePatterns) { - w->writeText("TODO: separate patterns\n\n"); - } else { - for (int j=0; jordersLen; j++) { - w->writeText(fmt::sprintf("----- ORDER %.2X\n",j)); - - for (int k=0; kpatLen; k++) { - w->writeText(fmt::sprintf("%.2X ",k)); - - for (int l=0; lpat[l].getPattern(s->orders.ord[l][j],false); - - int note=p->data[k][0]; - int octave=p->data[k][1]; - - if (note==0 && octave==0) { - w->writeText("|... "); - } else if (note==100) { - w->writeText("|OFF "); - } else if (note==101) { - w->writeText("|=== "); - } else if (note==102) { - w->writeText("|REL "); - } else if ((octave>9 && octave<250) || note>12) { - w->writeText("|??? "); - } else { - if (octave>=128) octave-=256; - if (note>11) { - note-=12; - octave++; - } - w->writeText(fmt::sprintf("|%s%d ",(octave<0)?notesNegative[note]:notes[note],(octave<0)?(-octave):octave)); - } - - if (p->data[k][2]==-1) { - w->writeText(".. "); - } else { - w->writeText(fmt::sprintf("%.2X ",p->data[k][2]&0xff)); - } - - if (p->data[k][3]==-1) { - w->writeText(".."); - } else { - w->writeText(fmt::sprintf("%.2X",p->data[k][3]&0xff)); - } - - for (int m=0; mpat[l].effectCols; m++) { - if (p->data[k][4+(m<<1)]==-1) { - w->writeText(" .."); - } else { - w->writeText(fmt::sprintf(" %.2X",p->data[k][4+(m<<1)]&0xff)); - } - if (p->data[k][5+(m<<1)]==-1) { - w->writeText(".."); - } else { - w->writeText(fmt::sprintf("%.2X",p->data[k][5+(m<<1)]&0xff)); - } - } - } - - w->writeText("\n"); - } - } - } - - } - - saveLock.unlock(); - return w; -} diff --git a/src/engine/fileOps/text.cpp b/src/engine/fileOps/text.cpp new file mode 100644 index 000000000..6ededd1fd --- /dev/null +++ b/src/engine/fileOps/text.cpp @@ -0,0 +1,372 @@ +/** + * 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. + */ + +#include "fileOpsCommon.h" + +static const char* trueFalse[2]={ + "no", "yes" +}; + +static const char* gbEnvDir[2]={ + "down", "up" +}; + +static const char* notes[12]={ + "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" +}; + +static const char* notesNegative[12]={ + "c_", "c+", "d_", "d+", "e_", "f_", "f+", "g_", "g+", "a_", "a+", "b_" +}; + +static const char* sampleLoopModes[4]={ + "forward", "backward", "ping-pong", "invalid" +}; + +void writeTextMacro(SafeWriter* w, DivInstrumentMacro& m, const char* name, bool& wroteMacroHeader) { + if ((m.open&6)==0 && m.len<1) return; + if (!wroteMacroHeader) { + w->writeText("- macros:\n"); + wroteMacroHeader=true; + } + w->writeText(fmt::sprintf(" - %s:",name)); + int len=m.len; + switch (m.open&6) { + case 2: + len=16; + w->writeText(" [ADSR]"); + break; + case 4: + len=16; + w->writeText(" [LFO]"); + break; + } + if (m.mode) { + w->writeText(fmt::sprintf(" [MODE %d]",m.mode)); + } + if (m.delay>0) { + w->writeText(fmt::sprintf(" [DELAY %d]",m.delay)); + } + if (m.speed>1) { + w->writeText(fmt::sprintf(" [SPEED %d]",m.speed)); + } + for (int i=0; iwriteText(" |"); + } + if (i==m.rel) { + w->writeText(" /"); + } + w->writeText(fmt::sprintf(" %d",m.val[i])); + } + w->writeText("\n"); +} + +SafeWriter* DivEngine::saveText(bool separatePatterns) { + saveLock.lock(); + + SafeWriter* w=new SafeWriter; + w->init(); + + w->writeText(fmt::sprintf("# Furnace Text Export\n\ngenerated by Furnace %s (%d)\n\n# Song Information\n\n",DIV_VERSION,DIV_ENGINE_VERSION)); + w->writeText(fmt::sprintf("- name: %s\n",song.name)); + w->writeText(fmt::sprintf("- author: %s\n",song.author)); + w->writeText(fmt::sprintf("- album: %s\n",song.category)); + w->writeText(fmt::sprintf("- system: %s\n",song.systemName)); + w->writeText(fmt::sprintf("- tuning: %g\n\n",song.tuning)); + + w->writeText(fmt::sprintf("- instruments: %d\n",song.insLen)); + w->writeText(fmt::sprintf("- wavetables: %d\n",song.waveLen)); + w->writeText(fmt::sprintf("- samples: %d\n\n",song.sampleLen)); + + w->writeText("# Sound Chips\n\n"); + + for (int i=0; iwriteText(fmt::sprintf("- %s\n",getSystemName(song.system[i]))); + w->writeText(fmt::sprintf(" - id: %.2X\n",(int)song.system[i])); + w->writeText(fmt::sprintf(" - volume: %g\n",song.systemVol[i])); + w->writeText(fmt::sprintf(" - panning: %g\n",song.systemPan[i])); + w->writeText(fmt::sprintf(" - front/rear: %g\n",song.systemPanFR[i])); + + String sysFlags=song.systemFlags[i].toString(); + + if (!sysFlags.empty()) { + w->writeText(fmt::sprintf(" - flags:\n```\n%s\n```\n",sysFlags)); + } + } + + if (!song.notes.empty()) { + w->writeText("\n# Song Comments\n\n"); + w->writeText(song.notes); + } + + w->writeText("\n# Instruments\n\n"); + + for (int i=0; iwriteText(fmt::sprintf("## %.2X: %s\n\n",i,ins->name)); + + w->writeText(fmt::sprintf("- type: %d\n",(int)ins->type)); + + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPM || ins->type==DIV_INS_ESFM) { + w->writeText("- FM parameters:\n"); + w->writeText(fmt::sprintf(" - ALG: %d\n",ins->fm.alg)); + w->writeText(fmt::sprintf(" - FB: %d\n",ins->fm.fb)); + w->writeText(fmt::sprintf(" - FMS: %d\n",ins->fm.fms)); + w->writeText(fmt::sprintf(" - AMS: %d\n",ins->fm.ams)); + w->writeText(fmt::sprintf(" - FMS2: %d\n",ins->fm.fms2)); + w->writeText(fmt::sprintf(" - AMS2: %d\n",ins->fm.ams2)); + w->writeText(fmt::sprintf(" - operators: %d\n",ins->fm.ops)); + w->writeText(fmt::sprintf(" - OPLL patch: %d\n",ins->fm.opllPreset)); + w->writeText(fmt::sprintf(" - fixed drum freq: %s\n",trueFalse[ins->fm.fixedDrums?1:0])); + w->writeText(fmt::sprintf(" - kick freq: %.4X\n",ins->fm.kickFreq)); + w->writeText(fmt::sprintf(" - snare/hat freq: %.4X\n",ins->fm.snareHatFreq)); + w->writeText(fmt::sprintf(" - tom/top freq: %.4X\n",ins->fm.tomTopFreq)); + + for (int j=0; jfm.ops; j++) { + DivInstrumentFM::Operator& op=ins->fm.op[j]; + + w->writeText(fmt::sprintf(" - operator %d:\n",j)); + w->writeText(fmt::sprintf(" - enabled: %s\n",trueFalse[op.enable?1:0])); + w->writeText(fmt::sprintf(" - AM: %d\n",op.am)); + w->writeText(fmt::sprintf(" - AR: %d\n",op.ar)); + w->writeText(fmt::sprintf(" - DR: %d\n",op.dr)); + w->writeText(fmt::sprintf(" - MULT: %d\n",op.mult)); + w->writeText(fmt::sprintf(" - RR: %d\n",op.rr)); + w->writeText(fmt::sprintf(" - SL: %d\n",op.sl)); + w->writeText(fmt::sprintf(" - TL: %d\n",op.tl)); + w->writeText(fmt::sprintf(" - DT2: %d\n",op.dt2)); + w->writeText(fmt::sprintf(" - RS: %d\n",op.rs)); + w->writeText(fmt::sprintf(" - DT: %d\n",op.dt)); + w->writeText(fmt::sprintf(" - D2R: %d\n",op.d2r)); + w->writeText(fmt::sprintf(" - SSG-EG: %d\n",op.ssgEnv)); + w->writeText(fmt::sprintf(" - DAM: %d\n",op.dam)); + w->writeText(fmt::sprintf(" - DVB: %d\n",op.dvb)); + w->writeText(fmt::sprintf(" - EGT: %d\n",op.egt)); + w->writeText(fmt::sprintf(" - KSL: %d\n",op.ksl)); + w->writeText(fmt::sprintf(" - SUS: %d\n",op.sus)); + w->writeText(fmt::sprintf(" - VIB: %d\n",op.vib)); + w->writeText(fmt::sprintf(" - WS: %d\n",op.ws)); + w->writeText(fmt::sprintf(" - KSR: %d\n",op.ksr)); + w->writeText(fmt::sprintf(" - TL volume scale: %d\n",op.kvs)); + } + } + + if (ins->type==DIV_INS_ESFM) { + w->writeText("- ESFM parameters:\n"); + w->writeText(fmt::sprintf(" - noise mode: %d\n",ins->esfm.noise)); + + for (int j=0; jfm.ops; j++) { + DivInstrumentESFM::Operator& opE=ins->esfm.op[j]; + + w->writeText(fmt::sprintf(" - operator %d:\n",j)); + w->writeText(fmt::sprintf(" - DL: %d\n",opE.delay)); + w->writeText(fmt::sprintf(" - OL: %d\n",opE.outLvl)); + w->writeText(fmt::sprintf(" - MI: %d\n",opE.modIn)); + w->writeText(fmt::sprintf(" - output left: %s\n",trueFalse[opE.left?1:0])); + w->writeText(fmt::sprintf(" - output right: %s\n",trueFalse[opE.right?1:0])); + w->writeText(fmt::sprintf(" - CT: %d\n",opE.ct)); + w->writeText(fmt::sprintf(" - DT: %d\n",opE.dt)); + w->writeText(fmt::sprintf(" - fixed frequency: %s\n",trueFalse[opE.fixed?1:0])); + } + } + + if (ins->type==DIV_INS_GB) { + w->writeText("- Game Boy parameters:\n"); + w->writeText(fmt::sprintf(" - volume: %d\n",ins->gb.envVol)); + w->writeText(fmt::sprintf(" - direction: %s\n",gbEnvDir[ins->gb.envDir?1:0])); + w->writeText(fmt::sprintf(" - length: %d\n",ins->gb.envLen)); + w->writeText(fmt::sprintf(" - sound length: %d\n",ins->gb.soundLen)); + w->writeText(fmt::sprintf(" - use software envelope: %s\n",trueFalse[ins->gb.softEnv?1:0])); + w->writeText(fmt::sprintf(" - always initialize: %s\n",trueFalse[ins->gb.softEnv?1:0])); + if (ins->gb.hwSeqLen>0) { + w->writeText(" - hardware sequence:\n"); + for (int j=0; jgb.hwSeqLen; j++) { + w->writeText(fmt::sprintf(" - %d: %.2X %.4X\n",j,ins->gb.hwSeq[j].cmd,ins->gb.hwSeq[j].data)); + } + } + } + + bool header=false; + writeTextMacro(w,ins->std.volMacro,"vol",header); + writeTextMacro(w,ins->std.arpMacro,"arp",header); + writeTextMacro(w,ins->std.dutyMacro,"duty",header); + writeTextMacro(w,ins->std.waveMacro,"wave",header); + writeTextMacro(w,ins->std.pitchMacro,"pitch",header); + writeTextMacro(w,ins->std.panLMacro,"panL",header); + writeTextMacro(w,ins->std.panRMacro,"panR",header); + writeTextMacro(w,ins->std.phaseResetMacro,"phaseReset",header); + writeTextMacro(w,ins->std.ex1Macro,"ex1",header); + writeTextMacro(w,ins->std.ex2Macro,"ex2",header); + writeTextMacro(w,ins->std.ex3Macro,"ex3",header); + writeTextMacro(w,ins->std.ex4Macro,"ex4",header); + writeTextMacro(w,ins->std.ex5Macro,"ex5",header); + writeTextMacro(w,ins->std.ex6Macro,"ex6",header); + writeTextMacro(w,ins->std.ex7Macro,"ex7",header); + writeTextMacro(w,ins->std.ex8Macro,"ex8",header); + writeTextMacro(w,ins->std.algMacro,"alg",header); + writeTextMacro(w,ins->std.fbMacro,"fb",header); + writeTextMacro(w,ins->std.fmsMacro,"fms",header); + writeTextMacro(w,ins->std.amsMacro,"ams",header); + + // TODO: the rest + w->writeText("\n"); + } + + w->writeText("\n# Wavetables\n\n"); + + for (int i=0; iwriteText(fmt::sprintf("- %d (%dx%d):",i,wave->len+1,wave->max+1)); + for (int j=0; j<=wave->len; j++) { + w->writeText(fmt::sprintf(" %d",wave->data[j])); + } + w->writeText("\n"); + } + + w->writeText("\n# Samples\n\n"); + + for (int i=0; iwriteText(fmt::sprintf("## %.2X: %s\n\n",i,sample->name)); + + w->writeText(fmt::sprintf("- format: %d\n",(int)sample->depth)); + w->writeText(fmt::sprintf("- data length: %d\n",sample->getCurBufLen())); + w->writeText(fmt::sprintf("- samples: %d\n",sample->samples)); + w->writeText(fmt::sprintf("- rate: %d\n",sample->centerRate)); + w->writeText(fmt::sprintf("- compat rate: %d\n",sample->rate)); + w->writeText(fmt::sprintf("- loop: %s\n",trueFalse[sample->loop?1:0])); + if (sample->loop) { + w->writeText(fmt::sprintf(" - start: %d\n",sample->loopStart)); + w->writeText(fmt::sprintf(" - end: %d\n",sample->loopEnd)); + w->writeText(fmt::sprintf(" - mode: %s\n",sampleLoopModes[sample->loopMode&3])); + } + w->writeText(fmt::sprintf("- BRR emphasis: %s\n",trueFalse[sample->brrEmphasis?1:0])); + w->writeText(fmt::sprintf("- dither: %s\n",trueFalse[sample->dither?1:0])); + + // TODO' render matrix + unsigned char* buf=(unsigned char*)sample->getCurBuf(); + unsigned int bufLen=sample->getCurBufLen(); + w->writeText("\n```"); + for (unsigned int i=0; iwriteText(fmt::sprintf("\n%.8X:",i)); + w->writeText(fmt::sprintf(" %.2X",buf[i])); + } + w->writeText("\n```\n\n"); + } + + w->writeText("\n# Subsongs\n\n"); + + for (size_t i=0; iwriteText(fmt::sprintf("## %d: %s\n\n",(int)i,s->name)); + + w->writeText(fmt::sprintf("- tick rate: %g\n",s->hz)); + w->writeText(fmt::sprintf("- speeds:")); + for (int j=0; jspeeds.len; j++) { + w->writeText(fmt::sprintf(" %d",s->speeds.val[j])); + } + w->writeText("\n"); + w->writeText(fmt::sprintf("- virtual tempo: %d/%d\n",s->virtualTempoN,s->virtualTempoD)); + w->writeText(fmt::sprintf("- time base: %d\n",s->timeBase)); + w->writeText(fmt::sprintf("- pattern length: %d\n",s->patLen)); + w->writeText(fmt::sprintf("\norders:\n```\n")); + + for (int j=0; jordersLen; j++) { + w->writeText(fmt::sprintf("%.2X |",j)); + for (int k=0; kwriteText(fmt::sprintf(" %.2X",s->orders.ord[k][j])); + } + w->writeText("\n"); + } + w->writeText("```\n\n## Patterns\n\n"); + + if (separatePatterns) { + w->writeText("TODO: separate patterns\n\n"); + } else { + for (int j=0; jordersLen; j++) { + w->writeText(fmt::sprintf("----- ORDER %.2X\n",j)); + + for (int k=0; kpatLen; k++) { + w->writeText(fmt::sprintf("%.2X ",k)); + + for (int l=0; lpat[l].getPattern(s->orders.ord[l][j],false); + + int note=p->data[k][0]; + int octave=p->data[k][1]; + + if (note==0 && octave==0) { + w->writeText("|... "); + } else if (note==100) { + w->writeText("|OFF "); + } else if (note==101) { + w->writeText("|=== "); + } else if (note==102) { + w->writeText("|REL "); + } else if ((octave>9 && octave<250) || note>12) { + w->writeText("|??? "); + } else { + if (octave>=128) octave-=256; + if (note>11) { + note-=12; + octave++; + } + w->writeText(fmt::sprintf("|%s%d ",(octave<0)?notesNegative[note]:notes[note],(octave<0)?(-octave):octave)); + } + + if (p->data[k][2]==-1) { + w->writeText(".. "); + } else { + w->writeText(fmt::sprintf("%.2X ",p->data[k][2]&0xff)); + } + + if (p->data[k][3]==-1) { + w->writeText(".."); + } else { + w->writeText(fmt::sprintf("%.2X",p->data[k][3]&0xff)); + } + + for (int m=0; mpat[l].effectCols; m++) { + if (p->data[k][4+(m<<1)]==-1) { + w->writeText(" .."); + } else { + w->writeText(fmt::sprintf(" %.2X",p->data[k][4+(m<<1)]&0xff)); + } + if (p->data[k][5+(m<<1)]==-1) { + w->writeText(".."); + } else { + w->writeText(fmt::sprintf("%.2X",p->data[k][5+(m<<1)]&0xff)); + } + } + } + + w->writeText("\n"); + } + } + } + + } + + saveLock.unlock(); + return w; +}