Add notifySampleChanged in dispatch and engine:

This method/variables are for notify sample is changed/altered/added/removed.  can be called together with updateSampleTex for sample update.

multipcm: Fix possible desync with instrument and sample parameter

opl4: Split sample table render and sample data render, Add notifySampleChange for refresh sample parameters
This commit is contained in:
cam900 2025-09-22 15:54:48 +09:00 committed by freq-mod
parent 7253bf66cd
commit 1b712e03ee
15 changed files with 146 additions and 52 deletions

View file

@ -917,6 +917,11 @@ class DivDispatch {
*/
virtual void notifyWaveChange(int wave);
/**
* notify sample change.
*/
virtual void notifySampleChange(int sample);
/**
* notify addition of an instrument.
*/

View file

@ -283,6 +283,14 @@ void DivEngine::notifyWaveChange(int wave) {
BUSY_END;
}
void DivEngine::notifySampleChange(int sample) {
BUSY_BEGIN;
for (int i=0; i<song.systemLen; i++) {
disCont[i].dispatch->notifySampleChange(sample);
}
BUSY_END;
}
int DivEngine::loadSampleROM(String path, ssize_t expectedSize, unsigned char*& ret) {
ret=NULL;
if (path.empty()) {

View file

@ -748,6 +748,8 @@ class DivEngine {
void notifyInsChange(int ins);
// notify wavetable change
void notifyWaveChange(int wave);
// notify sample change
void notifySampleChange(int sample);
// dispatch a command
int dispatchCmd(DivCommand c);

View file

@ -160,7 +160,11 @@ void DivDispatch::notifyInsChange(int ins) {
}
void DivDispatch::notifyWaveChange(int ins) {
void DivDispatch::notifyWaveChange(int wave) {
}
void DivDispatch::notifySampleChange(int sample) {
}

View file

@ -516,6 +516,10 @@ void DivPlatformMultiPCM::notifyInsChange(int ins) {
}
}
void DivPlatformMultiPCM::notifySampleChange(int sample) {
renderInstruments();
}
void DivPlatformMultiPCM::notifyInsAddition(int sysID) {
renderInstruments();
}
@ -654,8 +658,6 @@ void DivPlatformMultiPCM::renderSamples(int sysID) {
memCompo=DivMemoryComposition();
memCompo.name="Sample Memory";
renderInstruments();
size_t memPos=0x1800;
int sampleCount=parent->song.sampleLen;
if (sampleCount>512) {
@ -709,6 +711,7 @@ void DivPlatformMultiPCM::renderSamples(int sysID) {
pcmMemLen=memPos+256;
memCompo.used=pcmMemLen;
}
renderInstruments();
memCompo.capacity=getSampleMemCapacity(0);
}

View file

@ -120,6 +120,7 @@ class DivPlatformMultiPCM: public DivDispatch {
void toggleRegisterDump(bool enable);
void setFlags(const DivConfig& flags);
void notifyInsChange(int ins);
void notifySampleChange(int sample);
void notifyInsAddition(int sysID);
void notifyInsDeletion(void* ins);
int getPortaFloor(int ch);

View file

@ -2993,6 +2993,12 @@ void DivPlatformOPL::notifyInsChange(int ins) {
}
}
void DivPlatformOPL::notifySampleChange(int sample) {
if (pcmChanOffs>=0) {
renderInstruments();
}
}
void DivPlatformOPL::notifyInsDeletion(void* ins) {
for (int i=0; i<totalChans; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
@ -3264,6 +3270,58 @@ const DivMemoryComposition* DivPlatformOPL::getMemCompo(int index) {
return &memCompo;
}
// this is called on instrument change, reset and/or renderSamples().
// I am not making this part of DivDispatch as this is the only chip with
// instruments in ROM.
void DivPlatformOPL::renderInstruments() {
if (pcmChanOffs>=0) {
const int maxSample=PCM_IN_RAM?128:512;
int sampleCount=parent->song.sampleLen;
if (sampleCount>maxSample) {
sampleCount=maxSample;
}
// instrument table
for (int i=0; i<sampleCount; i++) {
DivSample* s=parent->song.sample[i];
unsigned int insAddr=(i*12)+(PCM_IN_RAM?0x200000:0);
unsigned char bitDepth;
int endPos=CLAMP(s->isLoopable()?s->loopEnd:(s->samples+1),1,0x10000);
int loop=s->isLoopable()?CLAMP(s->loopStart,0,endPos-2):(endPos-2);
switch (s->depth) {
case DIV_SAMPLE_DEPTH_8BIT:
bitDepth=0;
break;
case DIV_SAMPLE_DEPTH_12BIT:
bitDepth=1;
if (!s->isLoopable()) {
endPos++;
loop++;
}
break;
case DIV_SAMPLE_DEPTH_16BIT:
bitDepth=2;
break;
default:
bitDepth=0;
break;
}
pcmMem[insAddr]=(bitDepth<<6)|((sampleOffPCM[i]>>16)&0x3f);
pcmMem[1+insAddr]=(sampleOffPCM[i]>>8)&0xff;
pcmMem[2+insAddr]=(sampleOffPCM[i])&0xff;
pcmMem[3+insAddr]=(loop>>8)&0xff;
pcmMem[4+insAddr]=(loop)&0xff;
pcmMem[5+insAddr]=((~(endPos-1))>>8)&0xff;
pcmMem[6+insAddr]=(~(endPos-1))&0xff;
// on MultiPCM this consists of instrument params, but on OPL4 this is not used
pcmMem[7+insAddr]=0; // LFO, VIB
pcmMem[8+insAddr]=(0xf<<4)|(0xf<<0); // AR, D1R
pcmMem[9+insAddr]=0; // DL, D2R
pcmMem[10+insAddr]=(0xf<<4)|(0xf<<0); // RC, RR
pcmMem[11+insAddr]=0; // AM
}
}
}
void DivPlatformOPL::renderSamples(int sysID) {
if (adpcmChan<0 && pcmChanOffs<0) return;
if (adpcmChan>=0 && adpcmBMem!=NULL) {
@ -3349,45 +3407,7 @@ void DivPlatformOPL::renderSamples(int sysID) {
}
pcmMemLen=memPos+256;
// instrument table
for (int i=0; i<sampleCount; i++) {
DivSample* s=parent->song.sample[i];
unsigned int insAddr=(i*12)+(PCM_IN_RAM?0x200000:0);
unsigned char bitDepth;
int endPos=CLAMP(s->isLoopable()?s->loopEnd:(s->samples+1),1,0x10000);
int loop=s->isLoopable()?CLAMP(s->loopStart,0,endPos-2):(endPos-2);
switch (s->depth) {
case DIV_SAMPLE_DEPTH_8BIT:
bitDepth=0;
break;
case DIV_SAMPLE_DEPTH_12BIT:
bitDepth=1;
if (!s->isLoopable()) {
endPos++;
loop++;
}
break;
case DIV_SAMPLE_DEPTH_16BIT:
bitDepth=2;
break;
default:
bitDepth=0;
break;
}
pcmMem[insAddr]=(bitDepth<<6)|((sampleOffPCM[i]>>16)&0x3f);
pcmMem[1+insAddr]=(sampleOffPCM[i]>>8)&0xff;
pcmMem[2+insAddr]=(sampleOffPCM[i])&0xff;
pcmMem[3+insAddr]=(loop>>8)&0xff;
pcmMem[4+insAddr]=(loop)&0xff;
pcmMem[5+insAddr]=((~(endPos-1))>>8)&0xff;
pcmMem[6+insAddr]=(~(endPos-1))&0xff;
// on MultiPCM this consists of instrument params, but on OPL4 this is not used
pcmMem[7+insAddr]=0; // LFO, VIB
pcmMem[8+insAddr]=(0xf<<4)|(0xf<<0); // AR, D1R
pcmMem[9+insAddr]=0; // DL, D2R
pcmMem[10+insAddr]=(0xf<<4)|(0xf<<0); // RC, RR
pcmMem[11+insAddr]=0; // AM
}
renderInstruments();
if (PCM_IN_RAM) {
memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_RESERVED,"ROM data",0,0,0x200000));
}

View file

@ -186,6 +186,8 @@ class DivPlatformOPL: public DivDispatch {
void acquire_ymfm2(short** buf, size_t len);
void acquire_ymfm1(short** buf, size_t len);
void renderInstruments();
public:
void acquire(short** buf, size_t len);
int dispatch(DivCommand c);
@ -211,6 +213,7 @@ class DivPlatformOPL: public DivDispatch {
void toggleRegisterDump(bool enable);
void setFlags(const DivConfig& flags);
void notifyInsChange(int ins);
void notifySampleChange(int sample);
void notifyInsDeletion(void* ins);
int getPortaFloor(int ch);
void poke(unsigned int addr, unsigned short val);

View file

@ -279,6 +279,7 @@ void FurnaceGUI::sampleListItem(int i, int dir, int asset) {
curSample=i;
samplePos=0;
updateSampleTex=true;
notifySampleChange=true;
lastAssetType=2;
}
if (ImGui::IsItemHovered() && !mobileUI) {
@ -309,6 +310,7 @@ void FurnaceGUI::sampleListItem(int i, int dir, int asset) {
curSample=i;
samplePos=0;
updateSampleTex=true;
notifySampleChange=true;
lastAssetType=2;
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_TEXT]);
if (ImGui::MenuItem(_("edit"))) {

View file

@ -946,6 +946,7 @@ void FurnaceGUI::doAction(int what) {
MARK_MODIFIED;
}
updateSampleTex=true;
notifySampleChange=true;
}
break;
case GUI_ACTION_WAVE_LIST_MOVE_UP:
@ -1003,6 +1004,7 @@ void FurnaceGUI::doAction(int what) {
MARK_MODIFIED;
}
updateSampleTex=true;
notifySampleChange=true;
break;
case GUI_ACTION_SAMPLE_LIST_DUPLICATE:
if (curSample>=0 && curSample<(int)e->song.sample.size()) {
@ -1037,6 +1039,7 @@ void FurnaceGUI::doAction(int what) {
MARK_MODIFIED;
}
updateSampleTex=true;
notifySampleChange=true;
}
break;
case GUI_ACTION_SAMPLE_LIST_OPEN:
@ -1062,6 +1065,7 @@ void FurnaceGUI::doAction(int what) {
curSample--;
wantScrollListSample=true;
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
}
break;
@ -1070,6 +1074,7 @@ void FurnaceGUI::doAction(int what) {
curSample++;
wantScrollListSample=true;
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
}
break;
@ -1081,6 +1086,7 @@ void FurnaceGUI::doAction(int what) {
curSample--;
}
updateSampleTex=true;
notifySampleChange=true;
break;
case GUI_ACTION_SAMPLE_LIST_EDIT:
sampleEditOpen=true;
@ -1089,11 +1095,13 @@ void FurnaceGUI::doAction(int what) {
if (--curSample<0) curSample=0;
wantScrollListSample=true;
updateSampleTex=true;
notifySampleChange=true;
break;
case GUI_ACTION_SAMPLE_LIST_DOWN:
if (++curSample>=(int)e->song.sample.size()) curSample=((int)e->song.sample.size())-1;
wantScrollListSample=true;
updateSampleTex=true;
notifySampleChange=true;
break;
case GUI_ACTION_SAMPLE_LIST_PREVIEW:
e->previewSample(curSample);
@ -1183,6 +1191,7 @@ void FurnaceGUI::doAction(int what) {
e->lockEngine([this,sample,start,end]() {
sample->strip(start,end);
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1235,6 +1244,7 @@ void FurnaceGUI::doAction(int what) {
sampleSelStart=pos;
sampleSelEnd=pos+sampleClipboardLen;
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
break;
}
@ -1266,6 +1276,7 @@ void FurnaceGUI::doAction(int what) {
sampleSelEnd=pos+sampleClipboardLen;
if (sampleSelEnd>(int)sample->samples) sampleSelEnd=sample->samples;
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
break;
}
@ -1303,6 +1314,7 @@ void FurnaceGUI::doAction(int what) {
sampleSelEnd=pos+sampleClipboardLen;
if (sampleSelEnd>(int)sample->samples) sampleSelEnd=sample->samples;
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
break;
}
@ -1368,6 +1380,7 @@ void FurnaceGUI::doAction(int what) {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1399,6 +1412,7 @@ void FurnaceGUI::doAction(int what) {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1430,6 +1444,7 @@ void FurnaceGUI::doAction(int what) {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1459,6 +1474,7 @@ void FurnaceGUI::doAction(int what) {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1475,6 +1491,7 @@ void FurnaceGUI::doAction(int what) {
sample->strip(start,end);
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1493,6 +1510,7 @@ void FurnaceGUI::doAction(int what) {
sample->trim(start,end);
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1528,6 +1546,7 @@ void FurnaceGUI::doAction(int what) {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1555,6 +1574,7 @@ void FurnaceGUI::doAction(int what) {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1580,6 +1600,7 @@ void FurnaceGUI::doAction(int what) {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1713,6 +1734,7 @@ void FurnaceGUI::doAction(int what) {
sample->loopEnd=end;
sample->loop=true;
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});

View file

@ -2915,6 +2915,7 @@ void FurnaceGUI::processDrags(int dragX, int dragY) {
for (int i=x; i<=x1; i++) ((signed char*)sampleDragTarget)[i]=val;
}
updateSampleTex=true;
notifySampleChange=true;
}
} else { // select
if (sampleSelStart<0) {
@ -4019,26 +4020,22 @@ bool FurnaceGUI::loop() {
}
nextWindow=GUI_WINDOW_WAVE_LIST;
MARK_MODIFIED;
}
else if (!samples.empty())
{
} else if (!samples.empty()) {
if (e->song.sampleLen!=sampleCountBefore) {
//e->renderSamplesP();
}
if (!e->getWarnings().empty())
{
if (!e->getWarnings().empty()) {
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
}
int sampleCount=-1;
for (DivSample* s: samples)
{
for (DivSample* s: samples) {
sampleCount=e->addSamplePtr(s);
}
//sampleCount=e->addSamplePtr(droppedSample);
if (sampleCount>=0 && settings.selectAssetOnLoad)
{
if (sampleCount>=0 && settings.selectAssetOnLoad) {
curSample=sampleCount;
updateSampleTex=true;
notifySampleChange=true;
}
nextWindow=GUI_WINDOW_SAMPLE_LIST;
MARK_MODIFIED;
@ -4277,6 +4274,11 @@ bool FurnaceGUI::loop() {
e->notifyWaveChange(curWave);
}
if (notifySampleChange) {
notifySampleChange=false;
e->notifySampleChange(curSample);
}
eventTimeEnd=SDL_GetPerformanceCounter();
if (SDL_GetWindowFlags(sdlWin)&SDL_WINDOW_MINIMIZED) {
@ -5523,6 +5525,7 @@ bool FurnaceGUI::loop() {
MARK_MODIFIED;
});
updateSampleTex=true;
notifySampleChange=true;
} else {
showError(_("...but you haven't selected a sample!"));
delete samples[0];
@ -7146,6 +7149,7 @@ bool FurnaceGUI::loop() {
MARK_MODIFIED;
});
updateSampleTex=true;
notifySampleChange=true;
} else {
showError(_("...but you haven't selected a sample!"));
delete s;
@ -8511,6 +8515,7 @@ FurnaceGUI::FurnaceGUI():
sysDupEnd(false),
noteInputPoly(true),
notifyWaveChange(false),
notifySampleChange(false),
wantScrollListIns(false),
wantScrollListWave(false),
wantScrollListSample(false),

View file

@ -1707,7 +1707,7 @@ class FurnaceGUI {
bool vgmExportDirectStream, displayInsTypeList, displayWaveSizeList;
bool portrait, injectBackUp, mobileMenuOpen, warnColorPushed;
bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu;
bool displayNew, displayExport, displayPalette, fullScreen, preserveChanPos, sysDupCloneChannels, sysDupEnd, noteInputPoly, notifyWaveChange;
bool displayNew, displayExport, displayPalette, fullScreen, preserveChanPos, sysDupCloneChannels, sysDupEnd, noteInputPoly, notifyWaveChange, notifySampleChange;
bool wantScrollListIns, wantScrollListWave, wantScrollListSample;
bool displayPendingIns, pendingInsSingle, displayPendingRawSample, snesFilterHex, modTableHex, displayEditString;
bool displayPendingSamples, replacePendingSample;

View file

@ -3465,6 +3465,7 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) {
if (ImGui::InputInt(_("Sample bank slot##BANKSLOT"),&ins->x1_010.bankSlot,1,4)) { PARAMETER
if (ins->x1_010.bankSlot<0) ins->x1_010.bankSlot=0;
if (ins->x1_010.bankSlot>=7) ins->x1_010.bankSlot=7;
notifySampleChange=true;
}
}
}
@ -3478,6 +3479,7 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) {
id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name);
if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER
ins->amiga.initSample=i;
notifySampleChange=true;
}
}
ImGui::EndCombo();

View file

@ -289,6 +289,7 @@ void FurnaceGUI::drawNewSong() {
orderCursor=-1;
samplePos=0;
updateSampleTex=true;
notifySampleChange=true;
selStart=SelectionPoint();
selEnd=SelectionPoint();
cursor=SelectionPoint();

View file

@ -656,6 +656,7 @@ void FurnaceGUI::drawSampleEdit() {
sample->loopEnd=sample->samples;*/
}
updateSampleTex=true;
notifySampleChange=true;
REFRESH_SAMPLE
}
popWarningColor();
@ -688,6 +689,7 @@ void FurnaceGUI::drawSampleEdit() {
e->renderSamples(curSample);
});
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
}
}
@ -708,6 +710,7 @@ void FurnaceGUI::drawSampleEdit() {
sample->brrEmphasis=be;
e->renderSamplesP(curSample);
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
}
if (ImGui::IsItemHovered()) {
@ -725,6 +728,7 @@ void FurnaceGUI::drawSampleEdit() {
sample->brrNoFilter=bf;
e->renderSamplesP(curSample);
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
}
if (ImGui::IsItemHovered()) {
@ -738,6 +742,7 @@ void FurnaceGUI::drawSampleEdit() {
sample->dither=di;
e->renderSamplesP(curSample);
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
}
if (ImGui::IsItemHovered()) {
@ -870,6 +875,7 @@ void FurnaceGUI::drawSampleEdit() {
sample->loopMode=(DivSampleLoopMode)i;
e->renderSamplesP(curSample);
updateSampleTex=true;
notifySampleChange=true;
MARK_MODIFIED;
}
}
@ -893,6 +899,7 @@ void FurnaceGUI::drawSampleEdit() {
sample->loopStart=sample->loopEnd;
}
updateSampleTex=true;
notifySampleChange=true;
REFRESH_SAMPLE
}
if (ImGui::IsItemActive()) {
@ -934,6 +941,7 @@ void FurnaceGUI::drawSampleEdit() {
sample->loopEnd=sample->samples;
}
updateSampleTex=true;
notifySampleChange=true;
REFRESH_SAMPLE
}
if (ImGui::IsItemActive()) {
@ -1108,6 +1116,7 @@ void FurnaceGUI::drawSampleEdit() {
e->renderSamples(curSample);
});
updateSampleTex=true;
notifySampleChange=true;
sampleSelStart=-1;
sampleSelEnd=-1;
MARK_MODIFIED;
@ -1172,6 +1181,7 @@ void FurnaceGUI::drawSampleEdit() {
e->renderSamples(curSample);
});
updateSampleTex=true;
notifySampleChange=true;
sampleSelStart=-1;
sampleSelEnd=-1;
MARK_MODIFIED;
@ -1239,6 +1249,7 @@ void FurnaceGUI::drawSampleEdit() {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1292,6 +1303,7 @@ void FurnaceGUI::drawSampleEdit() {
e->renderSamples(curSample);
});
updateSampleTex=true;
notifySampleChange=true;
sampleSelStart=pos;
sampleSelEnd=pos+silenceSize;
MARK_MODIFIED;
@ -1467,6 +1479,7 @@ void FurnaceGUI::drawSampleEdit() {
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -1546,6 +1559,7 @@ void FurnaceGUI::drawSampleEdit() {
}
}
updateSampleTex=true;
notifySampleChange=true;
e->renderSamples(curSample);
});
@ -2508,6 +2522,7 @@ void FurnaceGUI::doUndoSample() {
if (sample->undo()==2) {
e->renderSamples(curSample);
updateSampleTex=true;
notifySampleChange=true;
}
});
}
@ -2520,6 +2535,7 @@ void FurnaceGUI::doRedoSample() {
if (sample->redo()==2) {
e->renderSamples(curSample);
updateSampleTex=true;
notifySampleChange=true;
}
});
}