prepare for text export
This commit is contained in:
parent
06c3455852
commit
643e5d5d5b
|
@ -647,6 +647,8 @@ class DivEngine {
|
||||||
SafeWriter* saveZSM(unsigned int zsmrate=60, bool loop=true, bool optimize=true);
|
SafeWriter* saveZSM(unsigned int zsmrate=60, bool loop=true, bool optimize=true);
|
||||||
// dump command stream.
|
// dump command stream.
|
||||||
SafeWriter* saveCommand(bool binary=false);
|
SafeWriter* saveCommand(bool binary=false);
|
||||||
|
// export to text
|
||||||
|
SafeWriter* saveText(bool separatePatterns=true);
|
||||||
// export to an audio file
|
// export to an audio file
|
||||||
bool saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime=0.0);
|
bool saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime=0.0);
|
||||||
// wait for audio export to finish
|
// wait for audio export to finish
|
||||||
|
|
|
@ -6308,3 +6308,179 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* trueFalse[2]={
|
||||||
|
"no", "yes"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* gbEnvDir[2]={
|
||||||
|
"down", "up"
|
||||||
|
};
|
||||||
|
|
||||||
|
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; i<song.systemLen; i++) {
|
||||||
|
w->writeText(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; i<song.insLen; i++) {
|
||||||
|
DivInstrument* ins=song.ins[i];
|
||||||
|
|
||||||
|
w->writeText(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) {
|
||||||
|
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; j<ins->fm.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_GB) {
|
||||||
|
w->writeText("- Game Boy parameters:\n");
|
||||||
|
w->writeText(fmt::sprintf(" - volume: %d\n",ins->gb.envVol));
|
||||||
|
w->writeText(fmt::sprintf(" - direction: %d\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; j<ins->gb.hwSeqLen; j++) {
|
||||||
|
w->writeText(fmt::sprintf(" - %d: %.2X %.4X\n",j,ins->gb.hwSeq[j].cmd,ins->gb.hwSeq[j].data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: the rest
|
||||||
|
w->writeText("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
w->writeText("# Wavetables\n\n");
|
||||||
|
|
||||||
|
for (int i=0; i<song.waveLen; i++) {
|
||||||
|
DivWavetable* wave=song.wave[i];
|
||||||
|
|
||||||
|
w->writeText(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# Subsongs\n\n");
|
||||||
|
|
||||||
|
for (size_t i=0; i<song.subsong.size(); i++) {
|
||||||
|
DivSubSong* s=song.subsong[i];
|
||||||
|
w->writeText(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; j<s->speeds.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; j<s->ordersLen; j++) {
|
||||||
|
w->writeText(fmt::sprintf("%.2X |",j));
|
||||||
|
for (int k=0; k<chans; k++) {
|
||||||
|
w->writeText(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; j<s->ordersLen; j++) {
|
||||||
|
w->writeText(fmt::sprintf("----- ORDER %.2X\n",j));
|
||||||
|
|
||||||
|
for (int k=0; k<s->patLen; k++) {
|
||||||
|
w->writeText(fmt::sprintf("%.2X | ",k));
|
||||||
|
|
||||||
|
w->writeText("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
saveLock.unlock();
|
||||||
|
return w;
|
||||||
|
}
|
|
@ -1872,6 +1872,15 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
||||||
dpiScale
|
dpiScale
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case GUI_FILE_EXPORT_TEXT:
|
||||||
|
if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir();
|
||||||
|
hasOpened=fileDialog->openSave(
|
||||||
|
"Export Command Stream",
|
||||||
|
{"text file", "*.txt"},
|
||||||
|
workingDirROMExport,
|
||||||
|
dpiScale
|
||||||
|
);
|
||||||
|
break;
|
||||||
case GUI_FILE_EXPORT_CMDSTREAM:
|
case GUI_FILE_EXPORT_CMDSTREAM:
|
||||||
if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir();
|
if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir();
|
||||||
hasOpened=fileDialog->openSave(
|
hasOpened=fileDialog->openSave(
|
||||||
|
@ -4237,6 +4246,16 @@ bool FurnaceGUI::loop() {
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ImGui::BeginMenu("export text...")) {
|
||||||
|
exitDisabledTimer=1;
|
||||||
|
ImGui::Text(
|
||||||
|
"this option exports the song to a text file.\n"
|
||||||
|
);
|
||||||
|
if (ImGui::Button("export")) {
|
||||||
|
openFileDialog(GUI_FILE_EXPORT_TEXT);
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
if (ImGui::BeginMenu("export command stream...")) {
|
if (ImGui::BeginMenu("export command stream...")) {
|
||||||
exitDisabledTimer=1;
|
exitDisabledTimer=1;
|
||||||
ImGui::Text(
|
ImGui::Text(
|
||||||
|
@ -4809,6 +4828,7 @@ bool FurnaceGUI::loop() {
|
||||||
workingDirZSMExport=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
workingDirZSMExport=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||||
break;
|
break;
|
||||||
case GUI_FILE_EXPORT_ROM:
|
case GUI_FILE_EXPORT_ROM:
|
||||||
|
case GUI_FILE_EXPORT_TEXT:
|
||||||
case GUI_FILE_EXPORT_CMDSTREAM:
|
case GUI_FILE_EXPORT_CMDSTREAM:
|
||||||
case GUI_FILE_EXPORT_CMDSTREAM_BINARY:
|
case GUI_FILE_EXPORT_CMDSTREAM_BINARY:
|
||||||
workingDirROMExport=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
workingDirROMExport=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||||
|
@ -5267,6 +5287,27 @@ bool FurnaceGUI::loop() {
|
||||||
case GUI_FILE_EXPORT_ROM:
|
case GUI_FILE_EXPORT_ROM:
|
||||||
showError("Coming soon!");
|
showError("Coming soon!");
|
||||||
break;
|
break;
|
||||||
|
case GUI_FILE_EXPORT_TEXT: {
|
||||||
|
SafeWriter* w=e->saveText(false);
|
||||||
|
if (w!=NULL) {
|
||||||
|
FILE* f=ps_fopen(copyOfName.c_str(),"wb");
|
||||||
|
if (f!=NULL) {
|
||||||
|
fwrite(w->getFinalBuf(),1,w->size(),f);
|
||||||
|
fclose(f);
|
||||||
|
pushRecentSys(copyOfName.c_str());
|
||||||
|
} else {
|
||||||
|
showError("could not open file!");
|
||||||
|
}
|
||||||
|
w->finish();
|
||||||
|
delete w;
|
||||||
|
if (!e->getWarnings().empty()) {
|
||||||
|
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showError(fmt::sprintf("could not write text! (%s)",e->getLastError()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GUI_FILE_EXPORT_CMDSTREAM:
|
case GUI_FILE_EXPORT_CMDSTREAM:
|
||||||
case GUI_FILE_EXPORT_CMDSTREAM_BINARY: {
|
case GUI_FILE_EXPORT_CMDSTREAM_BINARY: {
|
||||||
bool isBinary=(curFileDialog==GUI_FILE_EXPORT_CMDSTREAM_BINARY);
|
bool isBinary=(curFileDialog==GUI_FILE_EXPORT_CMDSTREAM_BINARY);
|
||||||
|
|
|
@ -465,6 +465,7 @@ enum FurnaceGUIFileDialogs {
|
||||||
GUI_FILE_EXPORT_ZSM,
|
GUI_FILE_EXPORT_ZSM,
|
||||||
GUI_FILE_EXPORT_CMDSTREAM,
|
GUI_FILE_EXPORT_CMDSTREAM,
|
||||||
GUI_FILE_EXPORT_CMDSTREAM_BINARY,
|
GUI_FILE_EXPORT_CMDSTREAM_BINARY,
|
||||||
|
GUI_FILE_EXPORT_TEXT,
|
||||||
GUI_FILE_EXPORT_ROM,
|
GUI_FILE_EXPORT_ROM,
|
||||||
GUI_FILE_LOAD_MAIN_FONT,
|
GUI_FILE_LOAD_MAIN_FONT,
|
||||||
GUI_FILE_LOAD_HEAD_FONT,
|
GUI_FILE_LOAD_HEAD_FONT,
|
||||||
|
|
Loading…
Reference in a new issue