From bd8d9a56a033b28f213fe60918f7d06becb7abb3 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 27 Aug 2025 22:52:19 +0900 Subject: [PATCH] Prepare to add hasSamplePtrHeader and hasSampleInstHeader in dispatch (WIP) for refresh sample memory when loop/end pointer and instrument parameter changed. Also, this PR has minor code style fixes and add warning in MultiPCM sample map usage. --- src/engine/dispatch.h | 20 ++++++++++++++--- src/engine/engine.cpp | 27 +++++++++++++++++++++++ src/engine/platform/abstract.cpp | 8 +++++++ src/engine/platform/opl.cpp | 8 +++++++ src/engine/platform/opl.h | 2 ++ src/engine/platform/snes.cpp | 4 ++++ src/engine/platform/snes.h | 7 +++--- src/gui/gui.cpp | 32 +++++++++++++++++++++++---- src/gui/insEdit.cpp | 37 ++++++++++++++++++++++++-------- src/gui/sampleEdit.cpp | 24 +++++++++++++-------- 10 files changed, 141 insertions(+), 28 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index c048ad918..ec10500dc 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -966,14 +966,14 @@ class DivDispatch { * @param index the memory index. * @return a pointer to sample memory, or NULL. */ - virtual const void* getSampleMem(int index = 0); + virtual const void* getSampleMem(int index=0); /** * Get sample memory capacity. * @param index the memory index. * @return memory capacity in bytes, or 0 if memory doesn't exist. */ - virtual size_t getSampleMemCapacity(int index = 0); + virtual size_t getSampleMemCapacity(int index=0); /** * get sample memory name. @@ -987,8 +987,22 @@ class DivDispatch { * @param index the memory index. * @return memory usage in bytes. */ - virtual size_t getSampleMemUsage(int index = 0); + virtual size_t getSampleMemUsage(int index=0); + /** + * check whether chip has sample pointer header in sample memory. + * @param index the memory index. + * @return whether it did. + */ + virtual bool hasSamplePtrHeader(int index=0); + + /** + * check whether chip has sample instrument header in sample memory. + * @param index the memory index. + * @return whether it did. + */ + virtual bool hasSampleInstHeader(int index=0); + /** * check whether sample has been loaded in memory. * @param index index. diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index ac6f49044..192c511db 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2648,6 +2648,15 @@ int DivEngine::addInstrument(int refChan, DivInstrumentType fallbackType) { song.insLen=insCount+1; checkAssetDir(song.insDir,song.ins.size()); saveLock.unlock(); + bool hasSampleInst=false; + for (int s=0; shasSampleInstHeader()) { + hasSampleInst=true; + } + } + if (hasSampleInst) { + renderSamplesP(); + } BUSY_END; return insCount; } @@ -2665,6 +2674,15 @@ int DivEngine::addInstrumentPtr(DivInstrument* which) { checkAssetDir(song.waveDir,song.wave.size()); checkAssetDir(song.sampleDir,song.sample.size()); saveLock.unlock(); + bool hasSampleInst=false; + for (int s=0; shasSampleInstHeader()) { + hasSampleInst=true; + } + } + if (hasSampleInst) { + renderSamplesP(); + } BUSY_END; return song.insLen; } @@ -2700,6 +2718,15 @@ void DivEngine::delInstrumentUnsafe(int index) { } removeAsset(song.insDir,index); checkAssetDir(song.insDir,song.ins.size()); + bool hasSampleInst=false; + for (int s=0; shasSampleInstHeader()) { + hasSampleInst=true; + } + } + if (hasSampleInst) { + renderSamplesP(); + } } } diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index a5ae25676..cc541a841 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -213,6 +213,14 @@ size_t DivDispatch::getSampleMemUsage(int index) { return 0; } +bool DivDispatch::hasSamplePtrHeader(int index) { + return false; +} + +bool DivDispatch::hasSampleInstHeader(int index) { + return false; +} + const DivMemoryComposition* DivDispatch::getMemCompo(int index) { return NULL; } diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 5a8f81a4e..10d28a73a 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -3244,6 +3244,14 @@ size_t DivPlatformOPL::getSampleMemUsage(int index) { (index==0 && adpcmChan>=0)?adpcmBMemLen:0; } +bool DivPlatformOPL::hasSamplePtrHeader(int index) { + return (index==0 && pcmChanOffs>=0); +} + +bool DivPlatformOPL::hasSampleInstHeader(int index) { + return (index==0 && pcmChanOffs>=0); +} + bool DivPlatformOPL::isSampleLoaded(int index, int sample) { if (index!=0) return false; if (sample<0 || sample>32767) return false; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 43cf9bd3c..2905b71bf 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -218,6 +218,8 @@ class DivPlatformOPL: public DivDispatch { const void* getSampleMem(int index); size_t getSampleMemCapacity(int index); size_t getSampleMemUsage(int index); + bool hasSamplePtrHeader(int index=0); + bool hasSampleInstHeader(int index=0); bool isSampleLoaded(int index, int sample); const DivMemoryComposition* getMemCompo(int index); void renderSamples(int chipID); diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 3686d0c30..6d7c90629 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -964,6 +964,10 @@ size_t DivPlatformSNES::getSampleMemUsage(int index) { return index == 0 ? sampleMemLen : 0; } +bool DivPlatformSNES::hasSamplePtrHeader(int index) { + return true; +} + bool DivPlatformSNES::isSampleLoaded(int index, int sample) { if (index!=0) return false; if (sample<0 || sample>32767) return false; diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index 62ec1bd35..306bf653d 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -124,9 +124,10 @@ class DivPlatformSNES: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); const char** getRegisterSheet(); - const void* getSampleMem(int index = 0); - size_t getSampleMemCapacity(int index = 0); - size_t getSampleMemUsage(int index = 0); + const void* getSampleMem(int index=0); + size_t getSampleMemCapacity(int index=0); + size_t getSampleMemUsage(int index=0); + bool hasSamplePtrHeader(int index=0); bool isSampleLoaded(int index, int sample); const DivMemoryComposition* getMemCompo(int index); void renderSamples(int chipID); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 8c3929022..e7efc2b3f 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1861,7 +1861,13 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { int sampleCountBefore=e->song.sampleLen; std::vector instruments=e->instrumentFromFile(path,false); if (!instruments.empty()) { - if (e->song.sampleLen!=sampleCountBefore) { + int hasSampleInst=false; + for (int s=0; ssong.systemLen; s++) { + if (e->getDispatch(s)->hasSampleInstHeader()) { + hasSampleInst=true; + } + } + if ((e->song.sampleLen!=sampleCountBefore) || hasSampleInst) { e->renderSamplesP(); } if (curFileDialog==GUI_FILE_INS_OPEN_REPLACE) { @@ -3928,7 +3934,13 @@ bool FurnaceGUI::loop() { DivWavetable* droppedWave=NULL; //DivSample* droppedSample=NULL; if (!instruments.empty()) { - if (e->song.sampleLen!=sampleCountBefore) { + bool hasSampleInst=false; + for (int s=0; ssong.systemLen; s++) { + if (e->getDispatch(s)->hasSampleInstHeader()) { + hasSampleInst=true; + } + } + if ((e->song.sampleLen!=sampleCountBefore) || hasSampleInst) { e->renderSamplesP(); } if (!e->getWarnings().empty()) { @@ -5521,7 +5533,13 @@ bool FurnaceGUI::loop() { instruments.push_back(j); } } - if (e->song.sampleLen!=sampleCountBefore) { + bool hasSampleInst=false; + for (int s=0; ssong.systemLen; s++) { + if (e->getDispatch(s)->hasSampleInstHeader()) { + hasSampleInst=true; + } + } + if ((e->song.sampleLen!=sampleCountBefore) || hasSampleInst) { e->renderSamplesP(); } if (warn) { @@ -5561,7 +5579,13 @@ bool FurnaceGUI::loop() { int sampleCountBefore=e->song.sampleLen; std::vector instruments=e->instrumentFromFile(copyOfName.c_str(),true,settings.readInsNames); if (!instruments.empty()) { - if (e->song.sampleLen!=sampleCountBefore) { + bool hasSampleInst=false; + for (int s=0; ssong.systemLen; s++) { + if (e->getDispatch(s)->hasSampleInstHeader()) { + hasSampleInst=true; + } + } + if ((e->song.sampleLen!=sampleCountBefore) || hasSampleInst) { e->renderSamplesP(); } if (!e->getWarnings().empty()) { diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 2f2e338ea..547a5c0c1 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1982,6 +1982,22 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s updateFMPreview=true; \ } +// with instrument header in sample memory +#define PH(x) if (x) { \ + MARK_MODIFIED; \ + e->notifyInsChange(curIns); \ + updateFMPreview=true; \ + bool hasSampleInst=false; \ + for (int s=0; ssong.systemLen; s++) { \ + if (e->getDispatch(s)->hasSampleInstHeader()) { \ + hasSampleInst=true; \ + } \ + } \ + if (hasSampleInst) { \ + e->renderSamplesP(curSample); \ + } \ +} + #define PARAMETER MARK_MODIFIED; e->notifyInsChange(curIns); updateFMPreview=true; String genericGuide(float value) { @@ -3512,6 +3528,9 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) { // Note map ImGui::BeginDisabled(ins->amiga.useWave); P(ImGui::Checkbox(_("Use sample map"),&ins->amiga.useNoteMap)); + if ((ins->type==DIV_INS_MULTIPCM) && ImGui::IsItemHovered()) { + ImGui::SetTooltip(_("Only for OPL4 PCM.")); + } if (ins->amiga.useNoteMap) { if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) sampleMapFocused=false; if (curWindowLast!=GUI_WINDOW_INS_EDIT) sampleMapFocused=false; @@ -7885,17 +7904,17 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); ImGui::TableNextColumn(); - P(CWVSliderScalar("##Attack Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.ar,&_ZERO,&_FIFTEEN)); rightClickable + PH(CWVSliderScalar("##Attack Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.ar,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay 1 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d1r,&_ZERO,&_FIFTEEN)); rightClickable + PH(CWVSliderScalar("##Decay 1 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d1r,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay Level",sliderSize,ImGuiDataType_U8,&ins->multipcm.dl,&_ZERO,&_FIFTEEN)); rightClickable + PH(CWVSliderScalar("##Decay Level",sliderSize,ImGuiDataType_U8,&ins->multipcm.dl,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Decay 2 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d2r,&_ZERO,&_FIFTEEN)); rightClickable + PH(CWVSliderScalar("##Decay 2 Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.d2r,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Release Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.rr,&_ZERO,&_FIFTEEN)); rightClickable + PH(CWVSliderScalar("##Release Rate",sliderSize,ImGuiDataType_U8,&ins->multipcm.rr,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); - P(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN)); rightClickable + PH(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN)); rightClickable ImGui::TableNextColumn(); drawFMEnv(0,ins->multipcm.ar,ins->multipcm.d1r,ins->multipcm.d2r,ins->multipcm.rr,ins->multipcm.dl,0,0,0,127,15,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); @@ -7905,11 +7924,11 @@ void FurnaceGUI::drawInsEdit() { 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 + PH(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 + PH(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 + PH(CWSliderScalar(_("AM Depth"),ImGuiDataType_U8,&ins->multipcm.am,&_ZERO,&_SEVEN)); rightClickable ImGui::EndTable(); } P(ImGui::Checkbox(_("Damp"),&ins->multipcm.damp)); diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 240d0c8bd..6b345aa28 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -60,6 +60,18 @@ const double timeMultipliers[13]={ _x+=_text; \ } +// with sample pointer header in sample memory +#define REFRESH_SAMPLE \ + bool hasSamplePtr=false; \ + for (int s=0; ssong.systemLen; s++) { \ + if (e->getDispatch(s)->hasSamplePtrHeader()) { \ + hasSamplePtr=true; \ + } \ + } \ + if (hasSamplePtr) { \ + e->renderSamplesP(curSample); \ + } + #define MAX_RATE(_name,_x) \ if (e->isPreviewingSample()) { \ if ((int)e->getSamplePreviewRate()>(int)(_x)) { \ @@ -638,9 +650,7 @@ void FurnaceGUI::drawSampleEdit() { sample->loopEnd=sample->samples;*/ } updateSampleTex=true; - if (e->getSampleFormatMask()&(1U<renderSamplesP(curSample); - } + REFRESH_SAMPLE } popWarningColor(); if (ImGui::IsItemHovered() && (!warnLoop.empty() || sample->depth==DIV_SAMPLE_DEPTH_BRR)) { @@ -877,9 +887,7 @@ void FurnaceGUI::drawSampleEdit() { sample->loopStart=sample->loopEnd; } updateSampleTex=true; - if (e->getSampleFormatMask()&(1U<renderSamplesP(curSample); - } + REFRESH_SAMPLE } if (ImGui::IsItemActive()) { keepLoopAlive=true; @@ -920,9 +928,7 @@ void FurnaceGUI::drawSampleEdit() { sample->loopEnd=sample->samples; } updateSampleTex=true; - if (e->getSampleFormatMask()&(1U<renderSamplesP(curSample); - } + REFRESH_SAMPLE } if (ImGui::IsItemActive()) { keepLoopAlive=true;