From 2785625475459c067888c9a61a1af87646a3a7e5 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Tue, 23 Sep 2025 14:24:45 +0400 Subject: [PATCH 1/3] fix dmf export "order out of range" error message --- src/engine/fileOps/dmf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/fileOps/dmf.cpp b/src/engine/fileOps/dmf.cpp index 19fa71afa..910be0d1e 100644 --- a/src/engine/fileOps/dmf.cpp +++ b/src/engine/fileOps/dmf.cpp @@ -1279,8 +1279,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { for (int i=0; iordersLen; j++) { if (curOrders->ord[i][j]>0x7f) { - logE("order %d, %d is out of range (0-127)!",curOrders->ord[i][j]); - lastError=fmt::sprintf("order %d, %d is out of range (0-127)",curOrders->ord[i][j]); + logE("order %d, %d is out of range (0-127)!",i,j); + lastError=fmt::sprintf("order %d, %d is out of range (0-127)",i,j); return NULL; } } From 4e976504882bca3d928fb6abfa917a0b5c30cb49 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Wed, 24 Sep 2025 13:55:22 +0400 Subject: [PATCH 2/3] separate and fix note selector in find/replace --- src/gui/findReplace.cpp | 128 +--------------------------------------- src/gui/gui.cpp | 66 +++++++++++++++++++++ src/gui/gui.h | 2 + 3 files changed, 71 insertions(+), 125 deletions(-) diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 2a3601cc3..0251acd8c 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -618,90 +618,14 @@ void FurnaceGUI::drawFindReplace() { if ((i.noteMode==GUI_QUERY_RANGE || i.noteMode==GUI_QUERY_RANGE_NOT) && i.note>=120) { i.note=0; } - if (i.note==130) { - snprintf(tempID,1024,"%s##MREL",macroRelLabel); - } else if (i.note==129) { - snprintf(tempID,1024,"%s##NREL",noteRelLabel); - } else if (i.note==128) { - snprintf(tempID,1024,"%s##NOFF",noteOffLabel); - } else if (i.note>=-60 && i.note<120) { - snprintf(tempID,1024,"%c%c",noteNames[i.note+60][0],(noteNames[i.note+60][1]=='-')?' ':noteNames[i.note+60][1]); - } else { - snprintf(tempID,1024,"???"); - i.note=0; - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2); - bool updateNote1=false; - int note1=i.note%12; - int oct1=i.note/12; - if (ImGui::BeginCombo("##NN1",tempID)) { - for (int j=0; j<12; j++) { - snprintf(tempID,1024,"%c%c",noteNames[j+72][0],(noteNames[j+72][1]=='-')?' ':noteNames[j+72][1]); - if (ImGui::Selectable(tempID,note1==j)) { - note1=j; - updateNote1=true; - } - } - if (i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT) { - if (ImGui::Selectable(noteOffLabel,note1==13)) { - i.note=128; - } - if (ImGui::Selectable(noteRelLabel,note1==14)) { - i.note=129; - } - if (ImGui::Selectable(macroRelLabel,note1==15)) { - i.note=130; - } - } - ImGui::EndCombo(); - } - ImGui::SameLine(); - if (i.note<128) { - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2); - if (ImGui::InputScalar("##NNO1",ImGuiDataType_S32,&oct1)) { - if (oct1<-5) oct1=-5; - if (oct1>9) oct1=9; - updateNote1=true; - } - } - if (updateNote1) { - i.note=oct1*12+note1; - } + NoteSelector(&i.note, i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT); } ImGui::TableNextColumn(); if (SECOND_VISIBLE(i.noteMode)) { if (i.noteMax<-60 || i.noteMax>=120) { i.noteMax=0; } - if (i.noteMax>=-60 && i.noteMax<120) { - snprintf(tempID,1024,"%c%c",noteNames[i.noteMax+60][0],(noteNames[i.noteMax+60][1]=='-')?' ':noteNames[i.noteMax+60][1]); - } else { - snprintf(tempID,1024,"???"); - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2); - bool updateNote2=false; - int note2=i.noteMax%12; - int oct2=i.noteMax/12; - if (ImGui::BeginCombo("##NN2",tempID)) { - for (int j=0; j<12; j++) { - snprintf(tempID,1024,"%c%c",noteNames[j+72][0],(noteNames[j+72][1]=='-')?' ':noteNames[j+72][1]); - if (ImGui::Selectable(tempID,note2==j)) { - note2=j; - updateNote2=true; - } - } - ImGui::EndCombo(); - } - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2); - if (ImGui::InputScalar("##NNO2",ImGuiDataType_S32,&oct2)) { - if (oct2<-5) oct2=-5; - if (oct2>9) oct2=9; - updateNote2=true; - } - if (updateNote2) { - i.noteMax=oct2*12+note2; - } + NoteSelector(&i.noteMax, false); } ImGui::TableNextRow(); @@ -912,53 +836,7 @@ void FurnaceGUI::drawFindReplace() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SET) { - if (queryReplaceNote==130) { - snprintf(tempID,1024,"%s##MREL",macroRelLabel); - } else if (queryReplaceNote==129) { - snprintf(tempID,1024,"%s##NREL",noteRelLabel); - } else if (queryReplaceNote==128) { - snprintf(tempID,1024,"%s##NOFF",noteOffLabel); - } else if (queryReplaceNote>=-60 && queryReplaceNote<120) { - snprintf(tempID,1024,"%c%c",noteNames[queryReplaceNote+60][0],(noteNames[queryReplaceNote+60][1]=='-')?' ':noteNames[queryReplaceNote+60][1]); - } else { - snprintf(tempID,1024,"???"); - queryReplaceNote=0; - } - bool updateNote=false; - int note1=queryReplaceNote%12; - int oct1=queryReplaceNote/12; - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2); - if (ImGui::BeginCombo("##NRValueC",tempID)) { - for (int i=0; i<12; i++) { - snprintf(tempID,1024,"%c%c",noteNames[i+72][0],(noteNames[i+72][1]=='-')?' ':noteNames[i+72][1]); - if (ImGui::Selectable(tempID,note1==i)) { - note1=i; - updateNote=true; - } - } - if (ImGui::Selectable(noteOffLabel,note1==13)) { - queryReplaceNote=128; - } - if (ImGui::Selectable(noteRelLabel,note1==14)) { - queryReplaceNote=129; - } - if (ImGui::Selectable(macroRelLabel,note1==15)) { - queryReplaceNote=130; - } - ImGui::EndCombo(); - } - ImGui::SameLine(); - if (queryReplaceNote<128) { - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x/2); - if (ImGui::InputScalar("##NRValueCO",ImGuiDataType_S32,&oct1)) { - if (oct1<-5) oct1=-5; - if (oct1>9) oct1=9; - updateNote=true; - } - } - if (updateNote) { - queryReplaceNote=oct1*12+note1; - } + NoteSelector(&queryReplaceNote, true); } else if (queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD || queryReplaceNoteMode==GUI_QUERY_REPLACE_ADD_OVERFLOW) { if (ImGui::InputInt("##NRValue",&queryReplaceNote,1,12)) { if (queryReplaceNote<-180) queryReplaceNote=-180; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index f3fff73c8..6b5b03bc7 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -535,6 +535,72 @@ bool FurnaceGUI::InvCheckbox(const char* label, bool* value) { return false; } +bool FurnaceGUI::NoteSelector(int* value, bool showOffRel, int octaveMin, int octaveMax) { + bool ret=false, calcNote=false; + char tempID[64]; + if (*value==130) { + snprintf(tempID,64,"%s##MREL",macroRelLabel); + } else if (*value==129) { + snprintf(tempID,64,"%s##NREL",noteRelLabel); + } else if (*value==128) { + snprintf(tempID,64,"%s##NOFF",noteOffLabel); + } else if (*value>=-60 && *value<120) { + snprintf(tempID,64,"%c%c",noteNames[*value%12+72][0],(noteNames[*value%12+72][1]=='-')?' ':noteNames[*value%12+72][1]); + } else { + snprintf(tempID,64,"???"); + *value=0; + } + float width=ImGui::GetContentRegionAvail().x/2-ImGui::GetStyle().FramePadding.x; + ImGui::SetNextItemWidth(width); + int note=(*value+60)%12; + int oct=0; + if (*value<120) oct=(*value-note)/12; + ImGui::BeginGroup(); + ImGui::PushID(value); + if (ImGui::BeginCombo("##NoteSelectorNote",tempID)) { + for (int j=0; j<12; j++) { + snprintf(tempID,64,"%c%c",noteNames[j+72][0],(noteNames[j+72][1]=='-')?' ':noteNames[j+72][1]); + if (ImGui::Selectable(tempID,note==j && *value<128)) { + note=j; + calcNote=true; + } + if (note==j && *value<120) ImGui::SetItemDefaultFocus(); + } + if (showOffRel) { + if (ImGui::Selectable(noteOffLabel,*value==128)) { + *value=128; + ret=true; + } + if (ImGui::Selectable(noteRelLabel,*value==129)) { + *value=129; + ret=true; + } + if (ImGui::Selectable(macroRelLabel,*value==130)) { + *value=130; + ret=true; + } + if (*value>=128 && *value<=130) ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + ImGui::SameLine(); + if (*value<120) { + ImGui::SetNextItemWidth(width/2); + if (ImGui::InputScalar("##NoteSelectorOctave",ImGuiDataType_S32,&oct)) { + if (octoctaveMax) oct=octaveMax; + calcNote=true; + } + } + if (calcNote) { + *value=oct*12+note; + ret=true; + } + ImGui::PopID(); + ImGui::EndGroup(); + return ret; +} + bool FurnaceGUI::LocalizedComboGetter(void* data, int idx, const char** out_text) { const char* const* items=(const char* const*)data; if (out_text) *out_text=_(items[idx]); diff --git a/src/gui/gui.h b/src/gui/gui.h index cdcc132bf..dc866ea33 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -2869,6 +2869,8 @@ class FurnaceGUI { // inverted checkbox bool InvCheckbox(const char* label, bool* value); + bool NoteSelector(int* value, bool showOffRel, int octaveMin=-5, int octaveMax=9); + // mixer stuff ImVec2 calcPortSetSize(String label, int ins, int outs); bool portSet(String label, unsigned int portSetID, int ins, int outs, int activeIns, int activeOuts, int& clickedPort, std::map& portPos); From 8716f2b93ff44559ecf58d01f8386507931f175a Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Fri, 26 Sep 2025 16:48:54 +0200 Subject: [PATCH 3/3] multipcm doc initial revision --- doc/7-systems/multipcm.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 doc/7-systems/multipcm.md diff --git a/doc/7-systems/multipcm.md b/doc/7-systems/multipcm.md new file mode 100644 index 000000000..79a81b3eb --- /dev/null +++ b/doc/7-systems/multipcm.md @@ -0,0 +1,23 @@ +# Yamaha YMW258-F (MultiPCM) + + a sound chip introduced in 1991 by Yamaha for their first General MIDI-compliant synthesizer, the Yamaha TG100. It also appeared on a number of higher-end consumer keyboards and specialized professional devices. The YMW258-F implements the GEW8 sound synthesis technology, which is PCM sample-based synthesis under Yamaha's "Advanced Wave Modulation" (AWM) umbrella. + +Sega used the chip in several arcade games on the Sega System Multi 32, Sega Model 1, and Sega Model 2 arcade boards. The chip as found on these boards is called MultiPCM, and has the Sega internal part number 315-5560. Contrary to popular belief, it is not a custom Sega part and is not based on the earlier SegaPCM chip, but it was named the MultiPCM as a successor to that chip. + +it has a whopping 28 channels of stereo 16-bit PCM and: + +- hardware LFO +- 8bit and 12bit wave format support +- up to 4MB of wave memory +- full blown ADSR envelopes + +## effects + +- `20xx`: **set PCM LFO rate.** +- `21xx`: **set PCM LFO PM depth..** +- `22xx`: **set PCM LFO AM depth.** + + +## info + +this chip uses the [MultiPCM](../4-instrument/multipcm.md) instrument editor.