diff --git a/papers/format.md b/papers/format.md index 42488719..7ab67800 100644 --- a/papers/format.md +++ b/papers/format.md @@ -697,6 +697,17 @@ size | description 1 | extra 8 macro mode --- | **extra C64 data** (>=89) 1 | don't test/gate before new note + --- | **MultiPCM data** (>=93) + 1 | attack rate + 1 | decay 1 rate + 1 | decay level + 1 | decay 2 rate + 1 | release rate + 1 | rate correction + 1 | lfo rate + 1 | vib depth + 1 | am depth + 23 | reserved ``` # wavetable diff --git a/src/engine/engine.h b/src/engine/engine.h index 9ca19ec0..e9a5db2e 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev92" -#define DIV_ENGINE_VERSION 92 +#define DIV_VERSION "dev93" +#define DIV_ENGINE_VERSION 93 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index f9a39724..8b8a1fb0 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -506,6 +506,20 @@ void DivInstrument::putInsData(SafeWriter* w) { // C64 no test w->writeC(c64.noTest); + + // MultiPCM + w->writeC(multipcm.ar); + w->writeC(multipcm.d1r); + w->writeC(multipcm.dl); + w->writeC(multipcm.d2r); + w->writeC(multipcm.rr); + w->writeC(multipcm.rc); + w->writeC(multipcm.lfo); + w->writeC(multipcm.vib); + w->writeC(multipcm.am); + for (int j=0; j<23; j++) { // reserved + w->writeC(0); + } } DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { @@ -1014,6 +1028,21 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { c64.noTest=reader.readC(); } + // MultiPCM + if (version>=93) { + multipcm.ar=reader.readC(); + multipcm.d1r=reader.readC(); + multipcm.dl=reader.readC(); + multipcm.d2r=reader.readC(); + multipcm.rr=reader.readC(); + multipcm.rc=reader.readC(); + multipcm.lfo=reader.readC(); + multipcm.vib=reader.readC(); + multipcm.am=reader.readC(); + // reserved + for (int k=0; k<23; k++) reader.readC(); + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index d660c579..dc1b0b7f 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -338,6 +338,16 @@ struct DivInstrumentFDS { } }; +struct DivInstrumentMultiPCM { + unsigned char ar, d1r, dl, d2r, rr, rc; + unsigned char lfo, vib, am; + + DivInstrumentMultiPCM(): + ar(15), d1r(15), dl(0), d2r(0), rr(15), rc(15), + lfo(0), vib(0), am(0) { + } +}; + enum DivWaveSynthEffects { DIV_WS_NONE=0, // one waveform effects @@ -393,6 +403,7 @@ struct DivInstrument { DivInstrumentAmiga amiga; DivInstrumentN163 n163; DivInstrumentFDS fds; + DivInstrumentMultiPCM multipcm; DivInstrumentWaveSynth ws; /** diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ed776524..99c5f4dd 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2587,6 +2587,108 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndTabItem(); } + if (ins->type==DIV_INS_MULTIPCM) { + if (ImGui::BeginTabItem("MultiPCM")) { + String sName; + if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) { + sName="none selected"; + } else { + sName=e->song.sample[ins->amiga.initSample]->name; + } + if (ImGui::BeginCombo("Initial Sample",sName.c_str())) { + String id; + for (int i=0; isong.sampleLen; i++) { + id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name); + if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { + ins->amiga.initSample=i; + PARAMETER + } + } + ImGui::EndCombo(); + } + ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); + if (ImGui::BeginTable("MultiPCMADSRParams",7,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c6",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("AR"); + ImGui::TextUnformatted("AR"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Attack Rate"); + } + ImGui::TableNextColumn(); + CENTER_TEXT("D1R"); + ImGui::TextUnformatted("D1R"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Decay 1 Rate"); + } + ImGui::TableNextColumn(); + CENTER_TEXT("DL"); + ImGui::TextUnformatted("DL"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Decay Level"); + } + ImGui::TableNextColumn(); + CENTER_TEXT("D2R"); + ImGui::TextUnformatted("D2R"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Decay 2 Rate"); + } + ImGui::TableNextColumn(); + CENTER_TEXT("RR"); + ImGui::TextUnformatted("RR"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Release Rate"); + } + ImGui::TableNextColumn(); + CENTER_TEXT("RC"); + ImGui::TextUnformatted("RC"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Rate Correction"); + } + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Attack Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.ar,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Decay 1 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d1r,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Decay Level",sliderSize,ImGuiDataType_U8,&ins->multipcm.dl,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Decay 2 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d2r,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Release Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.rr,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + drawFMEnv(0,ins->multipcm.ar,ins->multipcm.d1r,ins->multipcm.d2r,ins->multipcm.rr,ins->multipcm.dl,0,0,0,127,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + ImGui::EndTable(); + } + if (ImGui::BeginTable("MultiPCMLFOParams",3,ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableNextColumn(); + P(CWSliderScalar("LFO Rate",ImGuiDataType_U8,&ins->multipcm.lfo,&_ZERO,&_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("PM Depth",ImGuiDataType_U8,&ins->multipcm.vib,&_ZERO,&_SEVEN)); rightClickable + ImGui::TableNextColumn(); + P(CWSliderScalar("AM Depth",ImGuiDataType_U8,&ins->multipcm.am,&_ZERO,&_SEVEN)); rightClickable + ImGui::EndTable(); + } + ImGui::EndTabItem(); + } + } if (ins->type==DIV_INS_GB || (ins->type==DIV_INS_AMIGA && ins->amiga.useWave) || ins->type==DIV_INS_X1_010 || @@ -2718,7 +2820,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AMIGA) { volMax=64; } - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SU) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) { volMax=127; } if (ins->type==DIV_INS_GB) { @@ -2771,7 +2873,7 @@ void FurnaceGUI::drawInsEdit() { dutyLabel="Noise"; dutyMax=8; } - if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS) { + if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) { dutyMax=0; } if (ins->type==DIV_INS_VERA) { @@ -2803,6 +2905,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SAA1099) waveMax=2; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) waveMax=0; if (ins->type==DIV_INS_MIKEY) waveMax=0; + if (ins->type==DIV_INS_MULTIPCM) waveMax=0; if (ins->type==DIV_INS_SU) waveMax=7; if (ins->type==DIV_INS_PET) { waveMax=8; @@ -2863,6 +2966,11 @@ void FurnaceGUI::drawInsEdit() { panMin=-16; panMax=16; } + if (ins->type==DIV_INS_MULTIPCM) { + panMin=-7; + panMax=7; + panSingleNoBit=true; + } if (ins->type==DIV_INS_SU) { panMin=-127; panMax=127; @@ -2915,6 +3023,7 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SWAN || + ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) { NORMAL_MACRO(ins->std.phaseResetMacro,0,1,"phaseReset","Phase Reset",32,ins->std.phaseResetMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[16],0,1,NULL,false); }