add ability to select VGM version when exporting

by default it is 1.71 but please tell me if you want this to be changed
This commit is contained in:
tildearrow 2022-04-01 21:40:32 -05:00
parent 13d08b3cb6
commit 81c8bf4e59
7 changed files with 189 additions and 84 deletions

View file

@ -305,7 +305,7 @@ class DivEngine {
// specify system to build ROM for. // specify system to build ROM for.
SafeWriter* buildROM(int sys); SafeWriter* buildROM(int sys);
// dump to VGM. // dump to VGM.
SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true); SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171);
// export to an audio file // export to an audio file
bool saveAudio(const char* path, int loops, DivAudioExportModes mode); bool saveAudio(const char* path, int loops, DivAudioExportModes mode);
// wait for audio export to finish // wait for audio export to finish
@ -317,8 +317,8 @@ class DivEngine {
// notify wavetable change // notify wavetable change
void notifyWaveChange(int wave); void notifyWaveChange(int wave);
// returns whether a system is VGM compatible // returns the minimum VGM version which may carry the specified system, or 0 if none.
bool isVGMExportable(DivSystem which); int minVGMVersion(DivSystem which);
// save config // save config
bool saveConf(); bool saveConf();

View file

@ -1670,41 +1670,44 @@ DivInstrumentType DivEngine::getPreferInsType(int chan) {
return DIV_INS_FM; return DIV_INS_FM;
} }
bool DivEngine::isVGMExportable(DivSystem which) { int DivEngine::minVGMVersion(DivSystem which) {
switch (which) { switch (which) {
case DIV_SYSTEM_SMS:
case DIV_SYSTEM_GB:
case DIV_SYSTEM_PCE:
case DIV_SYSTEM_NES:
case DIV_SYSTEM_YM2151:
case DIV_SYSTEM_YM2612: case DIV_SYSTEM_YM2612:
case DIV_SYSTEM_YM2612_EXT: case DIV_SYSTEM_YM2612_EXT:
case DIV_SYSTEM_SMS:
case DIV_SYSTEM_OPLL:
case DIV_SYSTEM_OPLL_DRUMS:
case DIV_SYSTEM_VRC7:
case DIV_SYSTEM_YM2151:
return 0x150; // due to usage of data blocks
case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL: case DIV_SYSTEM_YM2610_FULL:
case DIV_SYSTEM_YM2610_FULL_EXT: case DIV_SYSTEM_YM2610_FULL_EXT:
case DIV_SYSTEM_YM2610B: case DIV_SYSTEM_YM2610B:
case DIV_SYSTEM_YM2610B_EXT: case DIV_SYSTEM_YM2610B_EXT:
case DIV_SYSTEM_AY8910:
case DIV_SYSTEM_AY8930:
case DIV_SYSTEM_SAA1099:
case DIV_SYSTEM_QSOUND:
case DIV_SYSTEM_SEGAPCM:
case DIV_SYSTEM_SEGAPCM_COMPAT:
case DIV_SYSTEM_OPLL:
case DIV_SYSTEM_OPLL_DRUMS:
case DIV_SYSTEM_VRC7:
case DIV_SYSTEM_X1_010:
case DIV_SYSTEM_SWAN:
case DIV_SYSTEM_OPL: case DIV_SYSTEM_OPL:
case DIV_SYSTEM_OPL_DRUMS: case DIV_SYSTEM_OPL_DRUMS:
case DIV_SYSTEM_OPL2: case DIV_SYSTEM_OPL2:
case DIV_SYSTEM_OPL2_DRUMS: case DIV_SYSTEM_OPL2_DRUMS:
case DIV_SYSTEM_OPL3: case DIV_SYSTEM_OPL3:
case DIV_SYSTEM_OPL3_DRUMS: case DIV_SYSTEM_OPL3_DRUMS:
return true; case DIV_SYSTEM_AY8910:
case DIV_SYSTEM_AY8930:
return 0x151;
case DIV_SYSTEM_GB:
case DIV_SYSTEM_PCE:
case DIV_SYSTEM_NES:
case DIV_SYSTEM_QSOUND:
return 0x161;
case DIV_SYSTEM_SAA1099:
case DIV_SYSTEM_X1_010:
case DIV_SYSTEM_SWAN:
return 0x171;
default: default:
return false; return 0;
} }
return false; return 0;
} }

View file

@ -592,7 +592,11 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
} }
} }
SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) { SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
if (version<0x150) {
lastError="VGM version is too low";
return NULL;
}
stop(); stop();
repeatPattern=false; repeatPattern=false;
setOrder(0); setOrder(0);
@ -679,7 +683,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
// write header // write header
w->write("Vgm ",4); w->write("Vgm ",4);
w->writeI(0); // will be written later w->writeI(0); // will be written later
w->writeI(0x171); // VGM 1.71 w->writeI(version);
bool willExport[32]; bool willExport[32];
bool isSecond[32]; bool isSecond[32];
@ -709,6 +713,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
if (sysToExport!=NULL) { if (sysToExport!=NULL) {
if (!sysToExport[i]) continue; if (!sysToExport[i]) continue;
} }
if (minVGMVersion(song.system[i])>version) continue;
switch (song.system[i]) { switch (song.system[i]) {
case DIV_SYSTEM_SMS: case DIV_SYSTEM_SMS:
if (!hasSN) { if (!hasSN) {
@ -979,66 +984,138 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
w->writeI(0); // tick rate w->writeI(0); // tick rate
w->writeS(snNoiseConfig); w->writeS(snNoiseConfig);
w->writeC(snNoiseSize); w->writeC(snNoiseSize);
w->writeC(snFlags); if (version>=0x151) {
w->writeC(snFlags);
} else {
w->writeC(0);
}
w->writeI(hasOPN2); w->writeI(hasOPN2);
w->writeI(hasOPM); w->writeI(hasOPM);
w->writeI(0); // data pointer. will be written later w->writeI(0); // data pointer. will be written later
w->writeI(hasSegaPCM); if (version>=0x151) {
w->writeI(segaPCMOffset); w->writeI(hasSegaPCM);
w->writeI(hasRFC); w->writeI(segaPCMOffset);
w->writeI(hasOPN); w->writeI(hasRFC);
w->writeI(hasOPNA); w->writeI(hasOPN);
w->writeI(hasOPNB); w->writeI(hasOPNA);
w->writeI(hasOPL2); w->writeI(hasOPNB);
w->writeI(hasOPL); w->writeI(hasOPL2);
w->writeI(hasY8950); w->writeI(hasOPL);
w->writeI(hasOPL3); w->writeI(hasY8950);
w->writeI(hasOPL4); w->writeI(hasOPL3);
w->writeI(hasOPX); w->writeI(hasOPL4);
w->writeI(hasZ280); w->writeI(hasOPX);
w->writeI(hasRFC1); w->writeI(hasZ280);
w->writeI(hasPWM); w->writeI(hasRFC1);
w->writeI(hasAY); w->writeI(hasPWM);
w->writeC(ayConfig); w->writeI(hasAY);
w->writeC(ayFlags); w->writeC(ayConfig);
w->writeC(ayFlags); // OPN w->writeC(ayFlags);
w->writeC(ayFlags); // OPNA w->writeC(ayFlags); // OPN
w->writeC(ayFlags); // OPNA
} else {
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeC(0);
w->writeC(0);
w->writeC(0); // OPN
w->writeC(0); // OPNA
}
// currently not used but is part of 1.60
w->writeC(0); // volume w->writeC(0); // volume
w->writeC(0); // reserved w->writeC(0); // reserved
w->writeC(0); // loop count w->writeC(0); // loop count
// 1.51
w->writeC(0); // loop modifier w->writeC(0); // loop modifier
w->writeI(hasGB);
w->writeI(hasNES); if (version>=0x161) {
w->writeI(hasMultiPCM); w->writeI(hasGB);
w->writeI(hasuPD7759); w->writeI(hasNES);
w->writeI(hasOKIM6258); w->writeI(hasMultiPCM);
w->writeC(0); // flags w->writeI(hasuPD7759);
w->writeC(0); // K flags w->writeI(hasOKIM6258);
w->writeC(0); // C140 chip type w->writeC(0); // flags
w->writeC(0); // reserved w->writeC(0); // K flags
w->writeI(hasOKIM6295); w->writeC(0); // C140 chip type
w->writeI(hasK051649); w->writeC(0); // reserved
w->writeI(hasK054539); w->writeI(hasOKIM6295);
w->writeI(hasPCE); w->writeI(hasK051649);
w->writeI(hasNamco); w->writeI(hasK054539);
w->writeI(hasK053260); w->writeI(hasPCE);
w->writeI(hasPOKEY); w->writeI(hasNamco);
w->writeI(hasQSound); w->writeI(hasK053260);
w->writeI(hasSCSP); w->writeI(hasPOKEY);
w->writeI(hasQSound);
} else {
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeC(0); // flags
w->writeC(0); // K flags
w->writeC(0); // C140 chip type
w->writeC(0); // reserved
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
}
if (version>=0x171) {
w->writeI(hasSCSP);
} else {
w->writeI(0);
}
// 1.70
w->writeI(0); // extra header w->writeI(0); // extra header
w->writeI(hasSwan); // 1.71
w->writeI(hasVSU); if (version>=0x171) {
w->writeI(hasSAA); w->writeI(hasSwan);
w->writeI(hasES5503); w->writeI(hasVSU);
w->writeI(hasES5505); w->writeI(hasSAA);
w->writeC(0); // 5503 chans w->writeI(hasES5503);
w->writeC(0); // 5505 chans w->writeI(hasES5505);
w->writeC(0); // C352 clock divider w->writeC(0); // 5503 chans
w->writeC(0); // reserved w->writeC(0); // 5505 chans
w->writeI(hasX1); w->writeC(0); // C352 clock divider
w->writeI(hasC352); w->writeC(0); // reserved
w->writeI(hasGA20); w->writeI(hasX1);
w->writeI(hasLynx); w->writeI(hasC352);
w->writeI(hasGA20);
w->writeI(hasLynx);
} else {
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeC(0); // 5503 chans
w->writeC(0); // 5505 chans
w->writeC(0); // C352 clock divider
w->writeC(0); // reserved
w->writeI(0);
w->writeI(0);
w->writeI(0);
w->writeI(0);
}
for (int i=0; i<6; i++) { // reserved for (int i=0; i<6; i++) { // reserved
w->writeI(0); w->writeI(0);
} }

View file

@ -2131,14 +2131,27 @@ bool FurnaceGUI::loop() {
} }
if (ImGui::BeginMenu("export VGM...")) { if (ImGui::BeginMenu("export VGM...")) {
ImGui::Text("settings:"); ImGui::Text("settings:");
if (ImGui::BeginCombo("format version",fmt::sprintf("%d.%.2x",vgmExportVersion>>8,vgmExportVersion&0xff).c_str())) {
for (int i=0; i<6; i++) {
if (ImGui::Selectable(fmt::sprintf("%d.%.2x",vgmVersions[i]>>8,vgmVersions[i]&0xff).c_str(),vgmExportVersion==vgmVersions[i])) {
vgmExportVersion=vgmVersions[i];
}
}
ImGui::EndCombo();
}
ImGui::Checkbox("loop",&vgmExportLoop); ImGui::Checkbox("loop",&vgmExportLoop);
ImGui::Text("systems to export:");; ImGui::Text("systems to export:");
bool hasOneAtLeast=false; bool hasOneAtLeast=false;
for (int i=0; i<e->song.systemLen; i++) { for (int i=0; i<e->song.systemLen; i++) {
ImGui::BeginDisabled(!e->isVGMExportable(e->song.system[i])); int minVersion=e->minVGMVersion(e->song.system[i]);
ImGui::BeginDisabled(minVersion>vgmExportVersion || minVersion==0);
ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i]); ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i]);
ImGui::EndDisabled(); ImGui::EndDisabled();
if (!e->isVGMExportable(e->song.system[i])) { if (minVersion>vgmExportVersion) {
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
ImGui::SetTooltip("this system is only available in VGM %d.%.2x and higher!",minVersion>>8,minVersion&0xff);
}
} else if (minVersion==0) {
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
ImGui::SetTooltip("this system is not supported by the VGM format!"); ImGui::SetTooltip("this system is not supported by the VGM format!");
} }
@ -2147,7 +2160,7 @@ bool FurnaceGUI::loop() {
} }
} }
ImGui::Text("select the systems you wish to export,"); ImGui::Text("select the systems you wish to export,");
ImGui::Text("but only up to 2 of each type."); ImGui::Text("but only up to %d of each type.",(vgmExportVersion>=0x151)?2:1);
if (hasOneAtLeast) { if (hasOneAtLeast) {
if (ImGui::MenuItem("click to export")) { if (ImGui::MenuItem("click to export")) {
openFileDialog(GUI_FILE_EXPORT_VGM); openFileDialog(GUI_FILE_EXPORT_VGM);
@ -2504,7 +2517,7 @@ bool FurnaceGUI::loop() {
MARK_MODIFIED; MARK_MODIFIED;
break; break;
case GUI_FILE_EXPORT_VGM: { case GUI_FILE_EXPORT_VGM: {
SafeWriter* w=e->saveVGM(willExport,vgmExportLoop); SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion);
if (w!=NULL) { if (w!=NULL) {
FILE* f=fopen(copyOfName.c_str(),"wb"); FILE* f=fopen(copyOfName.c_str(),"wb");
if (f!=NULL) { if (f!=NULL) {
@ -2519,7 +2532,7 @@ bool FurnaceGUI::loop() {
showWarning(e->getWarnings(),GUI_WARN_GENERIC); showWarning(e->getWarnings(),GUI_WARN_GENERIC);
} }
} else { } else {
showError("could not write VGM. dang it."); showError(fmt::sprintf("could not write VGM! (%s)",e->getLastError()));
} }
break; break;
} }
@ -2918,6 +2931,7 @@ FurnaceGUI::FurnaceGUI():
displayExporting(false), displayExporting(false),
vgmExportLoop(true), vgmExportLoop(true),
displayNew(false), displayNew(false),
vgmExportVersion(0x171),
curFileDialog(GUI_FILE_OPEN), curFileDialog(GUI_FILE_OPEN),
warnAction(GUI_WARN_OPEN), warnAction(GUI_WARN_OPEN),
fileDialog(NULL), fileDialog(NULL),

View file

@ -643,6 +643,7 @@ class FurnaceGUI {
bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop; bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop;
bool displayNew; bool displayNew;
bool willExport[32]; bool willExport[32];
int vgmExportVersion;
FurnaceGUIFileDialogs curFileDialog; FurnaceGUIFileDialogs curFileDialog;
FurnaceGUIWarnings warnAction; FurnaceGUIWarnings warnAction;

View file

@ -70,6 +70,15 @@ const int altValues[24]={
0, 10, 1, 11, 2, 3, 12, 4, 13, 5, 14, 6, 7, 15, 8, -1, 9, -1, -1, -1, -1, -1, -1, -1 0, 10, 1, 11, 2, 3, 12, 4, 13, 5, 14, 6, 7, 15, 8, -1, 9, -1, -1, -1, -1, -1, -1, -1
}; };
const int vgmVersions[6]={
0x150,
0x151,
0x160,
0x161,
0x170,
0x171
};
const char* insTypes[DIV_INS_MAX]={ const char* insTypes[DIV_INS_MAX]={
"Standard", "Standard",
"FM (4-operator)", "FM (4-operator)",

View file

@ -28,4 +28,5 @@ extern const char* sampleDepths[17];
extern const char* resampleStrats[]; extern const char* resampleStrats[];
extern const int availableSystems[]; extern const int availableSystems[];
extern const char* guiActions[][2]; extern const char* guiActions[][2];
extern const int altValues[24]; extern const int altValues[24];
extern const int vgmVersions[6];