diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 52b420aa4..e7f1653ca 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -6316,6 +6316,57 @@ 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(); @@ -6423,11 +6474,33 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) { } } + 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("# Wavetables\n\n"); + w->writeText("\n# Wavetables\n\n"); for (int i=0; iwriteText("\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("----- ORDER %.2X\n",j)); for (int k=0; kpatLen; k++) { - w->writeText(fmt::sprintf("%.2X | ",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"); } @@ -6483,4 +6639,4 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) { saveLock.unlock(); return w; -} \ No newline at end of file +} diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 2211cf0f9..6aa17ef45 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -39,7 +39,7 @@ void DivEngine::nextOrder() { } } -const char* notes[12]={ +static const char* notes[12]={ "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" }; diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 8a199997e..b9b8a7409 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -534,6 +534,10 @@ void FurnaceGUI::drawMobileControls() { if (ImGui::Button("CmdStream Text")) { openFileDialog(GUI_FILE_EXPORT_CMDSTREAM); } + ImGui::SameLine(); + if (ImGui::Button("Text")) { + openFileDialog(GUI_FILE_EXPORT_TEXT); + } if (ImGui::Button("Restore Backup")) { mobileMenuOpen=false; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 849e5e7b5..86cf09a86 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4920,7 +4920,7 @@ bool FurnaceGUI::loop() { if (curFileDialog==GUI_FILE_EXPORT_ZSM) { checkExtension(".zsm"); } - if (curFileDialog==GUI_FILE_EXPORT_CMDSTREAM) { + if (curFileDialog==GUI_FILE_EXPORT_CMDSTREAM || curFileDialog==GUI_FILE_EXPORT_TEXT) { checkExtension(".txt"); } if (curFileDialog==GUI_FILE_EXPORT_CMDSTREAM_BINARY) {