From 42d98f0894ea48f0b54a76b02d2189a51a50deac Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 13:58:39 -0500 Subject: [PATCH 01/52] SegaPCM: finally implement new behavior --- TODO.md | 1 - src/engine/platform/segapcm.cpp | 49 ++++++++++++++++++++++++++------- src/engine/platform/segapcm.h | 25 ++++++++++++++++- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/TODO.md b/TODO.md index 1b212d95..1d709d81 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,6 @@ - CSM - MSM6258 pitch and clock select - the last compat flags - - newSegaPCM - newVolumeScaling - collapse/expand pattern and song - Game Boy envelope macro/sequence diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 22ccbff0..46fa1977 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -85,10 +85,17 @@ void DivPlatformSegaPCM::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); - // TODO: fix - /*if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; - }*/ + if (parent->song.newSegaPCM) { + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; + chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; + if (dumpWrites) { + addWrite(0x10002+(i<<3),chan[i].chVolL); + addWrite(0x10003+(i<<3),chan[i].chVolR); + } + } + } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { @@ -107,14 +114,24 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } if (chan[i].std.panL.had) { - chan[i].chVolL=chan[i].std.panL.val&127; + if (parent->song.newSegaPCM) { + chan[i].chPanL=chan[i].std.panL.val&127; + chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; + } else { + chan[i].chVolL=chan[i].std.panL.val&127; + } if (dumpWrites) { addWrite(0x10002+(i<<3),chan[i].chVolL); } } if (chan[i].std.panR.had) { - chan[i].chVolR=chan[i].std.panR.val&127; + if (parent->song.newSegaPCM) { + chan[i].chPanR=chan[i].std.panR.val&127; + chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; + } else { + chan[i].chVolR=chan[i].std.panR.val&127; + } if (dumpWrites) { addWrite(0x10003+(i<<3),chan[i].chVolR); } @@ -261,8 +278,13 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - chan[c.chan].chVolL=c.value; - chan[c.chan].chVolR=c.value; + if (parent->song.newSegaPCM) { + chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127; + chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127; + } else { + chan[c.chan].chVolL=c.value; + chan[c.chan].chVolR=c.value; + } if (dumpWrites) { addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL); addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR); @@ -280,8 +302,15 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].ins=c.value; break; case DIV_CMD_PANNING: { - chan[c.chan].chVolL=c.value>>1; - chan[c.chan].chVolR=c.value2>>1; + if (parent->song.newSegaPCM) { + chan[c.chan].chPanL=c.value>>1; + chan[c.chan].chPanR=c.value2>>1; + chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127; + chan[c.chan].chVolR=(chan[c.chan].outVol*chan[c.chan].chPanR)/127; + } else { + chan[c.chan].chVolL=c.value>>1; + chan[c.chan].chVolR=c.value2>>1; + } if (dumpWrites) { addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL); addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR); diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 32cd22c2..f5fa4ecb 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -34,6 +34,7 @@ class DivPlatformSegaPCM: public DivDispatch { bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM; int vol, outVol; unsigned char chVolL, chVolR; + unsigned char chPanL, chPanR; struct PCMChannel { int sample; @@ -46,7 +47,29 @@ class DivPlatformSegaPCM: public DivDispatch { std.init(which); pitch2=0; } - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {} + Channel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + pitch2(0), + note(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + inPorta(false), + portaPause(false), + furnacePCM(false), + vol(0), + outVol(0), + chVolL(127), + chVolR(127), + chPanL(127), + chPanR(127) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; From 6c98f6d0517c2f0883c4bb15ad6b0a8c6c27a03c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 14:58:55 -0500 Subject: [PATCH 02/52] update to-do list --- TODO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 1d709d81..7c638b0f 100644 --- a/TODO.md +++ b/TODO.md @@ -12,7 +12,7 @@ - add another FM editor layout - if macros have release, note off should release them - add ability to move selection by dragging -- Apply button in settings +- add ability to move subsongs - find and replace - add mono/poly note preview button - (maybe) add default patch selection From 140318f8d3aadc0f56bbbf7a8270204396e35a85 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 15:15:32 -0500 Subject: [PATCH 03/52] SMS: prepare for an arp+porta fix --- src/engine/platform/sms.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index c5cf1091..32fbddd2 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -319,6 +319,8 @@ int DivPlatformSMS::dispatch(DivCommand c) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } chan[c.chan].inPorta=c.value; + // TODO: pre porta cancel arp compat flag + //if (chan[c.chan].inPorta) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); break; case DIV_CMD_GET_VOLMAX: return 15; From 8bfcf0020334c5961ce3a91a1309d763fd55c86a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 16:35:39 -0500 Subject: [PATCH 04/52] prepare for impl of the final compat flag --- src/engine/dispatch.h | 5 +++++ src/ta-utils.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 7cd30cfd..03bc23ca 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -524,6 +524,11 @@ class DivDispatch { // this is a special case definition. only use it for f-num/block-based chips. #define NOTE_FNUM_BLOCK(x,bits) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits) +// this is for volume scaling calculation. +#define VOL_SCALE_LINEAR_BROKEN(x,y,range) ((parent->song.newVolumeScaling)?(((x)*(y))/(range)):(CLAMP(((x)+(y))-(range),0,(range)))) +#define VOL_SCALE_LINEAR(x,y,range) (((x)*(y))/(range)) +#define VOL_SCALE_LOG(x,y,range) ((parent->song.newVolumeScaling)?(CLAMP(((x)+(y))-(range),0,(range))):(((x)*(y))/(range))) + // these are here for convenience. // it is encouraged to use these, since you get an exact value this way. // - NTSC colorburst: 3.58MHz diff --git a/src/ta-utils.h b/src/ta-utils.h index 3a619248..feddbc1e 100644 --- a/src/ta-utils.h +++ b/src/ta-utils.h @@ -40,6 +40,7 @@ typedef std::string String; #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) +#define CLAMP(x,xMin,xMax) (MIN(MAX((x),(xMin)),(xMax))) typedef std::wstring WString; From 8141574d3c0a987eb57c86cfc08d4ad0e6ab4983 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 17:50:26 -0500 Subject: [PATCH 05/52] newVolumeScaling, part 1 --- src/engine/platform/arcade.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 56446725..121183d1 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -284,12 +284,12 @@ void DivPlatformArcade::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127); for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -378,7 +378,7 @@ void DivPlatformArcade::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -432,7 +432,7 @@ void DivPlatformArcade::tick(bool sysTick) { if (m.tl.had) { op.tl=127-m.tl.val; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -528,7 +528,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { DivInstrumentFM::Operator op=chan[c.chan].state.op[i]; if (isOutput[chan[c.chan].state.alg][i]) { if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } } else { if (chan[c.chan].insChanged) { @@ -585,7 +585,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; if (isOutput[chan[c.chan].state.alg][i]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -676,7 +676,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; if (isOutput[chan[c.chan].state.alg][c.value]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -876,7 +876,7 @@ void DivPlatformArcade::forceIns() { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator op=chan[i].state.op[j]; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } From e94d1b857fa6cdd66172278258a85916de78946b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 18:02:34 -0500 Subject: [PATCH 06/52] newVolumeScaling, part 2 --- src/engine/platform/genesis.cpp | 18 +++++++++--------- src/engine/platform/genesisext.cpp | 14 +++++++------- src/engine/platform/opll.cpp | 2 +- src/engine/platform/segapcm.cpp | 2 +- src/engine/platform/tx81z.cpp | 18 +++++++++--------- src/engine/platform/ym2203.cpp | 18 +++++++++--------- src/engine/platform/ym2203ext.cpp | 8 ++++---- src/engine/platform/ym2608.cpp | 16 ++++++++-------- src/engine/platform/ym2608ext.cpp | 10 +++++----- src/engine/platform/ym2610.cpp | 16 ++++++++-------- src/engine/platform/ym2610b.cpp | 16 ++++++++-------- src/engine/platform/ym2610bext.cpp | 10 +++++----- src/engine/platform/ym2610ext.cpp | 10 +++++----- 13 files changed, 79 insertions(+), 79 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 6cba30dd..81ddd148 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -321,7 +321,7 @@ void DivPlatformGenesis::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127); for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -329,7 +329,7 @@ void DivPlatformGenesis::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -384,7 +384,7 @@ void DivPlatformGenesis::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -437,7 +437,7 @@ void DivPlatformGenesis::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -553,7 +553,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[ch].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -634,7 +634,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } else { if (isOutput[chan[c.chan].state.alg][i]) { if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } } else { if (chan[c.chan].insChanged) { @@ -706,7 +706,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[c.chan].state.alg][i]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -847,7 +847,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[c.chan].state.alg][c.value]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -1038,7 +1038,7 @@ void DivPlatformGenesis::forceIns() { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index cc4abc88..8b4629b9 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -54,7 +54,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { rWrite(baseAddr+0x40,127); } else { if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } } if (opChan[ch].insChanged) { @@ -92,7 +92,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } break; } @@ -198,7 +198,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else if (isOutput[chan[2].state.alg][c.value]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -381,8 +381,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { rWrite(baseAddr+0x40,127); immWrite(baseAddr+0x40,127); } else if (isOutput[chan[2].state.alg][ordch]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127)); - immWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); + immWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); immWrite(baseAddr+0x40,op.tl); @@ -460,7 +460,7 @@ void DivPlatformGenesisExt::forceIns() { if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); } else if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -469,7 +469,7 @@ void DivPlatformGenesisExt::forceIns() { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index c232e68e..58893d46 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -392,7 +392,7 @@ void DivPlatformOPLL::muteChannel(int ch, bool mute) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[ch].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 46fa1977..6d2f6b82 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -87,7 +87,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) { if (parent->song.newSegaPCM) { if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].outVol=(chan[i].vol*MIN(64,chan[i].std.vol.val))>>6; chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127; chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127; if (dumpWrites) { diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 569f722b..f15de0e7 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -270,7 +270,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127); for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -278,7 +278,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -354,7 +354,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -407,7 +407,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -499,7 +499,7 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[ch].state.alg][i]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -529,7 +529,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { } else { if (isOutput[chan[c.chan].state.alg][i]) { if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } } else { if (chan[c.chan].insChanged) { @@ -594,7 +594,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[c.chan].state.alg][i]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -694,7 +694,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[c.chan].state.alg][c.value]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -985,7 +985,7 @@ void DivPlatformTX81Z::forceIns() { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 3303fbf8..cebf7087 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -338,7 +338,7 @@ void DivPlatformYM2203::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127); for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -346,7 +346,7 @@ void DivPlatformYM2203::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -396,7 +396,7 @@ void DivPlatformYM2203::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -441,7 +441,7 @@ void DivPlatformYM2203::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -553,7 +553,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { } else { if (isOutput[chan[c.chan].state.alg][i]) { if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } } else { if (chan[c.chan].insChanged) { @@ -612,7 +612,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[c.chan].state.alg][i]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -690,7 +690,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[c.chan].state.alg][c.value]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -882,7 +882,7 @@ void DivPlatformYM2203::muteChannel(int ch, bool mute) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[ch].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[ch].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -899,7 +899,7 @@ void DivPlatformYM2203::forceIns() { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 95937207..1a4f60bb 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -45,7 +45,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { rWrite(baseAddr+0x40,127); } else { if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } } if (opChan[ch].insChanged) { @@ -84,7 +84,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } break; } @@ -416,7 +416,7 @@ void DivPlatformYM2203Ext::muteChannel(int ch, bool mute) { if (isOpMuted[ch-2]) { rWrite(baseAddr+0x40,127); } else if (isOutput[ins->fm.alg][ordch]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -431,7 +431,7 @@ void DivPlatformYM2203Ext::forceIns() { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index b6f1e16f..c02cbba8 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -500,12 +500,12 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127); for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -559,7 +559,7 @@ void DivPlatformYM2608::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -609,7 +609,7 @@ void DivPlatformYM2608::tick(bool sysTick) { if (m.tl.had) { op.tl=127-m.tl.val; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -836,7 +836,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; if (isOutput[chan[c.chan].state.alg][i]) { if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } } else { if (chan[c.chan].insChanged) { @@ -916,7 +916,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; if (isOutput[chan[c.chan].state.alg][i]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -1020,7 +1020,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; if (isOutput[chan[c.chan].state.alg][c.value]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -1223,7 +1223,7 @@ void DivPlatformYM2608::forceIns() { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 441640b4..4802cc65 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -45,7 +45,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) { rWrite(baseAddr+0x40,127); } else { if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } } if (opChan[ch].insChanged) { @@ -84,7 +84,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } break; } @@ -416,7 +416,7 @@ void DivPlatformYM2608Ext::muteChannel(int ch, bool mute) { if (isOpMuted[ch-2]) { rWrite(baseAddr+0x40,127); } else if (isOutput[ins->fm.alg][ordch]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -431,7 +431,7 @@ void DivPlatformYM2608Ext::forceIns() { if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); } else if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -440,7 +440,7 @@ void DivPlatformYM2608Ext::forceIns() { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 89ccc6c0..de3112c7 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -544,12 +544,12 @@ void DivPlatformYM2610::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127); for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -603,7 +603,7 @@ void DivPlatformYM2610::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -653,7 +653,7 @@ void DivPlatformYM2610::tick(bool sysTick) { if (m.tl.had) { op.tl=127-m.tl.val; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -883,7 +883,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; if (isOutput[chan[c.chan].state.alg][i]) { if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } } else { if (chan[c.chan].insChanged) { @@ -963,7 +963,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; if (isOutput[chan[c.chan].state.alg][i]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -1067,7 +1067,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; if (isOutput[chan[c.chan].state.alg][c.value]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -1270,7 +1270,7 @@ void DivPlatformYM2610::forceIns() { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 0e466f6f..172fbca2 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -523,12 +523,12 @@ void DivPlatformYM2610B::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(127,chan[i].std.vol.val),127); for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -582,7 +582,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -632,7 +632,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { if (m.tl.had) { op.tl=127-m.tl.val; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -861,7 +861,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; if (isOutput[chan[c.chan].state.alg][i]) { if (!chan[c.chan].active || chan[c.chan].insChanged) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } } else { if (chan[c.chan].insChanged) { @@ -941,7 +941,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; if (isOutput[chan[c.chan].state.alg][i]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -1045,7 +1045,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; if (isOutput[chan[c.chan].state.alg][c.value]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } @@ -1248,7 +1248,7 @@ void DivPlatformYM2610B::forceIns() { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index cd7e494b..42a1f2e1 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -45,7 +45,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { rWrite(baseAddr+0x40,127); } else { if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } } if (opChan[ch].insChanged) { @@ -84,7 +84,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } break; } @@ -416,7 +416,7 @@ void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) { if (isOpMuted[ch-2]) { rWrite(baseAddr+0x40,127); } else if (isOutput[ins->fm.alg][ordch]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -431,7 +431,7 @@ void DivPlatformYM2610BExt::forceIns() { if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); } else if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -440,7 +440,7 @@ void DivPlatformYM2610BExt::forceIns() { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index bf6df44e..8e940381 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -45,7 +45,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { rWrite(baseAddr+0x40,127); } else { if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } } if (opChan[ch].insChanged) { @@ -84,7 +84,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } break; } @@ -416,7 +416,7 @@ void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else if (isOutput[ins->fm.alg][ordch]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -431,7 +431,7 @@ void DivPlatformYM2610Ext::forceIns() { if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); } else if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -440,7 +440,7 @@ void DivPlatformYM2610Ext::forceIns() { rWrite(baseAddr+ADDR_TL,127); } else { if (isOutput[chan[i].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } From ad1ed7fe3567e4c2a5bd9771077c1c55dce30a31 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 18:10:50 -0500 Subject: [PATCH 07/52] newVolumeScaling, part 3 --- src/engine/platform/opl.cpp | 22 +++++++++++----------- src/engine/platform/opll.cpp | 31 ++++++++----------------------- 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index c8d72829..666826ba 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -342,7 +342,7 @@ void DivPlatformOPL::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol.val))/63; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(63,chan[i].std.vol.val),63); for (int j=0; jmelodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } @@ -480,7 +480,7 @@ void DivPlatformOPL::tick(bool sysTick) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } @@ -689,7 +689,7 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { if (isOutputL[ops==4][chan[ch].state.alg][i] || ch>melodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[ch].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } @@ -820,7 +820,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[ch].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6)); } rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult); @@ -855,7 +855,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } @@ -971,7 +971,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } @@ -1120,7 +1120,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } @@ -1350,7 +1350,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } @@ -1367,7 +1367,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } @@ -1441,7 +1441,7 @@ void DivPlatformOPL::forceIns() { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) { - rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[i].outVol&0x3f))/63))|(op.ksl<<6)); + rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); } diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 58893d46..8ce21534 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -149,9 +149,9 @@ void DivPlatformOPLL::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol.val))/15; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol,MIN(15,chan[i].std.vol.val),15); if (i<9) { - rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); + rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4)); } } @@ -174,7 +174,7 @@ void DivPlatformOPLL::tick(bool sysTick) { if (chan[i].std.wave.had && chan[i].state.opllPreset!=16) { chan[i].state.opllPreset=chan[i].std.wave.val; if (i<9) { - rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); + rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4)); } } @@ -244,7 +244,7 @@ void DivPlatformOPLL::tick(bool sysTick) { op.tl=((j==1)?15:63)-m.tl.val; if (j==1) { if (i<9) { - rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); + rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4)); } } else { rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(op.tl&63)); @@ -384,21 +384,6 @@ int DivPlatformOPLL::toFreq(int freq) { void DivPlatformOPLL::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - /* - for (int j=0; j<4; j++) { - unsigned short baseAddr=chanOffs[ch]|opOffs[j]; - DivInstrumentFM::Operator& op=chan[ch].state.op[j]; - if (isMuted[ch]) { - rWrite(baseAddr+ADDR_TL,127); - } else { - if (isOutput[chan[ch].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); - } else { - rWrite(baseAddr+ADDR_TL,op.tl); - } - } - } - rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));*/ } int DivPlatformOPLL::dispatch(DivCommand c) { @@ -483,7 +468,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { } } if (c.chan<9) { - rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4)); + rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4)); } } } @@ -553,7 +538,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { break; } else if (c.chan<6 || !drums) { if (c.chan<9) { - rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4)); + rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4)); } } break; @@ -647,7 +632,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { DivInstrumentFM::Operator& car=chan[c.chan].state.op[1]; car.tl=c.value2&15; if (c.chan<9) { - rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4)); + rWrite(0x30+c.chan,((15-VOL_SCALE_LOG(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4)); } } break; @@ -862,7 +847,7 @@ void DivPlatformOPLL::forceIns() { rWrite(0x07,(car.sl<<4)|(car.rr)); } if (i<9) { - rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); + rWrite(0x30+i,((15-VOL_SCALE_LOG(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4)); } if (!(i>=6 && properDrums)) { if (chan[i].active) { From 2da92b0433f7cccca1c9c4fd4bc52f6a8017a12b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 18:27:06 -0500 Subject: [PATCH 08/52] newVolumeScaling, part 4 (final) --- TODO.md | 2 -- src/engine/platform/fds.cpp | 2 +- src/engine/platform/mmc5.cpp | 2 +- src/engine/platform/nes.cpp | 2 +- src/engine/platform/pce.cpp | 2 +- src/engine/platform/saa.cpp | 2 +- src/engine/platform/tia.cpp | 2 +- 7 files changed, 6 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index 7c638b0f..1c6e9a7b 100644 --- a/TODO.md +++ b/TODO.md @@ -3,8 +3,6 @@ - additional YM2612 features - CSM - MSM6258 pitch and clock select -- the last compat flags - - newVolumeScaling - collapse/expand pattern and song - Game Boy envelope macro/sequence - rewrite the system name detection function anyway diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index eba37183..fabeeed9 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -139,7 +139,7 @@ void DivPlatformFDS::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { // ok, why are the volumes like that? - chan[i].outVol=MIN(32,chan[i].std.vol.val)-(32-MIN(32,chan[i].vol)); + chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol,chan[i].std.vol.val,32); if (chan[i].outVol<0) chan[i].outVol=0; rWrite(0x4080,0x80|chan[i].outVol); } diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 920b9a06..9a35ac8c 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -107,7 +107,7 @@ void DivPlatformMMC5::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { // ok, why are the volumes like that? - chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); + chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); if (chan[i].outVol<0) chan[i].outVol=0; rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index dfc9108b..a688a256 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -230,7 +230,7 @@ void DivPlatformNES::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { // ok, why are the volumes like that? - chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); + chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); if (chan[i].outVol<0) chan[i].outVol=0; if (i==2) { // triangle rWrite(0x4000+i*4,(chan[i].outVol==0)?0:255); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index be104fb9..1816cd07 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -154,7 +154,7 @@ void DivPlatformPCE::tick(bool sysTick) { for (int i=0; i<6; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol.val))>>5; + chan[i].outVol=VOL_SCALE_LOG(chan[i].vol&31,MIN(31,chan[i].std.vol.val),31); if (chan[i].furnaceDac && chan[i].pcm) { // ignore for now } else { diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index f6be8509..c3ce1444 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -136,7 +136,7 @@ void DivPlatformSAA1099::tick(bool sysTick) { for (int i=0; i<6; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); + chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); if (chan[i].outVol<0) chan[i].outVol=0; if (isMuted[i]) { rWrite(i,0); diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 7a4407eb..60e064b5 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -88,7 +88,7 @@ void DivPlatformTIA::tick(bool sysTick) { for (int i=0; i<2; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); + chan[i].outVol=VOL_SCALE_LINEAR_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15); if (chan[i].outVol<0) chan[i].outVol=0; if (isMuted[i]) { rWrite(0x19+i,0); From ddcd76328de0d5289bd5a32188564bc8ae6f29e9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 1 Jun 2022 18:50:30 -0500 Subject: [PATCH 09/52] add ability to move sub-songs --- TODO.md | 1 - src/engine/engine.cpp | 38 +++++++++++++++++++++++++++++++ src/engine/engine.h | 4 ++++ src/gui/subSongs.cpp | 53 ++++++++++++++++++++++++++++--------------- 4 files changed, 77 insertions(+), 19 deletions(-) diff --git a/TODO.md b/TODO.md index 1c6e9a7b..5657f97f 100644 --- a/TODO.md +++ b/TODO.md @@ -10,7 +10,6 @@ - add another FM editor layout - if macros have release, note off should release them - add ability to move selection by dragging -- add ability to move subsongs - find and replace - add mono/poly note preview button - (maybe) add default patch selection diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index b2066205..f086d19c 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -827,6 +827,44 @@ bool DivEngine::removeSubSong(int index) { return true; } +void DivEngine::moveSubSongUp(size_t index) { + if (index<1 || index>=song.subsong.size()) return; + BUSY_BEGIN; + saveLock.lock(); + + if (index==curSubSongIndex) { + curSubSongIndex--; + } else if (index-1==curSubSongIndex) { + curSubSongIndex++; + } + + DivSubSong* prev=song.subsong[index-1]; + song.subsong[index-1]=song.subsong[index]; + song.subsong[index]=prev; + + saveLock.unlock(); + BUSY_END; +} + +void DivEngine::moveSubSongDown(size_t index) { + if (index>=song.subsong.size()-1) return; + BUSY_BEGIN; + saveLock.lock(); + + if (index==curSubSongIndex) { + curSubSongIndex++; + } else if (index+1==curSubSongIndex) { + curSubSongIndex--; + } + + DivSubSong* prev=song.subsong[index+1]; + song.subsong[index+1]=song.subsong[index]; + song.subsong[index]=prev; + + saveLock.unlock(); + BUSY_END; +} + void DivEngine::clearSubSongs() { BUSY_BEGIN; saveLock.lock(); diff --git a/src/engine/engine.h b/src/engine/engine.h index 1ad8eb2e..78a56178 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -825,6 +825,10 @@ class DivEngine { // remove subsong bool removeSubSong(int index); + // move subsong + void moveSubSongUp(size_t index); + void moveSubSongDown(size_t index); + // clear all subsong data void clearSubSongs(); diff --git a/src/gui/subSongs.cpp b/src/gui/subSongs.cpp index 2b6030cb..b13b8420 100644 --- a/src/gui/subSongs.cpp +++ b/src/gui/subSongs.cpp @@ -20,25 +20,42 @@ void FurnaceGUI::drawSubSongs() { snprintf(id,1023,"%d. %s",(int)e->getCurrentSubSong()+1,e->curSubSong->name.c_str()); } if (ImGui::BeginCombo("##SubSong",id)) { - for (size_t i=0; isong.subsong.size(); i++) { - if (e->song.subsong[i]->name.empty()) { - snprintf(id,1023,"%d. ",(int)i+1); - } else { - snprintf(id,1023,"%d. %s",(int)i+1,e->song.subsong[i]->name.c_str()); - } - if (ImGui::Selectable(id,i==e->getCurrentSubSong())) { - e->changeSongP(i); - updateScroll(0); - oldOrder=0; - oldOrder1=0; - oldRow=0; - cursor.xCoarse=0; - cursor.xFine=0; - cursor.y=0; - selStart=cursor; - selEnd=cursor; - curOrder=0; + if (ImGui::BeginTable("SubSongSelection",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); + for (size_t i=0; isong.subsong.size(); i++) { + if (e->song.subsong[i]->name.empty()) { + snprintf(id,1023,"%d. ",(int)i+1); + } else { + snprintf(id,1023,"%d. %s",(int)i+1,e->song.subsong[i]->name.c_str()); + } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::Selectable(id,i==e->getCurrentSubSong())) { + e->changeSongP(i); + updateScroll(0); + oldOrder=0; + oldOrder1=0; + oldRow=0; + cursor.xCoarse=0; + cursor.xFine=0; + cursor.y=0; + selStart=cursor; + selEnd=cursor; + curOrder=0; + } + ImGui::TableNextColumn(); + ImGui::PushID(i); + if (ImGui::SmallButton(ICON_FA_ARROW_UP "##SubUp")) { + e->moveSubSongUp(i); + } + ImGui::SameLine(); + if (ImGui::SmallButton(ICON_FA_ARROW_DOWN "##SubDown")) { + e->moveSubSongDown(i); + } + ImGui::PopID(); } + ImGui::EndTable(); } ImGui::EndCombo(); } From 35fd588aca7e4f86420058afbe8c5cfa565edda6 Mon Sep 17 00:00:00 2001 From: Mahbod-Karamoozian <78406810+MAHBOD-85@users.noreply.github.com> Date: Thu, 2 Jun 2022 08:41:50 +0430 Subject: [PATCH 10/52] Cool beeper demo --- demos/beeper_torture.fur | Bin 0 -> 3691 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/beeper_torture.fur diff --git a/demos/beeper_torture.fur b/demos/beeper_torture.fur new file mode 100644 index 0000000000000000000000000000000000000000..72886c766205ed78e391480ee51d3d2b4dcb8c51 GIT binary patch literal 3691 zcmZ`*c{tQ<_qSE1C)w#~)a0>5Lg5L?j3voVM1@9?C>kkCneojaiP9rkk{PrN%2xJm zNGMsKY@ue5Z7eg>7{)B$?{A*p`@62+`*vOLb=~(r=Q`(e&iR~kpL0h)Tk&;D{c%Du zHgaNRl|Wd@k@~DB7nEeJZgIT3KiN7%173QjAVF(~N}ZHhJl^lJXZyoPGIA;=KXzJ8 zXBt{fK9Z447PsAb??#=ftehkYCR4Yg?Aj>zt8ahVWiR$kc9Z?2ue&$+eZHKqG<{|bOeq)$tUbi(Wjm%`MErWy1_U8Sf>6?&< zvF)PYI_yryBW~csW_Cb3*`+Wb^2y$k+?k+bDW3p>CH86`)+404c}a>=pxbuq{90r2 zLhRjVVd!MGHG+Y4cmB%2OmI=rfj%XQg$%i0J?&AYS{jw{%cHRU+oSh|H2S# zevnsmd?9#-S!Vje26%8wYKn$z$3LIDRXuk19!uowgzk7cUS0uul>}`)nz?cjjq^G8 zWvK%+`>5AB()E%VhDfdU<>R*OX?*|D6-VO0XEZw+k(#A$%|illm+g~Qn?CRKBMr4` zGDEL#NHy1uq^IadjxR62)F+W2Dp>|&EWCY~qE8)WU}m|xM@nQ;Qb~B<0HY^*Gp_V6 zYJC!hs+bbp)s_O~(R1O<4(HrF2Sm{O-awSK_uKA3N)N>}cRcBFZ#c95>p^8=Ztqj0 z4jY4(u>bJo!?oZ$R>Vce6g!-)8gZKO+g>$!s_O|=q3qv*_rRRnwvtL;>RlQI2V-8=rQnzWC4 zbmG;NM$AG-b*2xt@=KsC-m9YRHQh;;K1YX^O*JEYV9rzH)2r~?*Gn~&(aTj||Dq~{ zgwbN$k7qf;W@i4d)c(a?242d(%-~fmYo&j4J&W~I&3uAcGGiaMeN-umGLUjrx1Mv6 z)ca6^0gU)=dAgd7?#&^=4p#Ux^RUMB>jxXL)4y=yx&>ae*PC`qsWjq?$ReqS_oj_{VNcwgP|&3JA4oP%D=SnxYFQJt|nv(ue0#fqUnwH1pz z?siCd{x@=Xr){}`FvUlpcL?3Ev*@9A+^-~M3VbqiNL4%}<@ zUE+P;oDNKRCCIhU%aW-5rKuwie%vUJ0DU!D8V2fXm0 z))5F!Hfol5T^f49X@pZ$cXz!p7#VyXX$;oe<9r_I&qDIQ;YQkk5Jne)>HC0wU=9j* zZ1gV+k6lNhvIVHp)I=Rfd(%bN#3hHzX{}{KacVe&i?Q(h+noeT4+}-0aH$iE@=+sQ z8=O-h%BBX(OKW5;U7UlEV457>=DaGb&7k)5w1d?^sy@uputi;>my<4IG^(MhRiDGq zPz{>M_Y zGbXY;`%+Tu4ji`dUQ|Bb3A9U`lB&l?9*w=2n~r8v*#gVc$(pY31?Wo!R(<_3q7HA z8{}j!iA^h)hMMXUS|4~$E%~oQu4|Rv6}%3w6}?WcIcS(wn*;eS>azeiv0f;_X-jyen=K*JJ=fDKVqEUpJc+(#ba z6ko;;uU^Dn0@3C`4z#k#BTyK)CGnff8U0k`{kDPDxTpUgNgyO`gMjn3y81^H{>d2A z^vLC&(xp6h+QPop;)Fi6!kLAg^!xcw%?XW+{Z79Zh8A!^Yxpg9yD_V%(;^XgbTh# z0cF6?{_+m~^APF}MauWP7_$$xtr`nwY7TT=;%62x`A?4S)994Q6d$h$DwlUjUcYkJ zef@VCfq$W|6u!6_RA?%5H<6V`u)NUp7d%JT=DwtOm&NkyG;W$CKQ+X738l^@If5CW z0-{^b3%GyTs!IA^q&?6}g78&b*TOlA%>oQW>N6_?6`bFH!2AtdS2^u?g-|(#iMQ^> z_z1M0z1arz|lR{5b}MVk*^qY@vp zscEL}CTh0a&wO$ZdJbSQyZQPo@~ZIN8}>EyLRzY0PsyJ22?LZY(L?WaMwTn{@iM3Q z22IWpfu+eEQ6~3m_-?1n1>Y`l#udui`#K#fBcHuE%>O)ppahk5jT=ZhJh=Bc+OtUu zJDa4*w-$pQwW54fW3^b)4^T!mUs#_S*wVbDh)&(CW&h~Dv6h|eT}n^0=i|o42r@$Q zGJ;59ogpe$_C61b7SwYN4-%*Q^AMeWVC2374{tE*mqa1XYCq-r?D~^P@XB)FUY@@b zhof9B{7?&L!I#aeC+=L5sQ4p1an`lHk2gM4d?!D&zK0=TkdPM^%Qg?NlXdvUwg|S} zWQ{*Gn0<{6%L90v^~xo0#4?oo!o^3zJPVY6Zb6%X+NUVU7Thv-WPh2i;}IJ~gw2Jn zN+`&&mYdK=#$kD5>{972}M9Bq*t!vMNq4`^Oxz7^+6L zlw0H{P`mkm^0!1R@HJG=*y7%wbxrCMZjy+h{m=d-91FnlXOha&FkqGgVx5@@YYPFd zY?v>*&5IYV2CuM|8Y4M#F^5JUKnH;0Gv-494a7Z^G&^>|s%;H#uW*;f)1{qYpa=uly8|tKU{L<#L}<# z!s@0mQC3yku(t;XTkT+1YSmS5) zEPy!kvln;*i%VlxH(I$8Y)w8@bj+{yXA6okDTOrIcPMtKml1Ft&;xRh5-t~EvcePT RxhVF^g)+tzWUe1U{~y?i!%+YL literal 0 HcmV?d00001 From 4262674e612270c991d5ef3bab37959b80411495 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 2 Jun 2022 01:36:28 -0500 Subject: [PATCH 11/52] GUI: remove debug text in per-chan osc --- src/gui/chanOsc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 168f469d..f9b01622 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -162,8 +162,8 @@ void FurnaceGUI::drawChanOsc() { double phase=((double)buf->rate/(FURNACE_FFT_RATE*point))*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2))); //printf("%d cphase: %f\n",ch,phase*((double)buf->rate/FURNACE_FFT_RATE)); - String cPhase=fmt::sprintf("%d cphase: %f\n",point,phase); - dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); + //String cPhase=fmt::sprintf("%d cphase: %f\n",point,phase); + //dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); needlePos=fft->needle; needlePos-=phase; From 131bef26898910efca88f3d96318bc9137d51b4e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 2 Jun 2022 02:01:48 -0500 Subject: [PATCH 12/52] SMS: fix per-channel osc when using Nuked core --- src/engine/platform/sms.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 32fbddd2..d9e2e5fc 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -69,14 +69,13 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_ if (o<-32768) o=-32768; if (o>32767) o=32767; bufL[h]=o; - /* for (int i=0; i<4; i++) { if (isMuted[i]) { oscBuf[i]->data[oscBuf[i]->needle++]=0; } else { - oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i); + oscBuf[i]->data[oscBuf[i]->needle++]=sn_nuked.vol_table[sn_nuked.volume_out[i]]; } - }*/ + } } } From e2f3a89513289f0e548a9f91b5162f4bd322327e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 2 Jun 2022 02:59:07 -0500 Subject: [PATCH 13/52] test --- src/engine/platform/pcspkr.cpp | 89 ++++++++++++++++++++++++++-------- src/engine/platform/pcspkr.h | 20 +++++++- 2 files changed, 88 insertions(+), 21 deletions(-) diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index e26ef64f..3334b70b 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -38,6 +38,57 @@ const char* regCheatSheetPCSpeaker[]={ NULL }; +void _pcSpeakerThread(void* inst) { + ((DivPlatformPCSpeaker*)inst)->pcSpeakerThread(); +} + +void DivPlatformPCSpeaker::pcSpeakerThread() { + std::unique_lock unique(realOutSelfLock); + int lastDelay=0; + RealQueueVal r(0,0); + printf("starting\n"); + while (!realOutQuit) { + realQueueLock.lock(); + if (realQueue.empty()) { + realQueueLock.unlock(); + realOutCond.wait(unique); + continue; + } else { + r=realQueue.front(); + realQueue.pop(); + } + realQueueLock.unlock(); +#ifdef __linux__ + static struct input_event ie; + int nextSleep=r.delay-lastDelay; + lastDelay=r.delay; + if (nextSleep>0) { + int totalSleep=1000000.0*((double)nextSleep/(double)rate); + //printf("sleeping %d\n",totalSleep); + usleep(totalSleep); + } + if (beepFD>=0) { + gettimeofday(&ie.time,NULL); + ie.type=EV_SND; + ie.code=SND_TONE; + if (r.val>0) { + ie.value=chipClock/r.val; + } else { + ie.value=0; + } + if (write(beepFD,&ie,sizeof(struct input_event))<0) { + perror("error while writing frequency!"); + } else { + //printf("writing freq: %d\n",r.val); + } + } else { + printf("not writing because fd is less than 0\n"); + } +#endif + } + printf("stopping\n"); +} + const char** DivPlatformPCSpeaker::getRegisterSheet() { return regCheatSheetPCSpeaker; } @@ -126,25 +177,11 @@ void DivPlatformPCSpeaker::acquire_piezo(short* bufL, short* bufR, size_t start, } } -void DivPlatformPCSpeaker::beepFreq(int freq) { -#ifdef __linux__ - static struct input_event ie; - if (beepFD>=0) { - gettimeofday(&ie.time,NULL); - ie.type=EV_SND; - ie.code=SND_TONE; - if (freq>0) { - ie.value=chipClock/freq; - } else { - ie.value=0; - } - if (write(beepFD,&ie,sizeof(struct input_event))<0) { - perror("error while writing frequency!"); - } else { - //printf("writing freq: %d\n",freq); - } - } -#endif +void DivPlatformPCSpeaker::beepFreq(int freq, int delay) { + realQueueLock.lock(); + realQueue.push(RealQueueVal(freq,delay)); + realQueueLock.unlock(); + realOutCond.notify_one(); } void DivPlatformPCSpeaker::acquire_real(short* bufL, short* bufR, size_t start, size_t len) { @@ -152,7 +189,7 @@ void DivPlatformPCSpeaker::acquire_real(short* bufL, short* bufR, size_t start, if (lastOn!=on || lastFreq!=freq) { lastOn=on; lastFreq=freq; - beepFreq((on && !isMuted[0])?freq:0); + beepFreq((on && !isMuted[0])?freq:0,start); } for (size_t i=start; i=0) close(beepFD); #endif + if (realOutThread!=NULL) { + realOutQuit=true; + realOutCond.notify_one(); + realOutThread->join(); + delete realOutThread; + } delete oscBuf; } diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index 155416bb..397f6e0e 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -22,6 +22,10 @@ #include "../dispatch.h" #include "../macroInt.h" +#include +#include +#include +#include class DivPlatformPCSpeaker: public DivDispatch { struct Channel { @@ -57,6 +61,19 @@ class DivPlatformPCSpeaker: public DivDispatch { }; Channel chan[1]; DivDispatchOscBuffer* oscBuf; + std::thread* realOutThread; + std::mutex realOutSelfLock; + std::condition_variable realOutCond; + bool realOutQuit; + struct RealQueueVal { + int delay; + unsigned short val; + RealQueueVal(int d, unsigned short v): + delay(d), + val(v) {} + }; + std::queue realQueue; + std::mutex realQueueLock; bool isMuted[1]; bool on, flip, lastOn; int pos, speakerType, beepFD; @@ -68,7 +85,7 @@ class DivPlatformPCSpeaker: public DivDispatch { friend void putDispatchChan(void*,int,int); - void beepFreq(int freq); + void beepFreq(int freq, int delay=0); void acquire_unfilt(short* bufL, short* bufR, size_t start, size_t len); void acquire_cone(short* bufL, short* bufR, size_t start, size_t len); @@ -76,6 +93,7 @@ class DivPlatformPCSpeaker: public DivDispatch { void acquire_real(short* bufL, short* bufR, size_t start, size_t len); public: + void pcSpeakerThread(); void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); From 50bdbb784a4beb6765bb7541bd37eb548482af98 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 2 Jun 2022 03:21:00 -0500 Subject: [PATCH 14/52] oh no --- src/engine/platform/pcspkr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 3334b70b..a60149b0 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -44,7 +44,9 @@ void _pcSpeakerThread(void* inst) { void DivPlatformPCSpeaker::pcSpeakerThread() { std::unique_lock unique(realOutSelfLock); +#ifdef __linux__ int lastDelay=0; +#endif RealQueueVal r(0,0); printf("starting\n"); while (!realOutQuit) { @@ -179,7 +181,7 @@ void DivPlatformPCSpeaker::acquire_piezo(short* bufL, short* bufR, size_t start, void DivPlatformPCSpeaker::beepFreq(int freq, int delay) { realQueueLock.lock(); - realQueue.push(RealQueueVal(freq,delay)); + realQueue.push(RealQueueVal(delay,freq)); realQueueLock.unlock(); realOutCond.notify_one(); } From 37539157be7063e66f3ddb333c665dc2e2bfd862 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 2 Jun 2022 23:27:28 -0500 Subject: [PATCH 15/52] PC Speaker: timing improvements --- src/engine/platform/pcspkr.cpp | 55 ++++++++++++++++++++++++---------- src/engine/platform/pcspkr.h | 7 +++-- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index a60149b0..648fad1f 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #endif #define PCSPKR_DIVIDER 4 @@ -44,10 +45,7 @@ void _pcSpeakerThread(void* inst) { void DivPlatformPCSpeaker::pcSpeakerThread() { std::unique_lock unique(realOutSelfLock); -#ifdef __linux__ - int lastDelay=0; -#endif - RealQueueVal r(0,0); + RealQueueVal r(0,0,0); printf("starting\n"); while (!realOutQuit) { realQueueLock.lock(); @@ -62,15 +60,26 @@ void DivPlatformPCSpeaker::pcSpeakerThread() { realQueueLock.unlock(); #ifdef __linux__ static struct input_event ie; - int nextSleep=r.delay-lastDelay; - lastDelay=r.delay; - if (nextSleep>0) { - int totalSleep=1000000.0*((double)nextSleep/(double)rate); - //printf("sleeping %d\n",totalSleep); - usleep(totalSleep); + static struct timespec ts, tSleep, rSleep; + if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) { + printf("could not get time!\n"); + tSleep.tv_sec=0; + tSleep.tv_nsec=0; + } else { + tSleep.tv_sec=r.tv_sec-ts.tv_sec; + tSleep.tv_nsec=r.tv_nsec-ts.tv_nsec; + if (tSleep.tv_nsec<0) { + tSleep.tv_sec--; + tSleep.tv_nsec+=1000000000; + } + } + + if (tSleep.tv_nsec>0 || tSleep.tv_sec>0) { + nanosleep(&tSleep,&rSleep); } if (beepFD>=0) { - gettimeofday(&ie.time,NULL); + ie.time.tv_sec=r.tv_sec; + ie.time.tv_usec=r.tv_nsec/1000; ie.type=EV_SND; ie.code=SND_TONE; if (r.val>0) { @@ -181,7 +190,23 @@ void DivPlatformPCSpeaker::acquire_piezo(short* bufL, short* bufR, size_t start, void DivPlatformPCSpeaker::beepFreq(int freq, int delay) { realQueueLock.lock(); - realQueue.push(RealQueueVal(delay,freq)); +#ifdef __linux__ + struct timespec ts; + double addition=1000000000.0*(double)delay/(double)rate; + if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) { + ts.tv_sec=0; + ts.tv_nsec=0; + } else { + ts.tv_nsec+=addition; + while (ts.tv_nsec>=1000000000) { + ts.tv_sec++; + ts.tv_nsec-=1000000000; + } + } + realQueue.push(RealQueueVal(ts.tv_sec,ts.tv_nsec,freq)); +#else + realQueue.push(RealQueueVal(0,0,freq)); +#endif realQueueLock.unlock(); realOutCond.notify_one(); } @@ -495,15 +520,15 @@ void DivPlatformPCSpeaker::quit() { if (speakerType==3) { beepFreq(0); } -#ifdef __linux__ - if (beepFD>=0) close(beepFD); -#endif if (realOutThread!=NULL) { realOutQuit=true; realOutCond.notify_one(); realOutThread->join(); delete realOutThread; } +#ifdef __linux__ + if (beepFD>=0) close(beepFD); +#endif delete oscBuf; } diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index 397f6e0e..117e2b6b 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -66,10 +66,11 @@ class DivPlatformPCSpeaker: public DivDispatch { std::condition_variable realOutCond; bool realOutQuit; struct RealQueueVal { - int delay; + int tv_sec, tv_nsec; unsigned short val; - RealQueueVal(int d, unsigned short v): - delay(d), + RealQueueVal(int sec, int nsec, unsigned short v): + tv_sec(sec), + tv_nsec(nsec), val(v) {} }; std::queue realQueue; From cc80bfbd817ad49713fe083643503429807e8638 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 01:18:32 -0500 Subject: [PATCH 16/52] PC speaker: add alternative output methods --- src/engine/platform/pcspkr.cpp | 127 ++++++++++++++++++++++++++++----- src/engine/platform/pcspkr.h | 4 +- src/gui/gui.h | 4 +- src/gui/settings.cpp | 17 +++++ 4 files changed, 129 insertions(+), 23 deletions(-) diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 648fad1f..a8b14462 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #endif #define PCSPKR_DIVIDER 4 @@ -59,7 +60,6 @@ void DivPlatformPCSpeaker::pcSpeakerThread() { } realQueueLock.unlock(); #ifdef __linux__ - static struct input_event ie; static struct timespec ts, tSleep, rSleep; if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) { printf("could not get time!\n"); @@ -78,19 +78,76 @@ void DivPlatformPCSpeaker::pcSpeakerThread() { nanosleep(&tSleep,&rSleep); } if (beepFD>=0) { - ie.time.tv_sec=r.tv_sec; - ie.time.tv_usec=r.tv_nsec/1000; - ie.type=EV_SND; - ie.code=SND_TONE; - if (r.val>0) { - ie.value=chipClock/r.val; - } else { - ie.value=0; - } - if (write(beepFD,&ie,sizeof(struct input_event))<0) { - perror("error while writing frequency!"); - } else { - //printf("writing freq: %d\n",r.val); + switch (realOutMethod) { + case 0: { // evdev + static struct input_event ie; + ie.time.tv_sec=r.tv_sec; + ie.time.tv_usec=r.tv_nsec/1000; + ie.type=EV_SND; + ie.code=SND_TONE; + if (r.val>0) { + ie.value=chipClock/r.val; + } else { + ie.value=0; + } + if (write(beepFD,&ie,sizeof(struct input_event))<0) { + perror("error while writing frequency!"); + } else { + //printf("writing freq: %d\n",r.val); + } + break; + } + case 1: // KIOCSOUND (on tty) + if (ioctl(beepFD,KIOCSOUND,r.val)<0) { + perror("ioctl error"); + } + break; + case 2: { // /dev/port + unsigned char bOut; + bOut=0; + if (r.val==0) { + lseek(beepFD,0x61,SEEK_SET); + read(beepFD,&bOut,1); + bOut&=(~3); + lseek(beepFD,0x61,SEEK_SET); + write(beepFD,&bOut,1); + } else { + lseek(beepFD,0x43,SEEK_SET); + bOut=0xb6; + write(beepFD,&bOut,1); + lseek(beepFD,0x42,SEEK_SET); + bOut=r.val&0xff; + write(beepFD,&bOut,1); + lseek(beepFD,0x42,SEEK_SET); + bOut=r.val>>8; + write(beepFD,&bOut,1); + lseek(beepFD,0x61,SEEK_SET); + read(beepFD,&bOut,1); + bOut|=3; + lseek(beepFD,0x61,SEEK_SET); + write(beepFD,&bOut,1); + } + break; + } + case 3: // KIOCSOUND (on stdout) + if (ioctl(beepFD,KIOCSOUND,r.val)<0) { + perror("ioctl error"); + } + break; + case 4: // outb() + if (r.val==0) { + outb(inb(0x61)&(~3),0x61); + realOutEnabled=false; + } else { + outb(0xb6,0x43); + outb(r.val&0xff,0x42); + outb(r.val>>8,0x42); + if (!realOutEnabled) { + outb(inb(0x61)|3,0x61); + realOutEnabled=true; + } + } + break; } } else { printf("not writing because fd is less than 0\n"); @@ -193,6 +250,7 @@ void DivPlatformPCSpeaker::beepFreq(int freq, int delay) { #ifdef __linux__ struct timespec ts; double addition=1000000000.0*(double)delay/(double)rate; + addition+=1500000000.0*((double)parent->getAudioDescGot().bufsize/parent->getAudioDescGot().rate); if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) { ts.tv_sec=0; ts.tv_nsec=0; @@ -449,19 +507,48 @@ void DivPlatformPCSpeaker::reset() { low=0; band=0; - if (speakerType==3) { + //if (speakerType==3) { #ifdef __linux__ if (beepFD==-1) { - beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY); + switch (realOutMethod) { + case 0: // evdev + beepFD=open("/dev/input/by-path/platform-pcspkr-event-spkr",O_WRONLY); + break; + case 1: // KIOCSOUND (on tty) + beepFD=open("/dev/tty1",O_WRONLY); + break; + case 2: // /dev/port + beepFD=open("/dev/port",O_WRONLY); + break; + case 3: // KIOCSOUND (on stdout) + beepFD=STDOUT_FILENO; + break; + case 4: // outb() + beepFD=-1; + if (ioperm(0x61,8,1)<0) { + perror("ioperm 0x61"); + break; + } + if (ioperm(0x43,8,1)<0) { + perror("ioperm 0x43"); + break; + } + if (ioperm(0x42,8,1)<0) { + perror("ioperm 0x42"); + break; + } + beepFD=STDOUT_FILENO; + break; + } if (beepFD<0) { perror("error while opening PC speaker"); } } #endif beepFreq(0); - } else { + /*} else { beepFreq(0); - } + }*/ if (realOutThread==NULL) { realOutThread=new std::thread(_pcSpeakerThread,this); @@ -506,6 +593,8 @@ int DivPlatformPCSpeaker::init(DivEngine* p, int channels, int sugRate, unsigned beepFD=-1; realOutQuit=false; realOutThread=NULL; + realOutMethod=parent->getConfInt("pcSpeakerOutMethod",0); + realOutEnabled=false; for (int i=0; i<1; i++) { isMuted[i]=false; } @@ -527,7 +616,7 @@ void DivPlatformPCSpeaker::quit() { delete realOutThread; } #ifdef __linux__ - if (beepFD>=0) close(beepFD); + if (beepFD>=0 && realOutMethod<3) close(beepFD); #endif delete oscBuf; } diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index 117e2b6b..8b0371a8 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -76,8 +76,8 @@ class DivPlatformPCSpeaker: public DivDispatch { std::queue realQueue; std::mutex realQueueLock; bool isMuted[1]; - bool on, flip, lastOn; - int pos, speakerType, beepFD; + bool on, flip, lastOn, realOutEnabled; + int pos, speakerType, beepFD, realOutMethod; float low, band; float low2, high2, band2; float low3, band3; diff --git a/src/gui/gui.h b/src/gui/gui.h index e4a98337..da2ebc55 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -871,6 +871,7 @@ class FurnaceGUI { int saaCore; int nesCore; int fdsCore; + int pcSpeakerOutMethod; String yrw801Path; String tg100Path; String mu5Path; @@ -905,10 +906,8 @@ class FurnaceGUI { int avoidRaisingPattern; int insFocusesPattern; int stepOnInsert; - // TODO flags int unifiedDataView; int sysFileDialog; - // end int roundedWindows; int roundedButtons; int roundedMenus; @@ -972,6 +971,7 @@ class FurnaceGUI { saaCore(1), nesCore(0), fdsCore(0), + pcSpeakerOutMethod(0), yrw801Path(""), tg100Path(""), mu5Path(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 8176c6be..10e93743 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -94,6 +94,14 @@ const char* nesCores[]={ "NSFplay" }; +const char* pcspkrOutMethods[]={ + "evdev SND_TONE", + "KIOCSOUND on /dev/tty1", + "/dev/port", + "KIOCSOUND on standard output", + "outb()" +}; + const char* valueInputStyles[]={ "Disabled/custom", "Two octaves (0 is C-4, F is D#5)", @@ -898,6 +906,12 @@ void FurnaceGUI::drawSettings() { ImGui::SameLine(); ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2); + ImGui::Separator(); + + ImGui::Text("PC Speaker strategy"); + ImGui::SameLine(); + ImGui::Combo("##PCSOutMethod",&settings.pcSpeakerOutMethod,pcspkrOutMethods,5); + ImGui::Separator(); ImGui::Text("Sample ROMs:"); @@ -1937,6 +1951,7 @@ void FurnaceGUI::syncSettings() { settings.saaCore=e->getConfInt("saaCore",1); settings.nesCore=e->getConfInt("nesCore",0); settings.fdsCore=e->getConfInt("fdsCore",0); + settings.pcSpeakerOutMethod=e->getConfInt("pcSpeakerOutMethod",0); settings.yrw801Path=e->getConfString("yrw801Path",""); settings.tg100Path=e->getConfString("tg100Path",""); settings.mu5Path=e->getConfString("mu5Path",""); @@ -2029,6 +2044,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.saaCore,0,1); clampSetting(settings.nesCore,0,1); clampSetting(settings.fdsCore,0,1); + clampSetting(settings.pcSpeakerOutMethod,0,4); clampSetting(settings.mainFont,0,6); clampSetting(settings.patFont,0,6); clampSetting(settings.patRowsBase,0,1); @@ -2150,6 +2166,7 @@ void FurnaceGUI::commitSettings() { e->setConf("saaCore",settings.saaCore); e->setConf("nesCore",settings.nesCore); e->setConf("fdsCore",settings.fdsCore); + e->setConf("pcSpeakerOutMethod",settings.pcSpeakerOutMethod); e->setConf("yrw801Path",settings.yrw801Path); e->setConf("tg100Path",settings.tg100Path); e->setConf("mu5Path",settings.mu5Path); From 3aef4b2ede260c0cbb2e72fda6339d87873ce092 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 01:32:56 -0500 Subject: [PATCH 17/52] update PC speaker doc --- papers/doc/7-systems/pcspkr.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/papers/doc/7-systems/pcspkr.md b/papers/doc/7-systems/pcspkr.md index 6c2e1a94..50940a5a 100644 --- a/papers/doc/7-systems/pcspkr.md +++ b/papers/doc/7-systems/pcspkr.md @@ -2,6 +2,30 @@ 40 years of one square beep - and still going! Single channel, no volume control... +# real output + +so far this is the only system in Furnace which has a real hardware output option. +to enable it, select file > configure system... > PC Speaker > Use system beeper. + +be noted that this will only work on Linux as Windows does not provide any user-space APIs to address the PC speaker directly! + +you may configure the output method by going in Settings > Emulation > PC Speaker strategy: + +- `evdev SND_TONE`: uses input events to control the beeper. + - requires write permission to `/dev/input/by-path/platform-pcspkr-event-spkr`. + - is not 100% frequency-accurate as `SND_TONE` demands frequencies, but Furnace uses raw timer periods... +- `KIOCSOUND on /dev/tty1`: sends the `KIOCSOUND` ioctl to control the beeper. + - may require running Furnace as root. +- `/dev/port`: writes to `/dev/port` to control the beeper. + - requires read/write permission to `/dev/port`. +- `KIOCSOUND on standard output`: sends the `KIOCSOUND` ioctl to control the beeper. + - requires running Furnace on a TTY. +- `outb()`: uses the low-level kernel port API to control the beeper. + - requires running Furnace as root, or granting it `CAP_SYS_RAWIO` to the Furnace executable: `sudo setcap cap_sys_rawio=ep ./furnace`. + +real hardware output only works on BIOS/UEFI (non-Mac) x86-based machines! attempting to do this under any other device **will not work**, or may even brick the device (if using `/dev/port` or `outb()`)! +oh, and of course you also need the beeper to be present in your machine. some laptops connect the beeper output to the built-in speakers (or the audio output jack), and some other don't do this at all. + # effects ha! effects... From 94dae570e04e656e10e25029c85a9309b5225e8b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 01:40:09 -0500 Subject: [PATCH 18/52] fix Ubuntu build --- src/engine/platform/pcspkr.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index a8b14462..c62c2b95 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -107,25 +107,39 @@ void DivPlatformPCSpeaker::pcSpeakerThread() { bOut=0; if (r.val==0) { lseek(beepFD,0x61,SEEK_SET); - read(beepFD,&bOut,1); + if (read(beepFD,&bOut,1)<1) { + perror("read from 0x61"); + } bOut&=(~3); lseek(beepFD,0x61,SEEK_SET); - write(beepFD,&bOut,1); + if (write(beepFD,&bOut,1)<1) { + perror("write to 0x61"); + } } else { lseek(beepFD,0x43,SEEK_SET); bOut=0xb6; - write(beepFD,&bOut,1); + if (write(beepFD,&bOut,1)<1) { + perror("write to 0x43"); + } lseek(beepFD,0x42,SEEK_SET); bOut=r.val&0xff; - write(beepFD,&bOut,1); + if (write(beepFD,&bOut,1)<1) { + perror("write to 0x42"); + } lseek(beepFD,0x42,SEEK_SET); bOut=r.val>>8; - write(beepFD,&bOut,1); + if (write(beepFD,&bOut,1)<1) { + perror("write to 0x42"); + } lseek(beepFD,0x61,SEEK_SET); - read(beepFD,&bOut,1); + if (read(beepFD,&bOut,1)<1) { + perror("read from 0x61"); + } bOut|=3; lseek(beepFD,0x61,SEEK_SET); - write(beepFD,&bOut,1); + if (write(beepFD,&bOut,1)<1) { + perror("write to 0x61"); + } } break; } From 0895789539125356c75cb36bc333b4ae61fc4bce Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 01:47:31 -0500 Subject: [PATCH 19/52] YM2612: fix DAC output not visible in per-chan osc issue #515 --- src/engine/platform/genesis.cpp | 20 ++++++++++++++++++-- src/engine/platform/sound/ymfm/ymfm_opn.h | 4 ++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 81ddd148..65486192 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -249,7 +249,15 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1]; //OPN2_Write(&fm,0,0); - oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7; + if (i==5) { + if (fm.dacen) { + oscBuf[i]->data[oscBuf[i]->needle++]=fm.dacdata<<7; + } else { + oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7; + } + } else { + oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7; + } } os[0]=(os[0]<<5); @@ -293,7 +301,15 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si //OPN2_Write(&fm,0,0); for (int i=0; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6; + if (i==5) { + if (fm_ymfm->debug_dac_enable()) { + oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7; + } else { + oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6; + } + } else { + oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6; + } } if (os[0]<-32768) os[0]=-32768; diff --git a/src/engine/platform/sound/ymfm/ymfm_opn.h b/src/engine/platform/sound/ymfm/ymfm_opn.h index 74d2b01d..34dc065d 100644 --- a/src/engine/platform/sound/ymfm/ymfm_opn.h +++ b/src/engine/platform/sound/ymfm/ymfm_opn.h @@ -778,6 +778,10 @@ public: // get the engine fm_engine* debug_engine() { return &m_fm; } + // get DAC state + uint16_t debug_dac_data() { return m_dac_data; } + uint8_t debug_dac_enable() { return m_dac_enable; } + protected: // simulate the DAC discontinuity constexpr int32_t dac_discontinuity(int32_t value) const { return (value < 0) ? (value - 2) : (value + 3); } From ead4a053481f6343f560704228acab9711b7fac2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 03:32:24 -0500 Subject: [PATCH 20/52] GUI: much more stable osc view --- src/gui/chanOsc.cpp | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index f9b01622..fd9e2e10 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -22,8 +22,9 @@ #include "imgui.h" #include "imgui_internal.h" -#define FURNACE_FFT_SIZE 8192 +#define FURNACE_FFT_SIZE 4096 #define FURNACE_FFT_RATE 80.0 +#define FURNACE_FFT_CUTOFF 0.1 void FurnaceGUI::drawChanOsc() { if (nextWindow==GUI_WINDOW_CHAN_OSC) { @@ -34,6 +35,7 @@ void FurnaceGUI::drawChanOsc() { if (!chanOscOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); if (ImGui::Begin("Oscilloscope (per-channel)",&chanOscOpen,globalWinFlags)) { + bool centerSettingReset=false; if (ImGui::BeginTable("ChanOscSettings",3)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -55,7 +57,9 @@ void FurnaceGUI::drawChanOsc() { } ImGui::TableNextColumn(); - ImGui::Checkbox("Center waveform",&chanOscWaveCorr); + if (ImGui::Checkbox("Center waveform",&chanOscWaveCorr)) { + centerSettingReset=true; + } ImGui::EndTable(); } @@ -98,6 +102,10 @@ void FurnaceGUI::drawChanOsc() { ImVec2 size=ImGui::GetContentRegionAvail(); size.y=availY/rows; + if (centerSettingReset) { + buf->readNeedle=buf->needle; + } + // check FFT status existence if (fft->plan==NULL) { logD("creating FFT plan for channel %d",ch); @@ -129,11 +137,14 @@ void FurnaceGUI::drawChanOsc() { } else { unsigned short needlePos=buf->needle; if (chanOscWaveCorr) { + /* double fftDataRate=(FURNACE_FFT_SIZE*FURNACE_FFT_RATE)/((double)buf->rate); while (buf->readNeedle!=needlePos) { fft->inBufPosFrac+=fftDataRate; while (fft->inBufPosFrac>=1.0) { - fft->inBuf[fft->inBufPos]=(double)buf->data[buf->readNeedle]/32768.0; + chanOscLP0[ch]+=FURNACE_FFT_CUTOFF*((float)buf->data[buf->readNeedle]-chanOscLP0[ch]); + chanOscLP1[ch]+=FURNACE_FFT_CUTOFF*(chanOscLP0[ch]-chanOscLP1[ch]); + fft->inBuf[fft->inBufPos]=(double)chanOscLP1[ch]/32768.0; if (++fft->inBufPos>=FURNACE_FFT_SIZE) { fftw_execute(fft->plan); fft->inBufPos=0; @@ -142,7 +153,12 @@ void FurnaceGUI::drawChanOsc() { fft->inBufPosFrac-=1.0; } buf->readNeedle++; + }*/ + + for (int i=0; iinBuf[i]=(double)buf->data[(unsigned short)(needlePos-displaySize*2+((i*displaySize*2)/FURNACE_FFT_SIZE))]/32768.0; } + fftw_execute(fft->plan); // find origin frequency int point=1; @@ -159,14 +175,24 @@ void FurnaceGUI::drawChanOsc() { // PHASE fftw_complex& candPoint=fft->outBuf[point]; - double phase=((double)buf->rate/(FURNACE_FFT_RATE*point))*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2))); + double phase=((double)(displaySize*2)/(double)point)*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2))); - //printf("%d cphase: %f\n",ch,phase*((double)buf->rate/FURNACE_FFT_RATE)); - //String cPhase=fmt::sprintf("%d cphase: %f\n",point,phase); - //dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); - - needlePos=fft->needle; + //needlePos=fft->needle; needlePos-=phase; + + /* + int alignment=0; + for (unsigned short i=0; idata[(unsigned short)(needlePos-i)])>fabs(buf->data[(unsigned short)(needlePos-alignment)])) { + alignment=i; + } + } + needlePos-=alignment; + */ + + String cPhase=fmt::sprintf("%d cphase: %f",point,phase); + dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); + needlePos-=displaySize; for (unsigned short i=0; i<512; i++) { float x=(float)i/512.0f; From 2ac96510095ef0efcd451e26e738ff1c1d185c7c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 13:44:40 -0500 Subject: [PATCH 21/52] delay collapse/expand pattern/song feature :< too much work... --- TODO.md | 1 - src/gui/gui.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 5657f97f..c5c1ca0e 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,6 @@ - additional YM2612 features - CSM - MSM6258 pitch and clock select -- collapse/expand pattern and song - Game Boy envelope macro/sequence - rewrite the system name detection function anyway - volume commands should work on Game Boy diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 5c083a5c..7817d4ff 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2197,7 +2197,7 @@ void FurnaceGUI::editOptions(bool topMenu) { if (ImGui::MenuItem("collapse",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_ROWS))) doCollapse(2); if (ImGui::MenuItem("expand",BIND_FOR(GUI_ACTION_PAT_EXPAND_ROWS))) doExpand(2); - if (topMenu) { + /*if (topMenu) { ImGui::Separator(); ImGui::MenuItem("collapse pattern",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_PAT)); ImGui::MenuItem("expand pattern",BIND_FOR(GUI_ACTION_PAT_EXPAND_PAT)); @@ -2205,7 +2205,7 @@ void FurnaceGUI::editOptions(bool topMenu) { ImGui::Separator(); ImGui::MenuItem("collapse song",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_SONG)); ImGui::MenuItem("expand song",BIND_FOR(GUI_ACTION_PAT_EXPAND_SONG)); - } + }*/ } void FurnaceGUI::toggleMobileUI(bool enable, bool force) { From 365e4666111fb4575d3c32e7bcabcfd881646041 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 14:10:28 -0500 Subject: [PATCH 22/52] YM2612: earliest completely untested CSM work --- src/engine/platform/genesis.cpp | 37 +++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 65486192..9b5c631b 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -28,6 +28,7 @@ static unsigned char konOffs[6]={ 0, 1, 2, 4, 5, 6 }; +#define CHIP_DIVIDER 64 #define CHIP_FREQBASE 9440540 const char* DivPlatformGenesis::getEffectName(unsigned char effect) { @@ -511,8 +512,26 @@ void DivPlatformGenesis::tick(bool sysTick) { } } + if (extMode && softPCM) { + if (chan[7].freqChanged) { + chan[7].freq=parent->calcFreq(chan[7].baseFreq,chan[7].pitch,true,0,chan[7].pitch2,chipClock,CHIP_DIVIDER); + int wf=0x400-chan[7].freq; + immWrite(0x24,wf&0xff); + immWrite(0x25,wf>>8); + chan[7].freqChanged=false; + } - for (int i=0; i<8; i++) { + if (chan[7].keyOn) { + immWrite(0x27,0x81); + chan[7].keyOn=false; + } + if (chan[7].keyOff) { + immWrite(0x27,0x40); + chan[7].keyOff=false; + } + } + + for (int i=0; i<7; i++) { if (i==2 && extMode) continue; if (chan[i].freqChanged) { if (parent->song.linearPitch==2) { @@ -582,6 +601,20 @@ int DivPlatformGenesis::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); + if (c.chan==7 && extMode && softPCM) { // CSM + chan[c.chan].macroInit(ins); + chan[c.chan].insChanged=false; + + if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + chan[c.chan].portaPause=false; + chan[c.chan].note=c.value; + chan[c.chan].freqChanged=true; + } + chan[c.chan].keyOn=true; + chan[c.chan].active=true; + break; + } if (c.chan>=5) { if (ins->type==DIV_INS_AMIGA) { chan[c.chan].dacMode=1; @@ -684,7 +717,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_OFF: - if (c.chan>=5) { + if (c.chan>=5 && c.chan<7) { chan[c.chan].dacSample=-1; if (dumpWrites) addWrite(0xffff0002,0); if (parent->song.brokenDACMode) { From 59ba156cdfa32b53d4fd14732be9b389fe21a872 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 15:54:49 -0500 Subject: [PATCH 23/52] YM2612: half-working CSM --- src/engine/platform/genesis.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 9b5c631b..f240997c 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -28,7 +28,7 @@ static unsigned char konOffs[6]={ 0, 1, 2, 4, 5, 6 }; -#define CHIP_DIVIDER 64 +#define CHIP_DIVIDER 72 #define CHIP_FREQBASE 9440540 const char* DivPlatformGenesis::getEffectName(unsigned char effect) { @@ -516,16 +516,19 @@ void DivPlatformGenesis::tick(bool sysTick) { if (chan[7].freqChanged) { chan[7].freq=parent->calcFreq(chan[7].baseFreq,chan[7].pitch,true,0,chan[7].pitch2,chipClock,CHIP_DIVIDER); int wf=0x400-chan[7].freq; - immWrite(0x24,wf&0xff); - immWrite(0x25,wf>>8); + printf("freq: %d\n",wf); + immWrite(0x24,wf>>2); + immWrite(0x25,wf&3); chan[7].freqChanged=false; } if (chan[7].keyOn) { + printf("CSM key on\n"); immWrite(0x27,0x81); chan[7].keyOn=false; } if (chan[7].keyOff) { + printf("CSM key off\n"); immWrite(0x27,0x40); chan[7].keyOff=false; } @@ -605,6 +608,8 @@ int DivPlatformGenesis::dispatch(DivCommand c) { chan[c.chan].macroInit(ins); chan[c.chan].insChanged=false; + printf("note on CSM\n"); + if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].portaPause=false; From b4a7f0f5b7447e5127b65f025102c2452be3a00a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 16:13:57 -0500 Subject: [PATCH 24/52] YM2612: - C S M - CSM only available with Nuked core may not work on VGM export if you compress VGM (removes timer A writes) --- TODO.md | 2 -- src/engine/platform/genesis.cpp | 22 ------------------- src/engine/platform/genesisext.cpp | 35 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/TODO.md b/TODO.md index c5c1ca0e..2dc7bb8e 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,5 @@ # to-do for 0.6pre1 -- additional YM2612 features - - CSM - MSM6258 pitch and clock select - Game Boy envelope macro/sequence - rewrite the system name detection function anyway diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index f240997c..2368fc0b 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -512,28 +512,6 @@ void DivPlatformGenesis::tick(bool sysTick) { } } - if (extMode && softPCM) { - if (chan[7].freqChanged) { - chan[7].freq=parent->calcFreq(chan[7].baseFreq,chan[7].pitch,true,0,chan[7].pitch2,chipClock,CHIP_DIVIDER); - int wf=0x400-chan[7].freq; - printf("freq: %d\n",wf); - immWrite(0x24,wf>>2); - immWrite(0x25,wf&3); - chan[7].freqChanged=false; - } - - if (chan[7].keyOn) { - printf("CSM key on\n"); - immWrite(0x27,0x81); - chan[7].keyOn=false; - } - if (chan[7].keyOff) { - printf("CSM key off\n"); - immWrite(0x27,0x40); - chan[7].keyOff=false; - } - } - for (int i=0; i<7; i++) { if (i==2 && extMode) continue; if (chan[i].freqChanged) { diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 8b4629b9..e105f560 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -23,6 +23,7 @@ #include "genesisshared.h" +#define CHIP_DIVIDER 72 #define CHIP_FREQBASE 9440540 int DivPlatformGenesisExt::dispatch(DivCommand c) { @@ -446,9 +447,43 @@ void DivPlatformGenesisExt::tick(bool sysTick) { opChan[i].keyOn=false; } } + + if (extMode && softPCM) { + if (chan[7].freqChanged) { + chan[7].freq=parent->calcFreq(chan[7].baseFreq,chan[7].pitch,true,0,chan[7].pitch2,chipClock,CHIP_DIVIDER); + if (chan[7].freq<1) chan[7].freq=1; + if (chan[7].freq>1024) chan[7].freq=1024; + int wf=0x400-chan[7].freq; + immWrite(0x24,wf>>2); + immWrite(0x25,wf&3); + chan[7].freqChanged=false; + } + + if (chan[7].keyOff || chan[7].keyOn) { + writeNoteOn=true; + for (int i=0; i<4; i++) { + writeMask|=opChan[i].active<<(4+i); + } + } + } + if (writeNoteOn) { + if (chan[7].active) { // CSM + writeMask^=0xf0; + } immWrite(0x28,writeMask); } + + if (extMode && softPCM) { + if (chan[7].keyOn) { + immWrite(0x27,0x81); + chan[7].keyOn=false; + } + if (chan[7].keyOff) { + immWrite(0x27,0x40); + chan[7].keyOff=false; + } + } } void DivPlatformGenesisExt::forceIns() { From 71b4bf5fdd531b99d70d46d016f8fed3994bc2cb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 16:21:42 -0500 Subject: [PATCH 25/52] YM2612: CSM arpeggio and slides --- src/engine/platform/genesis.cpp | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 2368fc0b..34cec6b6 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -586,8 +586,6 @@ int DivPlatformGenesis::dispatch(DivCommand c) { chan[c.chan].macroInit(ins); chan[c.chan].insChanged=false; - printf("note on CSM\n"); - if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].portaPause=false; @@ -795,6 +793,29 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } break; } + if (c.chan==7) { + int destFreq=NOTE_PERIODIC(c.value2); + bool return2=false; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } else { + chan[c.chan].baseFreq-=c.value; + if (chan[c.chan].baseFreq<=destFreq) { + chan[c.chan].baseFreq=destFreq; + return2=true; + } + } + chan[c.chan].freqChanged=true; + if (return2) { + chan[c.chan].inPorta=false; + return 2; + } + break; + } if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) { int destFreq=parent->calcBaseFreq(1,1,c.value2,false); bool return2=false; @@ -841,7 +862,9 @@ int DivPlatformGenesis::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) { + if (c.chan==7) { + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); + } else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) { chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); } else { chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); From a6b33d0955ed2975ed0842080e5635b101fc33de Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 16:32:07 -0500 Subject: [PATCH 26/52] PC speaker: don't use printf/perror --- src/engine/platform/pcspkr.cpp | 39 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index c62c2b95..9e8ba0f4 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -19,6 +19,7 @@ #include "pcspkr.h" #include "../engine.h" +#include "../../ta-log.h" #include #ifdef __linux__ @@ -47,7 +48,7 @@ void _pcSpeakerThread(void* inst) { void DivPlatformPCSpeaker::pcSpeakerThread() { std::unique_lock unique(realOutSelfLock); RealQueueVal r(0,0,0); - printf("starting\n"); + logD("starting PC speaker out thread"); while (!realOutQuit) { realQueueLock.lock(); if (realQueue.empty()) { @@ -62,7 +63,7 @@ void DivPlatformPCSpeaker::pcSpeakerThread() { #ifdef __linux__ static struct timespec ts, tSleep, rSleep; if (clock_gettime(CLOCK_MONOTONIC,&ts)<0) { - printf("could not get time!\n"); + logW("could not get time!"); tSleep.tv_sec=0; tSleep.tv_nsec=0; } else { @@ -91,15 +92,15 @@ void DivPlatformPCSpeaker::pcSpeakerThread() { ie.value=0; } if (write(beepFD,&ie,sizeof(struct input_event))<0) { - perror("error while writing frequency!"); + logW("error while writing frequency! %s",strerror(errno)); } else { - //printf("writing freq: %d\n",r.val); + //logV("writing freq: %d",r.val); } break; } case 1: // KIOCSOUND (on tty) if (ioctl(beepFD,KIOCSOUND,r.val)<0) { - perror("ioctl error"); + logW("ioctl error! %s",strerror(errno)); } break; case 2: { // /dev/port @@ -108,44 +109,44 @@ void DivPlatformPCSpeaker::pcSpeakerThread() { if (r.val==0) { lseek(beepFD,0x61,SEEK_SET); if (read(beepFD,&bOut,1)<1) { - perror("read from 0x61"); + logW("read from 0x61: %s",strerror(errno)); } bOut&=(~3); lseek(beepFD,0x61,SEEK_SET); if (write(beepFD,&bOut,1)<1) { - perror("write to 0x61"); + logW("write to 0x61: %s",strerror(errno)); } } else { lseek(beepFD,0x43,SEEK_SET); bOut=0xb6; if (write(beepFD,&bOut,1)<1) { - perror("write to 0x43"); + logW("write to 0x43: %s",strerror(errno)); } lseek(beepFD,0x42,SEEK_SET); bOut=r.val&0xff; if (write(beepFD,&bOut,1)<1) { - perror("write to 0x42"); + logW("write to 0x42: %s",strerror(errno)); } lseek(beepFD,0x42,SEEK_SET); bOut=r.val>>8; if (write(beepFD,&bOut,1)<1) { - perror("write to 0x42"); + logW("write to 0x42: %s",strerror(errno)); } lseek(beepFD,0x61,SEEK_SET); if (read(beepFD,&bOut,1)<1) { - perror("read from 0x61"); + logW("read from 0x61: %s",strerror(errno)); } bOut|=3; lseek(beepFD,0x61,SEEK_SET); if (write(beepFD,&bOut,1)<1) { - perror("write to 0x61"); + logW("write to 0x61: %s",strerror(errno)); } } break; } case 3: // KIOCSOUND (on stdout) if (ioctl(beepFD,KIOCSOUND,r.val)<0) { - perror("ioctl error"); + logW("ioctl error! %s",strerror(errno)); } break; case 4: // outb() @@ -164,11 +165,11 @@ void DivPlatformPCSpeaker::pcSpeakerThread() { break; } } else { - printf("not writing because fd is less than 0\n"); + //logV("not writing because fd is less than 0"); } #endif } - printf("stopping\n"); + logD("stopping PC speaker out thread"); } const char** DivPlatformPCSpeaker::getRegisterSheet() { @@ -540,22 +541,22 @@ void DivPlatformPCSpeaker::reset() { case 4: // outb() beepFD=-1; if (ioperm(0x61,8,1)<0) { - perror("ioperm 0x61"); + logW("ioperm 0x61: %s",strerror(errno)); break; } if (ioperm(0x43,8,1)<0) { - perror("ioperm 0x43"); + logW("ioperm 0x43: %s",strerror(errno)); break; } if (ioperm(0x42,8,1)<0) { - perror("ioperm 0x42"); + logW("ioperm 0x42: %s",strerror(errno)); break; } beepFD=STDOUT_FILENO; break; } if (beepFD<0) { - perror("error while opening PC speaker"); + logW("error while opening PC speaker! %s",strerror(errno)); } } #endif From 1f1d2c85bd0391f22fe62dd437db989c01411ae8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 18:05:07 -0500 Subject: [PATCH 27/52] GUI: add mono/poly note preview button --- TODO.md | 1 - src/engine/engine.cpp | 6 +++++- src/engine/engine.h | 5 +++++ src/gui/editControls.cpp | 31 +++++++++++++++++++++++++++++++ src/gui/gui.cpp | 5 +++++ src/gui/gui.h | 2 +- 6 files changed, 47 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 2dc7bb8e..5b55743e 100644 --- a/TODO.md +++ b/TODO.md @@ -8,5 +8,4 @@ - if macros have release, note off should release them - add ability to move selection by dragging - find and replace -- add mono/poly note preview button - (maybe) add default patch selection diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index f086d19c..07e74922 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2500,7 +2500,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { // 2. find a free channel do { - if (isViable[finalChan] && chan[finalChan].midiNote==-1 && (insInst->type==DIV_INS_OPL || getChannelType(finalChan)==finalChanType || notInViableChannel)) { + if ((!midiPoly) || (isViable[finalChan] && chan[finalChan].midiNote==-1 && (insInst->type==DIV_INS_OPL || getChannelType(finalChan)==finalChanType || notInViableChannel))) { chan[finalChan].midiNote=note; chan[finalChan].midiAge=midiAgeCounter++; pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true)); @@ -2556,6 +2556,10 @@ void DivEngine::autoNoteOffAll() { } } +void DivEngine::setAutoNotePoly(bool poly) { + midiPoly=poly; +} + void DivEngine::setOrder(unsigned char order) { BUSY_BEGIN_SOFT; curOrder=order; diff --git a/src/engine/engine.h b/src/engine/engine.h index 78a56178..3bd4fc28 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -352,6 +352,7 @@ class DivEngine { int reversePitchTable[4096]; int pitchTable[4096]; int midiBaseChan; + bool midiPoly; size_t midiAgeCounter; blip_buffer_t* samp_bb; @@ -725,6 +726,9 @@ class DivEngine { void autoNoteOn(int chan, int ins, int note, int vol=-1); void autoNoteOff(int chan, int note, int vol=-1); void autoNoteOffAll(); + + // set whether autoNoteIn is mono or poly + void setAutoNotePoly(bool poly); // go to order void setOrder(unsigned char order); @@ -956,6 +960,7 @@ class DivEngine { audioEngine(DIV_AUDIO_NULL), exportMode(DIV_EXPORT_MODE_ONE), midiBaseChan(0), + midiPoly(true), midiAgeCounter(0), samp_bb(NULL), samp_bbInLen(0), diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 671ca63b..ecd71c6e 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -150,6 +150,14 @@ void FurnaceGUI::drawEditControls() { e->stepOne(cursor.y); pendingStepUpdate=true; } + + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); + if (ImGui::Button(noteInputPoly?(ICON_FA_ALIGN_LEFT "##PolyInput"):(ICON_FA_SPACE_SHUTTLE "##PolyInput"))) { + noteInputPoly=!noteInputPoly; + e->setAutoNotePoly(noteInputPoly); + } + ImGui::PopStyleColor(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); @@ -227,6 +235,14 @@ void FurnaceGUI::drawEditControls() { unimportant(ImGui::Checkbox("Orders",&followOrders)); ImGui::SameLine(); unimportant(ImGui::Checkbox("Pattern",&followPattern)); + + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); + if (ImGui::Button(noteInputPoly?(ICON_FA_ALIGN_LEFT "##PolyInput"):(ICON_FA_SPACE_SHUTTLE "##PolyInput"))) { + noteInputPoly=!noteInputPoly; + e->setAutoNotePoly(noteInputPoly); + } + ImGui::PopStyleColor(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); @@ -302,6 +318,13 @@ void FurnaceGUI::drawEditControls() { followPattern=!followPattern; } ImGui::PopStyleColor(); + + ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); + if (ImGui::Button(noteInputPoly?(ICON_FA_ALIGN_LEFT "##PolyInput"):(ICON_FA_SPACE_SHUTTLE "##PolyInput"))) { + noteInputPoly=!noteInputPoly; + e->setAutoNotePoly(noteInputPoly); + } + ImGui::PopStyleColor(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); @@ -357,6 +380,14 @@ void FurnaceGUI::drawEditControls() { e->setRepeatPattern(!repeatPattern); } ImGui::PopStyleColor(); + + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); + if (ImGui::Button(noteInputPoly?(ICON_FA_ALIGN_LEFT "##PolyInput"):(ICON_FA_SPACE_SHUTTLE "##PolyInput"))) { + noteInputPoly=!noteInputPoly; + e->setAutoNotePoly(noteInputPoly); + } + ImGui::PopStyleColor(); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS; ImGui::End(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 7817d4ff..bc18ae3c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3923,6 +3923,7 @@ bool FurnaceGUI::init() { edit=e->getConfBool("edit",false); followOrders=e->getConfBool("followOrders",true); followPattern=e->getConfBool("followPattern",true); + noteInputPoly=e->getConfBool("noteInputPoly",true); orderEditMode=e->getConfInt("orderEditMode",0); if (orderEditMode<0) orderEditMode=0; if (orderEditMode>3) orderEditMode=3; @@ -3949,6 +3950,8 @@ bool FurnaceGUI::init() { initSystemPresets(); + e->setAutoNotePoly(noteInputPoly); + #if !(defined(__APPLE__) || defined(_WIN32)) unsigned char* furIcon=getFurnaceIcon(); SDL_Surface* icon=SDL_CreateRGBSurfaceFrom(furIcon,256,256,32,256*4,0xff,0xff00,0xff0000,0xff000000); @@ -4142,6 +4145,7 @@ bool FurnaceGUI::finish() { e->setConf("followOrders",followOrders); e->setConf("followPattern",followPattern); e->setConf("orderEditMode",orderEditMode); + e->setConf("noteInputPoly",noteInputPoly); // commit oscilloscope state e->setConf("oscZoom",oscZoom); @@ -4193,6 +4197,7 @@ FurnaceGUI::FurnaceGUI(): fullScreen(false), preserveChanPos(false), wantScrollList(false), + noteInputPoly(true), vgmExportVersion(0x171), drawHalt(10), macroPointSize(16), diff --git a/src/gui/gui.h b/src/gui/gui.h index da2ebc55..705f6827 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -815,7 +815,7 @@ class FurnaceGUI { String mmlStringW; bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; - bool displayNew, fullScreen, preserveChanPos, wantScrollList; + bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; bool willExport[32]; int vgmExportVersion; int drawHalt; From d15c276f7494aff10145c76b06a0966320c5b70d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 3 Jun 2022 18:30:40 -0500 Subject: [PATCH 28/52] GUI: add "blank new instrument" option --- TODO.md | 8 +++++--- src/gui/doAction.cpp | 3 +++ src/gui/gui.h | 2 ++ src/gui/settings.cpp | 10 +++++++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/TODO.md b/TODO.md index 5b55743e..3b354a90 100644 --- a/TODO.md +++ b/TODO.md @@ -1,11 +1,13 @@ # to-do for 0.6pre1 - MSM6258 pitch and clock select -- Game Boy envelope macro/sequence - rewrite the system name detection function anyway -- volume commands should work on Game Boy - add another FM editor layout - if macros have release, note off should release them - add ability to move selection by dragging - find and replace -- (maybe) add default patch selection + +# to-do for 0.6pre2 (as this requires new data structures) + +- Game Boy envelope macro/sequence +- volume commands should work on Game Boy \ No newline at end of file diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index a83c646d..5b3020d2 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -536,6 +536,9 @@ void FurnaceGUI::doAction(int what) { if (curIns==-1) { showError("too many instruments!"); } else { + if (settings.blankIns) { + memset(&e->song.ins[curIns]->fm,0,sizeof(DivInstrumentFM)); + } wantScrollList=true; MARK_MODIFIED; wavePreviewInit=true; diff --git a/src/gui/gui.h b/src/gui/gui.h index 705f6827..60d49263 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -951,6 +951,7 @@ class FurnaceGUI { int effectCellSpacing; int effectValCellSpacing; int doubleClickColumn; + int blankIns; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1051,6 +1052,7 @@ class FurnaceGUI { effectCellSpacing(0), effectValCellSpacing(0), doubleClickColumn(1), + blankIns(0), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 10e93743..18490ad9 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -465,6 +465,11 @@ void FurnaceGUI::drawSettings() { ImGui::SetTooltip("saves power by lowering the frame rate to 2fps when idle.\nmay cause issues under Mesa drivers!"); } + bool blankInsB=settings.blankIns; + if (ImGui::Checkbox("New instruments are blank",&blankInsB)) { + settings.blankIns=blankInsB; + } + ImGui::Text("Note preview behavior:"); if (ImGui::RadioButton("Never##npb0",settings.notePreviewBehavior==0)) { settings.notePreviewBehavior=0; @@ -2029,7 +2034,8 @@ void FurnaceGUI::syncSettings() { settings.insCellSpacing=e->getConfInt("insCellSpacing",0); settings.volCellSpacing=e->getConfInt("volCellSpacing",0); settings.effectCellSpacing=e->getConfInt("effectCellSpacing",0); - settings.doubleClickColumn=e->getConfInt("doubleClickColumn",0); + settings.doubleClickColumn=e->getConfInt("doubleClickColumn",1); + settings.blankIns=e->getConfInt("blankIns",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2114,6 +2120,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.effectCellSpacing,0,32); clampSetting(settings.effectValCellSpacing,0,32); clampSetting(settings.doubleClickColumn,0,1); + clampSetting(settings.blankIns,0,1); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { @@ -2247,6 +2254,7 @@ void FurnaceGUI::commitSettings() { e->setConf("effectCellSpacing",settings.effectCellSpacing); e->setConf("effectValCellSpacing",settings.effectValCellSpacing); e->setConf("doubleClickColumn",settings.doubleClickColumn); + e->setConf("blankIns",settings.blankIns); // colors for (int i=0; i Date: Sat, 4 Jun 2022 00:19:04 -0500 Subject: [PATCH 29/52] GUI: finish the blank ins up --- src/gui/doAction.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 5b3020d2..17b515b2 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -537,7 +537,15 @@ void FurnaceGUI::doAction(int what) { showError("too many instruments!"); } else { if (settings.blankIns) { - memset(&e->song.ins[curIns]->fm,0,sizeof(DivInstrumentFM)); + e->song.ins[curIns]->fm.fb=0; + for (int i=0; i<4; i++) { + e->song.ins[curIns]->fm.op[i]=DivInstrumentFM::Operator(); + e->song.ins[curIns]->fm.op[i].ar=31; + e->song.ins[curIns]->fm.op[i].dr=31; + e->song.ins[curIns]->fm.op[i].rr=15; + e->song.ins[curIns]->fm.op[i].tl=127; + e->song.ins[curIns]->fm.op[i].dt=3; + } } wantScrollList=true; MARK_MODIFIED; From 641648ca0f85b2792f35b10fddd8c08b8a8dfedc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 4 Jun 2022 00:50:53 -0500 Subject: [PATCH 30/52] YM2612: fix DualPCM muting issue #516 --- src/engine/platform/genesis.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 34cec6b6..aee7feb2 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -24,6 +24,8 @@ #include "genesisshared.h" +#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]) || !chan[5].dacMode)) + static unsigned char konOffs[6]={ 0, 1, 2, 4, 5, 6 }; @@ -372,7 +374,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (chan[i].std.panL.had) { chan[i].pan=chan[i].std.panL.val&3; - rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } if (chan[i].std.pitch.had) { @@ -414,11 +416,11 @@ void DivPlatformGenesis::tick(bool sysTick) { } if (chan[i].std.fms.had) { chan[i].state.fms=chan[i].std.fms.val; - rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } if (chan[i].std.ams.had) { chan[i].state.ams=chan[i].std.ams.val; - rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; @@ -575,7 +577,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) { } } } - rWrite(chanOffs[ch]+ADDR_LRAF,(isMuted[ch]?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); + rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); } int DivPlatformGenesis::dispatch(DivCommand c) { @@ -683,7 +685,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } if (chan[c.chan].insChanged) { rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); - rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); + rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); } chan[c.chan].insChanged=false; @@ -761,7 +763,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } else { chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1); } - rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); + rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4)); break; } case DIV_CMD_PITCH: { @@ -1106,7 +1108,7 @@ void DivPlatformGenesis::forceIns() { rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); - rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); if (chan[i].active) { chan[i].keyOn=true; chan[i].freqChanged=true; From a550c4cb305ecbbef52e1173174d2063ee9eea9e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 4 Jun 2022 01:00:29 -0500 Subject: [PATCH 31/52] YM2612: more DualPCM muting fixes --- src/engine/platform/genesis.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index aee7feb2..0d18ddf4 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -24,7 +24,7 @@ #include "genesisshared.h" -#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]) || !chan[5].dacMode)) +#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) static unsigned char konOffs[6]={ 0, 1, 2, 4, 5, 6 @@ -563,19 +563,23 @@ void DivPlatformGenesis::tick(bool sysTick) { void DivPlatformGenesis::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (ch>5) return; - for (int j=0; j<4; j++) { - unsigned short baseAddr=chanOffs[ch]|opOffs[j]; - DivInstrumentFM::Operator& op=chan[ch].state.op[j]; - if (isMuted[ch]) { - rWrite(baseAddr+ADDR_TL,127); - } else { - if (isOutput[chan[ch].state.alg][j]) { - rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); + if (ch>6) return; + if (ch<6) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[ch]|opOffs[j]; + DivInstrumentFM::Operator& op=chan[ch].state.op[j]; + if (isMuted[ch]) { + rWrite(baseAddr+ADDR_TL,127); } else { - rWrite(baseAddr+ADDR_TL,op.tl); + if (isOutput[chan[ch].state.alg][j]) { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); + } else { + rWrite(baseAddr+ADDR_TL,op.tl); + } } } + } else { + ch--; } rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); } From 91621fe0f59211fab31f73d6566fedb2a0c78123 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 4 Jun 2022 01:03:58 -0500 Subject: [PATCH 32/52] YM2612: DualPCM per-channel osc fixes #516 --- src/engine/platform/genesis.cpp | 21 +++++++++++++++++---- src/engine/platform/genesis.h | 4 +++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 0d18ddf4..683fa3b2 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -147,10 +147,13 @@ void DivPlatformGenesis::processDAC() { DivSample* s=parent->getSample(chan[i].dacSample); if (!isMuted[i] && s->samples>0) { if (parent->song.noOPN2Vol) { - sample+=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]; + chan[i].dacOutput=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]; } else { - sample+=(s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7; + chan[i].dacOutput=(s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7; } + sample+=chan[i].dacOutput; + } else { + chan[i].dacOutput=0; } chan[i].dacPeriod+=chan[i].dacRate; if (chan[i].dacPeriod>=(chipClock/576)) { @@ -254,7 +257,12 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s //OPN2_Write(&fm,0,0); if (i==5) { if (fm.dacen) { - oscBuf[i]->data[oscBuf[i]->needle++]=fm.dacdata<<7; + if (softPCM) { + oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7; + oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7; + } else { + oscBuf[i]->data[oscBuf[i]->needle++]=fm.dacdata<<7; + } } else { oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7; } @@ -306,7 +314,12 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si for (int i=0; i<6; i++) { if (i==5) { if (fm_ymfm->debug_dac_enable()) { - oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7; + if (softPCM) { + oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7; + oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7; + } else { + oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7; + } } else { oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6; } diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index b4862427..26c6c58b 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -51,6 +51,7 @@ class DivPlatformGenesis: public DivDispatch { bool dacReady; bool dacDirection; unsigned char sampleBank; + signed char dacOutput; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; @@ -85,7 +86,8 @@ class DivPlatformGenesis: public DivDispatch { dacDelay(0), dacReady(true), dacDirection(false), - sampleBank(0) {} + sampleBank(0), + dacOutput(0) {} }; Channel chan[10]; DivDispatchOscBuffer* oscBuf[10]; From 0e05d4e599e171b7b4b895eda372b30fbf4739c9 Mon Sep 17 00:00:00 2001 From: The789Guy <43525032+The789Guy@users.noreply.github.com> Date: Sat, 4 Jun 2022 16:09:51 -0500 Subject: [PATCH 33/52] Update n163.md Fixed horrible grammar --- papers/doc/7-systems/n163.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index 76b750cb..6057fa3c 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,12 +1,12 @@ # Namco C163 -This is Namco's one of NES mapper, with up to 8 wavetable channels. It has also 128 byte of internal RAM, both channel register and wavetables are stored here. Wavetables are variable size and freely allocable anywhere in RAM, it means it can be uses part of or continuously pre-loaded waveform and/or its sequences in RAM. But waveform RAM area becomes smaller as much as activating more channels; Channel register consumes 8 byte for each channels. You must avoid conflict with channel register area and waveform for avoid channel playback broken. +This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 128 byte of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consumes 8 bytes for each channel. You must avoid conflict with channel register area and waveform for avoid broken channel playback. -It has can be outputs only single channel at clock; so it's sound quality is more crunchy as much as activating more channels. +It outputs only a single channel at clock; so its sound quality gets more crunchy as more channels are activated. -Furnace supports both load waveform into RAM and waveform playback simultaneously, and channel limit is dynamically changeable with effect commands. -You must load waveform to RAM first for playback or do something, its load behavior is changeable to auto-update when every waveform changes or manual update. -Both waveform playback and load command is works independently per each channel columns, (Global) commands are don't care about the channel columns for work commands and its load behavior is independent with per-channel column load commands. +Furnace supports loading waveforms into RAM and waveform playback simultaneously, and channel limit is dynamically changeable with effect commands. +You must load waveform to RAM first for playback, as its load behavior auto-updates when every waveform changes. +Both waveform playback and load command works independently per each channel columns, (Global) commands don't care about the channel columns for work commands and its load behavior is independent with per-channel column load commands. # effects From fc34474d6e3b575b1a6555bf14ddfdca2a573986 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 4 Jun 2022 16:52:42 -0500 Subject: [PATCH 34/52] MSM6258: prepare for rate changing --- src/engine/platform/msm6258.cpp | 10 ++++++++++ src/engine/platform/msm6258.h | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index 826d221b..9bcb7966 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -46,6 +46,16 @@ void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t case 0: msm->ctrl_w(w.val); break; + case 2: + msmPan=w.val; + break; + case 8: + msmClock=w.val; + break; + case 12: + msmDivider=4-(w.val&3); + if (msmDivider<2) msmDivider=2; + break; } writes.pop(); } diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index ea0482f3..7ef22681 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -87,9 +87,9 @@ class DivPlatformMSM6258: public DivDispatch { unsigned char* adpcmMem; size_t adpcmMemLen; - unsigned char sampleBank; + unsigned char sampleBank, msmPan, msmDivider; - int delay, updateOsc, sample, samplePos; + int delay, updateOsc, sample, samplePos, msmClock; bool extMode; From 05c2fb357ffcebb1d50d03c5e9a828feb130fc69 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 4 Jun 2022 17:51:59 -0500 Subject: [PATCH 35/52] MSM6258: clock/rate selection --- TODO.md | 1 - src/engine/platform/msm6258.cpp | 124 +++++++++++++++++++++----------- src/engine/platform/msm6258.h | 6 +- src/engine/sysDef.cpp | 16 ++++- src/gui/sysConf.cpp | 16 +++++ 5 files changed, 119 insertions(+), 44 deletions(-) diff --git a/TODO.md b/TODO.md index 3b354a90..7de18ef0 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # to-do for 0.6pre1 -- MSM6258 pitch and clock select - rewrite the system name detection function anyway - add another FM editor layout - if macros have release, note off should release them diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index 9bcb7966..a144959e 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -31,51 +31,68 @@ const char** DivPlatformMSM6258::getRegisterSheet() { } const char* DivPlatformMSM6258::getEffectName(unsigned char effect) { + switch (effect) { + case 0x20: + return "20xx: Set frequency divider (0-2)"; + break; + case 0x21: + return "21xx: Select clock rate (0: full; 1: half)"; + break; + } return NULL; } void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t len) { + short* outs[2]={ + &msmOut, + NULL + }; for (size_t h=start; hctrl_w(w.val); - break; - case 2: - msmPan=w.val; - break; - case 8: - msmClock=w.val; - break; - case 12: - msmDivider=4-(w.val&3); - if (msmDivider<2) msmDivider=2; - break; - } - writes.pop(); - } - - if (sample>=0 && samplesong.sampleLen) { - DivSample* s=parent->getSample(sample); - unsigned char nextData=(s->dataVOX[samplePos]>>4)|(s->dataVOX[samplePos]<<4); - if (msm->data_w(nextData)) { - samplePos++; - if (samplePos>=(int)s->lengthVOX) { - sample=-1; - samplePos=0; - msm->ctrl_w(1); + if (--msmClockCount<0) { + if (--msmDividerCount<=0) { + if (!writes.empty()) { + QueuedWrite& w=writes.front(); + switch (w.addr) { + case 0: + msm->ctrl_w(w.val); + break; + case 2: + msmPan=w.val; + break; + case 8: + msmClock=w.val; + break; + case 12: + msmDivider=4-(w.val&3); + if (msmDivider<2) msmDivider=2; + break; + } + writes.pop(); } + + if (sample>=0 && samplesong.sampleLen) { + DivSample* s=parent->getSample(sample); + unsigned char nextData=(s->dataVOX[samplePos]>>4)|(s->dataVOX[samplePos]<<4); + if (msm->data_w(nextData)) { + samplePos++; + if (samplePos>=(int)s->lengthVOX) { + sample=-1; + samplePos=0; + msm->ctrl_w(1); + } + } + } + + msm->sound_stream_update(outs,1); + msmDividerCount=msmDivider; } + msmClockCount=msmClock; } - msm->sound_stream_update(outs,1); if (isMuted[0]) { bufL[h]=0; + } else { + bufL[h]=msmOut; } /*if (++updateOsc>=22) { @@ -186,6 +203,14 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { sampleBank=parent->song.sample.size()/12; } break; + case DIV_CMD_SAMPLE_FREQ: + rateSel=c.value&3; + rWrite(12,rateSel); + break; + case DIV_CMD_SAMPLE_MODE: + clockSel=c.value&1; + rWrite(8,clockSel); + break; case DIV_CMD_LEGATO: { break; } @@ -215,6 +240,8 @@ void DivPlatformMSM6258::forceIns() { for (int i=0; i<1; i++) { chan[i].insChanged=true; } + rWrite(12,rateSel); + rWrite(8,clockSel); } void* DivPlatformMSM6258::getChanState(int ch) { @@ -244,6 +271,14 @@ void DivPlatformMSM6258::poke(std::vector& wlist) { void DivPlatformMSM6258::reset() { while (!writes.empty()) writes.pop(); msm->device_reset(); + msmClock=chipClock; + msmDivider=2; + msmDividerCount=0; + msmClock=0; + msmClockCount=0; + msmPan=3; + rateSel=0; + clockSel=0; if (dumpWrites) { addWrite(0xffffffff,0); } @@ -317,15 +352,24 @@ void DivPlatformMSM6258::renderSamples() { } void DivPlatformMSM6258::setFlags(unsigned int flags) { - if (flags&1) { - chipClock=4096000; - } else { - chipClock=4000000; + switch (flags) { + case 3: + chipClock=8192000; + break; + case 2: + chipClock=8000000; + break; + case 1: + chipClock=4096000; + break; + default: + chipClock=4000000; + break; } - rate=chipClock/256; + rate=chipClock/128; for (int i=0; i<1; i++) { isMuted[i]=false; - oscBuf[i]->rate=rate/256; + oscBuf[i]->rate=rate; } } diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index 7ef22681..b870eb1c 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -87,9 +87,11 @@ class DivPlatformMSM6258: public DivDispatch { unsigned char* adpcmMem; size_t adpcmMemLen; - unsigned char sampleBank, msmPan, msmDivider; + unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel; + signed char msmDividerCount, msmClockCount; + short msmOut; - int delay, updateOsc, sample, samplePos, msmClock; + int delay, updateOsc, sample, samplePos; bool extMode; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index be2c7236..e5a4888b 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1975,7 +1975,21 @@ void DivEngine::registerSystems() { {"Sample"}, {"PCM"}, {DIV_CH_PCM}, - {DIV_INS_AMIGA} + {DIV_INS_AMIGA}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x20: // select rate + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); + break; + case 0x21: // select clock + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_YMZ280B]=new DivSysDef( diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 91d542bd..89d35b0b 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -415,6 +415,22 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool } break; } + case DIV_SYSTEM_MSM6258: { + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("4MHz",flags==0)) { + copyOfFlags=0; + } + if (ImGui::RadioButton("4.096MHz",flags==1)) { + copyOfFlags=1; + } + if (ImGui::RadioButton("8MHz (X68000)",flags==2)) { + copyOfFlags=2; + } + if (ImGui::RadioButton("8.192MHz",flags==3)) { + copyOfFlags=3; + } + break; + } case DIV_SYSTEM_MSM6295: { ImGui::Text("Clock rate:"); if (ImGui::RadioButton("1MHz",flags==0)) { From 05ffc98ed1bc53674b51cc19f8f38da925a4c45f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 4 Jun 2022 17:58:19 -0500 Subject: [PATCH 36/52] MSM6258: the final bits --- src/engine/platform/msm6258.cpp | 31 ++++++++++++++++++++----------- src/engine/platform/msm6258.h | 1 + src/engine/platform/msm6295.cpp | 1 - 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index a144959e..44986fc7 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -91,17 +91,13 @@ void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t if (isMuted[0]) { bufL[h]=0; + bufR[h]=0; + oscBuf[0]->data[oscBuf[0]->needle++]=0; } else { - bufL[h]=msmOut; + bufL[h]=(msmPan&2)?msmOut:0; + bufR[h]=(msmPan&1)?msmOut:0; + oscBuf[0]->data[oscBuf[0]->needle++]=msmPan?msmOut:0; } - - /*if (++updateOsc>=22) { - updateOsc=0; - // TODO: per-channel osc - for (int i=0; i<1; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=msm->m_voice[i].m_muted?0:(msm->m_voice[i].m_out<<6); - } - }*/ } } @@ -211,6 +207,15 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { clockSel=c.value&1; rWrite(8,clockSel); break; + case DIV_CMD_PANNING: { + if (c.value==0 && c.value2==0) { + chan[c.chan].pan=3; + } else { + chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1); + } + rWrite(2,chan[c.chan].pan); + break; + } case DIV_CMD_LEGATO: { break; } @@ -242,6 +247,7 @@ void DivPlatformMSM6258::forceIns() { } rWrite(12,rateSel); rWrite(8,clockSel); + rWrite(2,chan[0].pan); } void* DivPlatformMSM6258::getChanState(int ch) { @@ -277,7 +283,7 @@ void DivPlatformMSM6258::reset() { msmClock=0; msmClockCount=0; msmPan=3; - rateSel=0; + rateSel=2; clockSel=0; if (dumpWrites) { addWrite(0xffffffff,0); @@ -298,6 +304,10 @@ void DivPlatformMSM6258::reset() { delay=0; } +bool DivPlatformMSM6258::isStereo() { + return true; +} + bool DivPlatformMSM6258::keyOffAffectsArp(int ch) { return false; } @@ -368,7 +378,6 @@ void DivPlatformMSM6258::setFlags(unsigned int flags) { } rate=chipClock/128; for (int i=0; i<1; i++) { - isMuted[i]=false; oscBuf[i]->rate=rate; } } diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index b870eb1c..f60f8bc9 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -111,6 +111,7 @@ class DivPlatformMSM6258: public DivDispatch { void forceIns(); void tick(bool sysTick=true); void muteChannel(int ch, bool mute); + bool isStereo(); bool keyOffAffectsArp(int ch); void notifyInsChange(int ins); void notifyInsDeletion(void* ins); diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 541dded6..32de1e09 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -385,7 +385,6 @@ void DivPlatformMSM6295::setFlags(unsigned int flags) { } rate=chipClock/3; for (int i=0; i<4; i++) { - isMuted[i]=false; oscBuf[i]->rate=rate/22; } } From 270a1fa98950bf0e32087e8e6a8f4a13e96fb422 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Jun 2022 00:37:51 -0500 Subject: [PATCH 37/52] update to-do list --- TODO.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 7de18ef0..0823e2d0 100644 --- a/TODO.md +++ b/TODO.md @@ -5,8 +5,9 @@ - if macros have release, note off should release them - add ability to move selection by dragging - find and replace +- implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change) # to-do for 0.6pre2 (as this requires new data structures) - Game Boy envelope macro/sequence -- volume commands should work on Game Boy \ No newline at end of file +- volume commands should work on Game Boy From d1b33d14104bcaf367e8038804112645933b0531 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Jun 2022 00:42:14 -0500 Subject: [PATCH 38/52] GUI: get rid of these stupid icons --- src/gui/editControls.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index ecd71c6e..912bd1c0 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -153,7 +153,7 @@ void FurnaceGUI::drawEditControls() { ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); - if (ImGui::Button(noteInputPoly?(ICON_FA_ALIGN_LEFT "##PolyInput"):(ICON_FA_SPACE_SHUTTLE "##PolyInput"))) { + if (ImGui::Button(noteInputPoly?("Poly##PolyInput"):("Mono##PolyInput"))) { noteInputPoly=!noteInputPoly; e->setAutoNotePoly(noteInputPoly); } @@ -238,7 +238,7 @@ void FurnaceGUI::drawEditControls() { ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); - if (ImGui::Button(noteInputPoly?(ICON_FA_ALIGN_LEFT "##PolyInput"):(ICON_FA_SPACE_SHUTTLE "##PolyInput"))) { + if (ImGui::Button(noteInputPoly?("Poly##PolyInput"):("Mono##PolyInput"))) { noteInputPoly=!noteInputPoly; e->setAutoNotePoly(noteInputPoly); } @@ -320,7 +320,7 @@ void FurnaceGUI::drawEditControls() { ImGui::PopStyleColor(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); - if (ImGui::Button(noteInputPoly?(ICON_FA_ALIGN_LEFT "##PolyInput"):(ICON_FA_SPACE_SHUTTLE "##PolyInput"))) { + if (ImGui::Button(noteInputPoly?("Poly##PolyInput"):("Mono##PolyInput"))) { noteInputPoly=!noteInputPoly; e->setAutoNotePoly(noteInputPoly); } @@ -383,7 +383,7 @@ void FurnaceGUI::drawEditControls() { ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button,TOGGLE_COLOR(noteInputPoly)); - if (ImGui::Button(noteInputPoly?(ICON_FA_ALIGN_LEFT "##PolyInput"):(ICON_FA_SPACE_SHUTTLE "##PolyInput"))) { + if (ImGui::Button(noteInputPoly?("Poly##PolyInput"):("Mono##PolyInput"))) { noteInputPoly=!noteInputPoly; e->setAutoNotePoly(noteInputPoly); } From 6095255fce6619b154decb067a040f72b5df7838 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Jun 2022 14:42:03 -0500 Subject: [PATCH 39/52] update to-do list again --- TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.md b/TODO.md index 0823e2d0..6c500f49 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,6 @@ # to-do for 0.6pre1 +- instrument loading selector - rewrite the system name detection function anyway - add another FM editor layout - if macros have release, note off should release them From af0103d76e9f43b92c2ac34e237802b97f794d8a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Jun 2022 16:24:12 -0500 Subject: [PATCH 40/52] macroInt: add hasRelease variable --- src/engine/macroInt.cpp | 8 +++++++- src/engine/macroInt.h | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 6f853bff..06f04682 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -101,6 +101,7 @@ void DivMacroInt::init(DivInstrument* which) { macroListLen=0; subTick=1; + hasRelease=false; released=false; if (ins==NULL) return; @@ -236,7 +237,12 @@ void DivMacroInt::init(DivInstrument* which) { } for (size_t i=0; iprepare(*macroSource[i],e); + if (macroSource[i]!=NULL) { + macroList[i]->prepare(*macroSource[i],e); + hasRelease=(macroSource[i]->rel>=0 && macroSource[i]->rellen); + } else { + hasRelease=false; + } } } diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index d82cb2b2..83962555 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -96,6 +96,9 @@ class DivMacroInt { ksr() {} } op[4]; + // state + bool hasRelease; + /** * trigger macro release. */ @@ -149,7 +152,8 @@ class DivMacroInt { ex5(), ex6(), ex7(), - ex8() { + ex8(), + hasRelease(false) { memset(macroList,0,128*sizeof(void*)); memset(macroSource,0,128*sizeof(void*)); } From 2932a7281dc005bed50bf2df492d77eb9ceb5c14 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Jun 2022 18:17:00 -0500 Subject: [PATCH 41/52] implement getChanMacroInt() on supported systems --- TODO.md | 1 - src/engine/platform/amiga.cpp | 4 ++++ src/engine/platform/amiga.h | 1 + src/engine/platform/arcade.cpp | 4 ++++ src/engine/platform/arcade.h | 1 + src/engine/platform/ay.cpp | 4 ++++ src/engine/platform/ay.h | 1 + src/engine/platform/ay8930.cpp | 4 ++++ src/engine/platform/ay8930.h | 1 + src/engine/platform/bubsyswsg.cpp | 4 ++++ src/engine/platform/bubsyswsg.h | 1 + src/engine/platform/c64.cpp | 4 ++++ src/engine/platform/c64.h | 1 + src/engine/platform/fds.cpp | 4 ++++ src/engine/platform/fds.h | 1 + src/engine/platform/gb.cpp | 4 ++++ src/engine/platform/gb.h | 1 + src/engine/platform/genesis.cpp | 4 ++++ src/engine/platform/genesis.h | 1 + src/engine/platform/genesisext.cpp | 6 ++++++ src/engine/platform/genesisext.h | 1 + src/engine/platform/lynx.cpp | 4 ++++ src/engine/platform/lynx.h | 1 + src/engine/platform/mmc5.cpp | 4 ++++ src/engine/platform/mmc5.h | 1 + src/engine/platform/msm6258.cpp | 4 ++++ src/engine/platform/msm6258.h | 1 + src/engine/platform/msm6295.cpp | 4 ++++ src/engine/platform/msm6295.h | 1 + src/engine/platform/n163.cpp | 4 ++++ src/engine/platform/n163.h | 1 + src/engine/platform/namcowsg.cpp | 4 ++++ src/engine/platform/namcowsg.h | 1 + src/engine/platform/nes.cpp | 4 ++++ src/engine/platform/nes.h | 1 + src/engine/platform/opl.cpp | 4 ++++ src/engine/platform/opl.h | 1 + src/engine/platform/opll.cpp | 4 ++++ src/engine/platform/opll.h | 1 + src/engine/platform/pce.cpp | 4 ++++ src/engine/platform/pce.h | 1 + src/engine/platform/pcspkr.cpp | 4 ++++ src/engine/platform/pcspkr.h | 1 + src/engine/platform/pet.cpp | 4 ++++ src/engine/platform/pet.h | 1 + src/engine/platform/qsound.cpp | 4 ++++ src/engine/platform/qsound.h | 1 + src/engine/platform/rf5c68.cpp | 4 ++++ src/engine/platform/rf5c68.h | 1 + src/engine/platform/saa.cpp | 4 ++++ src/engine/platform/saa.h | 1 + src/engine/platform/scc.cpp | 4 ++++ src/engine/platform/scc.h | 1 + src/engine/platform/segapcm.cpp | 4 ++++ src/engine/platform/segapcm.h | 1 + src/engine/platform/sms.cpp | 4 ++++ src/engine/platform/sms.h | 1 + src/engine/platform/su.cpp | 4 ++++ src/engine/platform/su.h | 1 + src/engine/platform/swan.cpp | 4 ++++ src/engine/platform/swan.h | 1 + src/engine/platform/tia.cpp | 4 ++++ src/engine/platform/tia.h | 1 + src/engine/platform/tx81z.cpp | 4 ++++ src/engine/platform/tx81z.h | 1 + src/engine/platform/vera.cpp | 4 ++++ src/engine/platform/vera.h | 1 + src/engine/platform/vic20.cpp | 4 ++++ src/engine/platform/vic20.h | 1 + src/engine/platform/vrc6.cpp | 4 ++++ src/engine/platform/vrc6.h | 1 + src/engine/platform/x1_010.cpp | 4 ++++ src/engine/platform/x1_010.h | 1 + src/engine/platform/ym2203.cpp | 5 +++++ src/engine/platform/ym2203.h | 1 + src/engine/platform/ym2203ext.cpp | 6 ++++++ src/engine/platform/ym2203ext.h | 1 + src/engine/platform/ym2608.cpp | 5 +++++ src/engine/platform/ym2608.h | 1 + src/engine/platform/ym2608ext.cpp | 7 +++++++ src/engine/platform/ym2608ext.h | 1 + src/engine/platform/ym2610.cpp | 5 +++++ src/engine/platform/ym2610.h | 1 + src/engine/platform/ym2610b.cpp | 5 +++++ src/engine/platform/ym2610b.h | 1 + src/engine/platform/ym2610bext.cpp | 7 +++++++ src/engine/platform/ym2610bext.h | 1 + src/engine/platform/ym2610ext.cpp | 8 +++++++- src/engine/platform/ym2610ext.h | 1 + src/engine/platform/ymz280b.cpp | 4 ++++ src/engine/platform/ymz280b.h | 1 + src/engine/platform/zxbeeper.cpp | 4 ++++ src/engine/platform/zxbeeper.h | 1 + src/engine/playback.cpp | 16 +++++++++++++++- 94 files changed, 262 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 6c500f49..19918981 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,6 @@ - instrument loading selector - rewrite the system name detection function anyway - add another FM editor layout -- if macros have release, note off should release them - add ability to move selection by dragging - find and replace - implement Defle slide bug when using E1xy/E2xy and repeating origin note (requires format change) diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 03961b0a..8037feaf 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -427,6 +427,10 @@ bool DivPlatformAmiga::keyOffAffectsArp(int ch) { return true; } +DivMacroInt* DivPlatformAmiga::getChanMacroInt(int ch) { + return &chan[ch].std; +} + void DivPlatformAmiga::notifyInsChange(int ins) { for (int i=0; i<4; i++) { if (chan[i].ins==ins) { diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index 539f7830..e7372e63 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -99,6 +99,7 @@ class DivPlatformAmiga: public DivDispatch { void muteChannel(int ch, bool mute); bool isStereo(); bool keyOffAffectsArp(int ch); + DivMacroInt* getChanMacroInt(int ch); void setFlags(unsigned int flags); void notifyInsChange(int ins); void notifyWaveChange(int wave); diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 121183d1..87c402e0 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -913,6 +913,10 @@ void* DivPlatformArcade::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformArcade::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformArcade::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 6f68eeda..e73c0618 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -116,6 +116,7 @@ class DivPlatformArcade: public DivDispatch { void forceIns(); void tick(bool sysTick=true); void muteChannel(int ch, bool mute); + DivMacroInt* getChanMacroInt(int ch); void notifyInsChange(int ins); void setFlags(unsigned int flags); bool isStereo(); diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index a3d325ad..0bca2766 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -509,6 +509,10 @@ void* DivPlatformAY8910::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformAY8910::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformAY8910::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index f93d34bd..0b05eb44 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -102,6 +102,7 @@ class DivPlatformAY8910: public DivDispatch { void setFlags(unsigned int flags); bool isStereo(); bool keyOffAffectsArp(int ch); + DivMacroInt* getChanMacroInt(int ch); bool getDCOffRequired(); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index fb498b2c..a92f185c 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -539,6 +539,10 @@ void* DivPlatformAY8930::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformAY8930::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformAY8930::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 67420f48..10ac7736 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -98,6 +98,7 @@ class DivPlatformAY8930: public DivDispatch { void setFlags(unsigned int flags); bool isStereo(); bool keyOffAffectsArp(int ch); + DivMacroInt* getChanMacroInt(int ch); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 5793277d..85d50e66 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -281,6 +281,10 @@ void* DivPlatformBubSysWSG::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformBubSysWSG::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformBubSysWSG::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/bubsyswsg.h b/src/engine/platform/bubsyswsg.h index cb30d85c..e288493c 100644 --- a/src/engine/platform/bubsyswsg.h +++ b/src/engine/platform/bubsyswsg.h @@ -78,6 +78,7 @@ class DivPlatformBubSysWSG: public DivDispatch { void muteChannel(int ch, bool mute); bool isStereo(); bool keyOffAffectsArp(int ch); + DivMacroInt* getChanMacroInt(int ch); void setFlags(unsigned int flags); void notifyWaveChange(int wave); void notifyInsDeletion(void* ins); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 72692887..3372c820 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -491,6 +491,10 @@ void* DivPlatformC64::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformC64::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformC64::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index 495da461..d9dc0804 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -97,6 +97,7 @@ class DivPlatformC64: public DivDispatch { void setFlags(unsigned int flags); void notifyInsChange(int ins); bool getDCOffRequired(); + DivMacroInt* getChanMacroInt(int ch); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index fabeeed9..ea4b83e9 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -436,6 +436,10 @@ void* DivPlatformFDS::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformFDS::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformFDS::getOscBuffer(int ch) { return oscBuf; } diff --git a/src/engine/platform/fds.h b/src/engine/platform/fds.h index c563a47f..f655a777 100644 --- a/src/engine/platform/fds.h +++ b/src/engine/platform/fds.h @@ -88,6 +88,7 @@ class DivPlatformFDS: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 40bf6a83..999d31b9 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -433,6 +433,10 @@ void* DivPlatformGB::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformGB::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformGB::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index cce1ffb6..fe2f6e51 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -72,6 +72,7 @@ class DivPlatformGB: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 683fa3b2..46e28ccb 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -1145,6 +1145,10 @@ void* DivPlatformGenesis::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformGenesis::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformGenesis::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 26c6c58b..14257409 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -130,6 +130,7 @@ class DivPlatformGenesis: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index e105f560..f7fdaf44 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -543,6 +543,12 @@ void* DivPlatformGenesisExt::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformGenesisExt::getChanMacroInt(int ch) { + if (ch>=6) return &chan[ch-3].std; + if (ch>=2) return NULL; // currently not implemented + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) { if (ch>=6) return oscBuf[ch-3]; if (ch<3) return oscBuf[ch]; diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index f6c1e3dc..07e0d5cc 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -55,6 +55,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { public: int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index dce2fb04..4fd30db9 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -424,6 +424,10 @@ void* DivPlatformLynx::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformLynx::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformLynx::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index 4f221d03..849c3182 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -88,6 +88,7 @@ class DivPlatformLynx: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 9a35ac8c..2b97f46f 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -353,6 +353,10 @@ void* DivPlatformMMC5::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformMMC5::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformMMC5::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index 2213b995..f09092d5 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -74,6 +74,7 @@ class DivPlatformMMC5: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index 44986fc7..db1848cf 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -254,6 +254,10 @@ void* DivPlatformMSM6258::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformMSM6258::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformMSM6258::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index f60f8bc9..e3b50a17 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -104,6 +104,7 @@ class DivPlatformMSM6258: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 32de1e09..aeb29dd3 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -227,6 +227,10 @@ void* DivPlatformMSM6295::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformMSM6295::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformMSM6295::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/msm6295.h b/src/engine/platform/msm6295.h index 2930a169..3e019208 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -112,6 +112,7 @@ class DivPlatformMSM6295: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 58a41693..50f9d836 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -625,6 +625,10 @@ void* DivPlatformN163::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformN163::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformN163::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index 6ecb1e0c..5e44d3dd 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -95,6 +95,7 @@ class DivPlatformN163: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index 88cba360..1e8ff46d 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -467,6 +467,10 @@ void* DivPlatformNamcoWSG::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformNamcoWSG::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformNamcoWSG::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/namcowsg.h b/src/engine/platform/namcowsg.h index 652181e0..4ab81bdc 100644 --- a/src/engine/platform/namcowsg.h +++ b/src/engine/platform/namcowsg.h @@ -79,6 +79,7 @@ class DivPlatformNamcoWSG: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index a688a256..50e548ea 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -610,6 +610,10 @@ void* DivPlatformNES::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformNES::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformNES::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index a03efc7a..35c51df7 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -89,6 +89,7 @@ class DivPlatformNES: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 666826ba..fbf91448 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1483,6 +1483,10 @@ void* DivPlatformOPL::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) { if (ch>=18) return NULL; return oscBuf[ch]; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 61ea4648..a051074a 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -125,6 +125,7 @@ class DivPlatformOPL: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 8ce21534..6d77ca1f 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -896,6 +896,10 @@ void* DivPlatformOPLL::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformOPLL::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformOPLL::getOscBuffer(int ch) { if (ch>=9) return NULL; return oscBuf[ch]; diff --git a/src/engine/platform/opll.h b/src/engine/platform/opll.h index d2d20826..dad660de 100644 --- a/src/engine/platform/opll.h +++ b/src/engine/platform/opll.h @@ -102,6 +102,7 @@ class DivPlatformOPLL: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 1816cd07..b8c580e5 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -477,6 +477,10 @@ void* DivPlatformPCE::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformPCE::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformPCE::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 58fa6600..870b5218 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -89,6 +89,7 @@ class DivPlatformPCE: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 9e8ba0f4..d977690f 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -485,6 +485,10 @@ void* DivPlatformPCSpeaker::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformPCSpeaker::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformPCSpeaker::getOscBuffer(int ch) { return oscBuf; } diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index 8b0371a8..cb6f070f 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -98,6 +98,7 @@ class DivPlatformPCSpeaker: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index 233027e2..0decd909 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -249,6 +249,10 @@ void* DivPlatformPET::getChanState(int ch) { return &chan; } +DivMacroInt* DivPlatformPET::getChanMacroInt(int ch) { + return &chan.std; +} + DivDispatchOscBuffer* DivPlatformPET::getOscBuffer(int ch) { return oscBuf; } diff --git a/src/engine/platform/pet.h b/src/engine/platform/pet.h index 1e5e49ce..a5037045 100644 --- a/src/engine/platform/pet.h +++ b/src/engine/platform/pet.h @@ -66,6 +66,7 @@ class DivPlatformPET: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 4bd9c322..8af565df 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -530,6 +530,10 @@ void* DivPlatformQSound::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformQSound::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformQSound::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index d12e952e..28576013 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -78,6 +78,7 @@ class DivPlatformQSound: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index ae5138c1..2106a5a7 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -300,6 +300,10 @@ void* DivPlatformRF5C68::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformRF5C68::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformRF5C68::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/rf5c68.h b/src/engine/platform/rf5c68.h index 79d7d58b..6946b490 100644 --- a/src/engine/platform/rf5c68.h +++ b/src/engine/platform/rf5c68.h @@ -75,6 +75,7 @@ class DivPlatformRF5C68: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index c3ce1444..dc9a13e8 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -401,6 +401,10 @@ void* DivPlatformSAA1099::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformSAA1099::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformSAA1099::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 70edaa24..fafb36d7 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -91,6 +91,7 @@ class DivPlatformSAA1099: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/scc.cpp b/src/engine/platform/scc.cpp index 2ab6f1aa..011f63bc 100644 --- a/src/engine/platform/scc.cpp +++ b/src/engine/platform/scc.cpp @@ -310,6 +310,10 @@ void* DivPlatformSCC::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformSCC::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformSCC::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/scc.h b/src/engine/platform/scc.h index df6ef84e..31f6abc5 100644 --- a/src/engine/platform/scc.h +++ b/src/engine/platform/scc.h @@ -70,6 +70,7 @@ class DivPlatformSCC: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 6d2f6b82..19b8eb82 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -400,6 +400,10 @@ void* DivPlatformSegaPCM::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformSegaPCM::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformSegaPCM::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index f5fa4ecb..6edc8530 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -101,6 +101,7 @@ class DivPlatformSegaPCM: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index d9e2e5fc..a32305a3 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -352,6 +352,10 @@ void* DivPlatformSMS::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformSMS::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformSMS::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 3c97a9a5..9054eb7a 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -76,6 +76,7 @@ class DivPlatformSMS: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 1f85cd33..692fbbee 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -484,6 +484,10 @@ void* DivPlatformSoundUnit::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformSoundUnit::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformSoundUnit::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 857ae725..1d39854f 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -112,6 +112,7 @@ class DivPlatformSoundUnit: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index c941a8ff..73dc7928 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -464,6 +464,10 @@ void* DivPlatformSwan::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformSwan::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index 32f400e5..aafb17ac 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -79,6 +79,7 @@ class DivPlatformSwan: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 60e064b5..da347244 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -293,6 +293,10 @@ void* DivPlatformTIA::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformTIA::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformTIA::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index 76064d06..cabe9153 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -52,6 +52,7 @@ class DivPlatformTIA: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index f15de0e7..30db376d 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -1027,6 +1027,10 @@ void* DivPlatformTX81Z::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformTX81Z::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformTX81Z::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index 60ea66ae..ece914d1 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -103,6 +103,7 @@ class DivPlatformTX81Z: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 353a9f60..62e1ea68 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -397,6 +397,10 @@ void* DivPlatformVERA::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformVERA::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformVERA::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index 734db020..612b4354 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -66,6 +66,7 @@ class DivPlatformVERA: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index 708db4ab..a766ba44 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -278,6 +278,10 @@ void* DivPlatformVIC20::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformVIC20::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformVIC20::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/vic20.h b/src/engine/platform/vic20.h index f05ad8f2..d23f27be 100644 --- a/src/engine/platform/vic20.h +++ b/src/engine/platform/vic20.h @@ -68,6 +68,7 @@ class DivPlatformVIC20: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 16ba73b0..08c6d053 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -438,6 +438,10 @@ void* DivPlatformVRC6::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformVRC6::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformVRC6::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index dd6863d5..450e09b9 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -85,6 +85,7 @@ class DivPlatformVRC6: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 1cbfd68e..dc5c7ed2 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -842,6 +842,10 @@ void* DivPlatformX1_010::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformX1_010::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 939280ef..7a85b633 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -129,6 +129,7 @@ class DivPlatformX1_010: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index cebf7087..5507b11c 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -933,6 +933,11 @@ void* DivPlatformYM2203::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformYM2203::getChanMacroInt(int ch) { + if (ch>=3) return ay->getChanMacroInt(ch-3); + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYM2203::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index ab527eea..f91b7e0f 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -108,6 +108,7 @@ class DivPlatformYM2203: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 1a4f60bb..3a38bde2 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -471,6 +471,12 @@ void* DivPlatformYM2203Ext::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformYM2203Ext::getChanMacroInt(int ch) { + if (ch>=6) return ay->getChanMacroInt(ch-6); + if (ch>=2) return NULL; // currently not implemented + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYM2203Ext::getOscBuffer(int ch) { if (ch>=6) return oscBuf[ch-3]; if (ch<3) return oscBuf[ch]; diff --git a/src/engine/platform/ym2203ext.h b/src/engine/platform/ym2203ext.h index 5025881c..1a398d1a 100644 --- a/src/engine/platform/ym2203ext.h +++ b/src/engine/platform/ym2203ext.h @@ -40,6 +40,7 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 { public: int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index c02cbba8..773f9ed5 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1257,6 +1257,11 @@ void* DivPlatformYM2608::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformYM2608::getChanMacroInt(int ch) { + if (ch>=6 && ch<9) return ay->getChanMacroInt(ch-6); + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYM2608::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 5c673629..f65c4cd6 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -121,6 +121,7 @@ class DivPlatformYM2608: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 4802cc65..f7d3217f 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -484,6 +484,13 @@ void* DivPlatformYM2608Ext::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformYM2608Ext::getChanMacroInt(int ch) { + if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9); + if (ch>=6) return &chan[ch-3].std; + if (ch>=2) return NULL; // currently not implemented + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYM2608Ext::getOscBuffer(int ch) { if (ch>=6) return oscBuf[ch-3]; if (ch<3) return oscBuf[ch]; diff --git a/src/engine/platform/ym2608ext.h b/src/engine/platform/ym2608ext.h index a0966dfe..bc3d4f99 100644 --- a/src/engine/platform/ym2608ext.h +++ b/src/engine/platform/ym2608ext.h @@ -40,6 +40,7 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 { public: int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index de3112c7..ccb9bfda 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -1304,6 +1304,11 @@ void* DivPlatformYM2610::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformYM2610::getChanMacroInt(int ch) { + if (ch>=4 && ch<7) return ay->getChanMacroInt(ch-4); + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYM2610::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 92f4ca07..1d807213 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -134,6 +134,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 172fbca2..c327645b 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -1282,6 +1282,11 @@ void* DivPlatformYM2610B::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformYM2610B::getChanMacroInt(int ch) { + if (ch>=6 && ch<9) return ay->getChanMacroInt(ch-6); + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYM2610B::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 3a034028..fe2126dd 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -107,6 +107,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 42a1f2e1..f208bf18 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -484,6 +484,13 @@ void* DivPlatformYM2610BExt::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) { + if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9); + if (ch>=6) return &chan[ch-3].std; + if (ch>=2) return NULL; // currently not implemented + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) { if (ch>=6) return oscBuf[ch-3]; if (ch<3) return oscBuf[ch]; diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index c17fd8d8..732678fe 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -40,6 +40,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { public: int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 8e940381..af9a3da0 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -478,13 +478,19 @@ void DivPlatformYM2610Ext::forceIns() { } } - void* DivPlatformYM2610Ext::getChanState(int ch) { if (ch>=5) return &chan[ch-3]; if (ch>=1) return &opChan[ch-1]; return &chan[ch]; } +DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) { + if (ch>=7 && ch<10) return ay->getChanMacroInt(ch-7); + if (ch>=5) return &chan[ch-3].std; + if (ch>=1) return NULL; // currently not implemented + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) { if (ch>=5) return oscBuf[ch-3]; if (ch<2) return oscBuf[ch]; diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index 492eb5de..119d6356 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -40,6 +40,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { public: int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 1c4997c2..ed50ccd4 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -333,6 +333,10 @@ void* DivPlatformYMZ280B::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformYMZ280B::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformYMZ280B::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/ymz280b.h b/src/engine/platform/ymz280b.h index 4957d899..fbba3319 100644 --- a/src/engine/platform/ymz280b.h +++ b/src/engine/platform/ymz280b.h @@ -74,6 +74,7 @@ class DivPlatformYMZ280B: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index ff14d161..34265f8a 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -251,6 +251,10 @@ void* DivPlatformZXBeeper::getChanState(int ch) { return &chan[ch]; } +DivMacroInt* DivPlatformZXBeeper::getChanMacroInt(int ch) { + return &chan[ch].std; +} + DivDispatchOscBuffer* DivPlatformZXBeeper::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/zxbeeper.h b/src/engine/platform/zxbeeper.h index 9520ea71..a9b400cb 100644 --- a/src/engine/platform/zxbeeper.h +++ b/src/engine/platform/zxbeeper.h @@ -77,6 +77,7 @@ class DivPlatformZXBeeper: public DivDispatch { void acquire(short* bufL, short* bufR, size_t start, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); + DivMacroInt* getChanMacroInt(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 73e12238..0297a56b 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "macroInt.h" #include #define _USE_MATH_DEFINES #include "dispatch.h" @@ -901,13 +902,26 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { while (!pendingNotes.empty()) { DivNoteEvent& note=pendingNotes.front(); + if (note.channel<0 || note.channel>=chans) { + pendingNotes.pop(); + continue; + } if (note.on) { dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins,1)); dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,note.channel,note.note)); keyHit[note.channel]=true; chan[note.channel].noteOnInhibit=true; } else { - dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel)); + DivMacroInt* macroInt=disCont[dispatchOfChan[note.channel]].dispatch->getChanMacroInt(dispatchChanOfChan[note.channel]); + if (macroInt!=NULL) { + if (macroInt->hasRelease) { + dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF_ENV,note.channel)); + } else { + dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel)); + } + } else { + dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel)); + } } pendingNotes.pop(); } From eb71c27ad9256cb9c2974eb5c7f368df5dc29283 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Jun 2022 19:04:41 -0500 Subject: [PATCH 42/52] GUI: preliminary "select instrument" dialog --- src/gui/gui.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++------- src/gui/gui.h | 4 ++- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index bc18ae3c..68196c35 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3330,8 +3330,16 @@ bool FurnaceGUI::loop() { if (!e->getWarnings().empty()) { showWarning(e->getWarnings(),GUI_WARN_GENERIC); } - for (DivInstrument* i: instruments) { - e->addInstrumentPtr(i); + if (instruments.size()>1) { // ask which instruments to load + for (DivInstrument* i: instruments) { + pendingIns.push_back(std::make_pair(i,false)); + } + displayPendingIns=true; + pendingInsSingle=false; + } else { // load the only instrument + for (DivInstrument* i: instruments) { + e->addInstrumentPtr(i); + } } } else { showError("cannot load instrument! ("+e->getLastError()+")"); @@ -3344,13 +3352,21 @@ bool FurnaceGUI::loop() { if (!e->getWarnings().empty()) { showWarning(e->getWarnings(),GUI_WARN_GENERIC); } - if (curIns>=0 && curIns<(int)e->song.ins.size()) { - *e->song.ins[curIns]=*instruments[0]; - } else { - showError("...but you haven't selected an instrument!"); - } - for (DivInstrument* i: instruments) { - delete i; + if (instruments.size()>1) { // ask which instrument + for (DivInstrument* i: instruments) { + pendingIns.push_back(std::make_pair(i,false)); + } + displayPendingIns=true; + pendingInsSingle=true; + } else { // replace with the only instrument + if (curIns>=0 && curIns<(int)e->song.ins.size()) { + *e->song.ins[curIns]=*instruments[0]; + } else { + showError("...but you haven't selected an instrument!"); + } + for (DivInstrument* i: instruments) { + delete i; + } } } else { showError("cannot load instrument! ("+e->getLastError()+")"); @@ -3442,6 +3458,11 @@ bool FurnaceGUI::loop() { ImGui::OpenPopup("Error"); } + if (displayPendingIns) { + displayPendingIns=false; + ImGui::OpenPopup("Select Instrument"); + } + if (displayExporting) { displayExporting=false; ImGui::OpenPopup("Rendering..."); @@ -3792,6 +3813,36 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } + // TODO: + // - multiple selection + // - replace instrument + if (ImGui::BeginPopupModal("Select Instrument",NULL,ImGuiWindowFlags_AlwaysAutoResize)) { + bool quitPlease=false; + if (pendingInsSingle) { + ImGui::Text("this is an instrument bank! select which one to use:"); + } else { + ImGui::Text("this is an instrument bank! select which ones to load:"); + } + for (size_t i=0; iname); + if (ImGui::Selectable(id.c_str())) { + pendingIns[i].second=true; + e->addInstrumentPtr(pendingIns[i].first); + quitPlease=true; + } + } + if (quitPlease) { + ImGui::CloseCurrentPopup(); + for (std::pair i: pendingIns) { + if (!i.second) { + delete i.first; + } + } + pendingIns.clear(); + } + ImGui::EndPopup(); + } + layoutTimeEnd=SDL_GetPerformanceCounter(); // backup trigger @@ -4198,6 +4249,8 @@ FurnaceGUI::FurnaceGUI(): preserveChanPos(false), wantScrollList(false), noteInputPoly(true), + displayPendingIns(false), + pendingInsSingle(false), vgmExportVersion(0x171), drawHalt(10), macroPointSize(16), diff --git a/src/gui/gui.h b/src/gui/gui.h index 60d49263..5bda0246 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "fileDialog.h" @@ -816,6 +817,7 @@ class FurnaceGUI { bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; + bool displayPendingIns, pendingInsSingle; bool willExport[32]; int vgmExportVersion; int drawHalt; @@ -1130,7 +1132,7 @@ class FurnaceGUI { std::vector activeNotes; std::vector cmdStream; std::vector particles; - std::vector pendingIns; + std::vector> pendingIns; std::vector sysCategories; From b8c785230e304bfa8c1e4c98c60cc21141fc742a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Jun 2022 23:34:58 -0500 Subject: [PATCH 43/52] GUI: implement instrument bank ins picker --- TODO.md | 1 - src/gui/gui.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index 19918981..5bd4e892 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # to-do for 0.6pre1 -- instrument loading selector - rewrite the system name detection function anyway - add another FM editor layout - add ability to move selection by dragging diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 68196c35..154000ef 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3823,19 +3823,57 @@ bool FurnaceGUI::loop() { } else { ImGui::Text("this is an instrument bank! select which ones to load:"); } - for (size_t i=0; iname); - if (ImGui::Selectable(id.c_str())) { - pendingIns[i].second=true; - e->addInstrumentPtr(pendingIns[i].first); + bool anySelected=false; + float sizeY=ImGui::GetFrameHeightWithSpacing()*pendingIns.size(); + if (sizeY>(scrH-180.0)*dpiScale) { + sizeY=(scrH-180.0)*dpiScale; + if (sizeY<60.0*dpiScale) sizeY=60.0*dpiScale; + } + if (ImGui::BeginTable("PendingInsList",1,ImGuiTableFlags_ScrollY,ImVec2(0.0f,sizeY))) { + for (size_t i=0; iname); + if (pendingInsSingle) { + if (ImGui::Selectable(id.c_str())) { + pendingIns[i].second=true; + quitPlease=true; + } + } else { + ImGui::Checkbox(id.c_str(),&pendingIns[i].second); + } + if (pendingIns[i].second) anySelected=true; + } + ImGui::EndTable(); + } + if (!pendingInsSingle) { + ImGui::BeginDisabled(!anySelected); + if (ImGui::Button("OK")) { quitPlease=true; } + ImGui::EndDisabled(); + ImGui::SameLine(); + } + if (ImGui::Button("Cancel")) { + for (std::pair& i: pendingIns) { + i.second=false; + } + quitPlease=true; } if (quitPlease) { ImGui::CloseCurrentPopup(); - for (std::pair i: pendingIns) { - if (!i.second) { + for (std::pair& i: pendingIns) { + if (!i.second || pendingInsSingle) { + if (i.second) { + if (curIns>=0 && curIns<(int)e->song.ins.size()) { + *e->song.ins[curIns]=*i.first; + } else { + showError("...but you haven't selected an instrument!"); + } + } delete i.first; + } else { + e->addInstrumentPtr(i.first); } } pendingIns.clear(); From 177836293383c5296d33982745f65d8400099cd0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 5 Jun 2022 23:44:52 -0500 Subject: [PATCH 44/52] GUI: add all/none buttons to ins selector --- src/gui/gui.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 154000ef..4ecc719d 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3822,6 +3822,18 @@ bool FurnaceGUI::loop() { ImGui::Text("this is an instrument bank! select which one to use:"); } else { ImGui::Text("this is an instrument bank! select which ones to load:"); + ImGui::SameLine(); + if (ImGui::Button("All")) { + for (std::pair& i: pendingIns) { + i.second=true; + } + } + ImGui::SameLine(); + if (ImGui::Button("None")) { + for (std::pair& i: pendingIns) { + i.second=false; + } + } } bool anySelected=false; float sizeY=ImGui::GetFrameHeightWithSpacing()*pendingIns.size(); From 5a0a9db9c3a830aa172d43de8e74bc800622a030 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Jun 2022 01:05:06 -0500 Subject: [PATCH 45/52] highlight cur row instead of next one on playback --- src/engine/engine.cpp | 15 +++++++++++++-- src/engine/engine.h | 4 +++- src/engine/playback.cpp | 3 +++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 07e74922..093f6d94 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -780,6 +780,8 @@ void DivEngine::changeSong(size_t songIndex) { curSubSongIndex=songIndex; curOrder=0; curRow=0; + prevOrder=0; + prevRow=0; } void DivEngine::swapChannelsP(int src, int dest) { @@ -871,6 +873,7 @@ void DivEngine::clearSubSongs() { song.clearSongData(); changeSong(0); curOrder=0; + prevOrder=0; saveLock.unlock(); BUSY_END; } @@ -1113,6 +1116,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { int goal=curOrder; curOrder=0; curRow=0; + prevOrder=0; + prevRow=0; stepPlay=0; int prevDrift; prevDrift=clockDrift; @@ -1162,6 +1167,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { if (!preserveDrift) { ticks=1; subticks=1; + prevOrder=curOrder; + prevRow=curRow; } skipping=false; cmdStream.clear(); @@ -1288,6 +1295,7 @@ unsigned int DivEngine::convertPanLinearToSplit(int val, unsigned char bits, int void DivEngine::play() { BUSY_BEGIN_SOFT; + curOrder=prevOrder; sPreview.sample=-1; sPreview.wave=-1; sPreview.pos=0; @@ -1583,11 +1591,11 @@ int DivEngine::getMaxVolumeChan(int ch) { } unsigned char DivEngine::getOrder() { - return curOrder; + return prevOrder; } int DivEngine::getRow() { - return curRow; + return prevRow; } size_t DivEngine::getCurrentSubSong() { @@ -2564,6 +2572,7 @@ void DivEngine::setOrder(unsigned char order) { BUSY_BEGIN_SOFT; curOrder=order; if (order>=curSubSong->ordersLen) curOrder=0; + prevOrder=curOrder; if (playing && !freelance) { playSub(false); } @@ -2757,6 +2766,8 @@ void DivEngine::quitDispatch() { tempoAccum=0; curRow=0; curOrder=0; + prevRow=0; + prevOrder=0; nextSpeed=3; changeOrd=-1; changePos=0; diff --git a/src/engine/engine.h b/src/engine/engine.h index 3bd4fc28..ec48e187 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -303,7 +303,7 @@ class DivEngine { bool systemsRegistered; bool hasLoadedSomething; int softLockCount; - int subticks, ticks, curRow, curOrder, remainingLoops, nextSpeed; + int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, nextSpeed; size_t curSubSongIndex; double divider; int cycles; @@ -935,6 +935,8 @@ class DivEngine { ticks(0), curRow(0), curOrder(0), + prevRow(0), + prevOrder(0), remainingLoops(-1), nextSpeed(3), curSubSongIndex(0), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 0297a56b..f7c1646f 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -798,6 +798,9 @@ void DivEngine::nextRow() { printf("| %.2x:%s | \x1b[1;33m%3d%s\x1b[m\n",curOrder,pb1,curRow,pb3); } + prevOrder=curOrder; + prevRow=curRow; + for (int i=0; i Date: Mon, 6 Jun 2022 01:08:15 -0500 Subject: [PATCH 46/52] GUI: better selection cursor tracking during playb --- src/gui/pattern.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index ee06a1b8..fa00243c 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -320,7 +320,13 @@ void FurnaceGUI::drawPattern() { bool inhibitMenu=false; float scrollX=0; - if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) cursor.y=oldRow+((pendingStepUpdate)?1:0); + if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) { + cursor.y=oldRow+((pendingStepUpdate)?1:0); + if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) { + selStart=cursor; + selEnd=cursor; + } + } demandX=0; sel1=selStart; sel2=selEnd; From 8b33525a36d3320009eebe6958aae41a30a46d96 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Jun 2022 01:23:35 -0500 Subject: [PATCH 47/52] GUI: always go to beginning of song when loading --- src/gui/gui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4ecc719d..309d605b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1657,6 +1657,8 @@ int FurnaceGUI::load(String path) { curNibble=false; orderNibble=false; orderCursor=-1; + curOrder=0; + oldRow=0; samplePos=0; updateSampleTex=true; selStart=SelectionPoint(); @@ -1666,6 +1668,7 @@ int FurnaceGUI::load(String path) { undoHist.clear(); redoHist.clear(); updateWindowTitle(); + updateScroll(0); if (!e->getWarnings().empty()) { showWarning(e->getWarnings(),GUI_WARN_GENERIC); } From fe4aec70dbbbb49746f4f8b61f9222fd5d6b821e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Jun 2022 01:28:46 -0500 Subject: [PATCH 48/52] GUI: add play from beginning hotkey --- src/gui/doAction.cpp | 6 ++++++ src/gui/gui.h | 1 + src/gui/guiConst.cpp | 1 + src/gui/settings.cpp | 1 + 4 files changed, 9 insertions(+) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 17b515b2..83fdad38 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -87,6 +87,12 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_STOP: stop(); break; + case GUI_ACTION_PLAY_START: + e->setOrder(0); + if (!e->isPlaying()) { + play(); + } + break; case GUI_ACTION_PLAY_REPEAT: play(); e->setRepeatPattern(true); diff --git a/src/gui/gui.h b/src/gui/gui.h index 5bda0246..86301b0a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -309,6 +309,7 @@ enum FurnaceGUIActions { GUI_ACTION_PLAY_TOGGLE, GUI_ACTION_PLAY, GUI_ACTION_STOP, + GUI_ACTION_PLAY_START, GUI_ACTION_PLAY_REPEAT, GUI_ACTION_PLAY_CURSOR, GUI_ACTION_STEP_ONE, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 722c5652..a9541222 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -447,6 +447,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("PLAY_TOGGLE", "Play/Stop (toggle)", SDLK_RETURN), D("PLAY", "Play", 0), D("STOP", "Stop", 0), + D("PLAY_START", "Play (from beginning)", SDLK_F5), D("PLAY_REPEAT", "Play (repeat pattern)", 0), D("PLAY_CURSOR", "Play from cursor", FURKMOD_SHIFT|SDLK_RETURN), D("STEP_ONE", "Step row", FURKMOD_CMD|SDLK_RETURN), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 18490ad9..eef892ab 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1545,6 +1545,7 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_PLAY_TOGGLE); UI_KEYBIND_CONFIG(GUI_ACTION_PLAY); UI_KEYBIND_CONFIG(GUI_ACTION_STOP); + UI_KEYBIND_CONFIG(GUI_ACTION_PLAY_START); UI_KEYBIND_CONFIG(GUI_ACTION_PLAY_REPEAT); UI_KEYBIND_CONFIG(GUI_ACTION_PLAY_CURSOR); UI_KEYBIND_CONFIG(GUI_ACTION_STEP_ONE); From d1ba9e2c3ef417483f1fb02311005191b55b85d5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Jun 2022 01:50:35 -0500 Subject: [PATCH 49/52] audio: JACK verbose error messages --- src/audio/jack.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++--- src/audio/jack.h | 2 ++ 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/audio/jack.cpp b/src/audio/jack.cpp index 33a464d5..6e7b7bf1 100644 --- a/src/audio/jack.cpp +++ b/src/audio/jack.cpp @@ -19,6 +19,7 @@ #include #include "jack.h" +#include "../ta-log.h" int taJACKonSampleRate(jack_nframes_t rate, void* inst) { TAAudioJACK* in=(TAAudioJACK*)inst; @@ -74,7 +75,10 @@ bool TAAudioJACK::quit() { if (running) { running=false; - if (jack_deactivate(ac)) return false; + if (jack_deactivate(ac)) { + logE("could not deactivate!"); + return false; + } } for (int i=0; i Date: Mon, 6 Jun 2022 03:05:55 -0500 Subject: [PATCH 50/52] fade out experiments - DO NOT COMPILE --- TODO.md | 1 + src/engine/engine.cpp | 53 ++++++++++++++++++++++++++++++++++------- src/engine/engine.h | 9 +++++-- src/engine/playback.cpp | 5 ++++ src/gui/gui.cpp | 6 ++++- src/gui/gui.h | 2 ++ 6 files changed, 65 insertions(+), 11 deletions(-) diff --git a/TODO.md b/TODO.md index 5bd4e892..edf0caf6 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,6 @@ # to-do for 0.6pre1 +- fade out in audio export - rewrite the system name detection function anyway - add another FM editor layout - add ability to move selection by dragging diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 093f6d94..5c73817a 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -193,6 +193,9 @@ bool DivEngine::isExporting() { #ifdef HAVE_SNDFILE void DivEngine::runExportThread() { + size_t fadeOutSamples=got.rate*exportFadeOut; + size_t curFadeOutSample=0; + bool isFadingOut=false; switch (exportMode) { case DIV_EXPORT_MODE_ONE: { SNDFILE* sf; @@ -220,15 +223,36 @@ void DivEngine::runExportThread() { logI("rendering to file..."); while (playing) { + size_t total=0; nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); - for (int i=0; iEXPORT_BUFSIZE) { logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); + totalProcessed=EXPORT_BUFSIZE; } - if (sf_writef_float(sf,outBuf[2],totalProcessed)!=(int)totalProcessed) { + if (totalProcessed!=EXPORT_BUFSIZE) { + logW("wait what? %d != %d",totalProcessed,EXPORT_BUFSIZE); + } + for (int i=0; i<(int)totalProcessed; i++) { + total++; + if (isFadingOut) { + double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); + outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i]))*mul; + outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]))*mul; + if (++curFadeOutSample>=fadeOutSamples) { + playing=false; + break; + } + } else { + outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i])); + outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i])); + if (lastLoopPos>-1 && i>=lastLoopPos && totalLoops>=exportLoopCount) { + logD("start fading out..."); + isFadingOut=true; + } + } + } + + if (sf_writef_float(sf,outBuf[2],total)!=(int)total) { logE("error: failed to write entire buffer!"); break; } @@ -382,7 +406,12 @@ void DivEngine::runExportThread() { } curOrder=0; - remainingLoops=loopCount; + prevOrder=0; + if (exportFadeOut<=0.01) { + remainingLoops=loopCount; + } else { + remainingLoops=-1; + } playSub(false); while (playing) { @@ -448,13 +477,14 @@ void DivEngine::runExportThread() { } #endif -bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode) { +bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime) { #ifndef HAVE_SNDFILE logE("Furnace was not compiled with libsndfile. cannot export!"); return false; #else exportPath=path; exportMode=mode; + exportFadeOut=fadeOutTime; if (exportMode!=DIV_EXPORT_MODE_ONE) { // remove extension String lowerCase=exportPath; @@ -471,7 +501,12 @@ bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode) stop(); repeatPattern=false; setOrder(0); - remainingLoops=loops; + if (exportFadeOut<=0.01) { + remainingLoops=loops; + } else { + remainingLoops=-1; + } + exportLoopCount=loops; exportThread=new std::thread(_runExportThread,this); return true; #endif @@ -1131,6 +1166,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { totalTicks=0; totalSeconds=0; totalTicksR=0; + totalLoops=0; + lastLoopPos=-1; } speedAB=false; playing=true; diff --git a/src/engine/engine.h b/src/engine/engine.h index ec48e187..dc16584d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -303,7 +303,7 @@ class DivEngine { bool systemsRegistered; bool hasLoadedSomething; int softLockCount; - int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, nextSpeed; + int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed; size_t curSubSongIndex; double divider; int cycles; @@ -318,6 +318,7 @@ class DivEngine { DivChannelState chan[DIV_MAX_CHANS]; DivAudioEngines audioEngine; DivAudioExportModes exportMode; + double exportFadeOut; std::map conf; std::queue pendingNotes; bool isMuted[DIV_MAX_CHANS]; @@ -463,7 +464,7 @@ class DivEngine { // dump to VGM. SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171); // export to an audio file - bool saveAudio(const char* path, int loops, DivAudioExportModes mode); + bool saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime=0.0); // wait for audio export to finish void waitAudioFile(); // stop audio file export @@ -938,6 +939,9 @@ class DivEngine { prevRow(0), prevOrder(0), remainingLoops(-1), + totalLoops(0), + lastLoopPos(0), + exportLoopCount(0), nextSpeed(3), curSubSongIndex(0), divider(60), @@ -961,6 +965,7 @@ class DivEngine { haltOn(DIV_HALT_NONE), audioEngine(DIV_AUDIO_NULL), exportMode(DIV_EXPORT_MODE_ONE), + exportFadeOut(0.0), midiBaseChan(0), midiPoly(true), midiAgeCounter(0), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index f7c1646f..ed70da94 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1096,6 +1096,8 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { } void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size) { + lastLoopPos=-1; + if (out!=NULL) { memset(out[0],0,size*sizeof(float)); memset(out[1],0,size*sizeof(float)); @@ -1287,6 +1289,9 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } if (nextTick()) { + lastLoopPos=size-(runLeftG>>MASTER_CLOCK_PREC); + logD("last loop pos: %d for a size of %d and runLeftG of %d",lastLoopPos,size,runLeftG); + totalLoops++; if (remainingLoops>0) { remainingLoops--; if (!remainingLoops) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 309d605b..6e464184 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1676,7 +1676,7 @@ int FurnaceGUI::load(String path) { } void FurnaceGUI::exportAudio(String path, DivAudioExportModes mode) { - e->saveAudio(path.c_str(),exportLoops+1,mode); + e->saveAudio(path.c_str(),exportLoops+1,mode,exportFadeOut); displayExporting=true; } @@ -2827,6 +2827,9 @@ bool FurnaceGUI::loop() { if (ImGui::InputInt("Loops",&exportLoops,1,2)) { if (exportLoops<0) exportLoops=0; } + if (ImGui::InputDouble("Fade out (seconds)",&exportFadeOut,1.0,2.0,"%.1f")) { + if (exportFadeOut<0.0) exportFadeOut=0.0; + } ImGui::EndMenu(); } if (ImGui::BeginMenu("export VGM...")) { @@ -4351,6 +4354,7 @@ FurnaceGUI::FurnaceGUI(): latchTarget(0), wheelX(0), wheelY(0), + exportFadeOut(5.0), editControlsOpen(true), ordersOpen(true), insListOpen(true), diff --git a/src/gui/gui.h b/src/gui/gui.h index 86301b0a..7001c88e 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1072,6 +1072,8 @@ class FurnaceGUI { int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory, latchTarget; int wheelX, wheelY; + double exportFadeOut; + bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; From 64fa5f804b91be19a01c10761fd45c793ebe1ddf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Jun 2022 04:00:56 -0500 Subject: [PATCH 51/52] finish fade out on audio export option --- TODO.md | 1 - src/engine/engine.cpp | 86 ++++++++++++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/TODO.md b/TODO.md index edf0caf6..5bd4e892 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # to-do for 0.6pre1 -- fade out in audio export - rewrite the system name detection function anyway - add another FM editor layout - add ability to move selection by dragging diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 5c73817a..76b2cd11 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -229,9 +229,6 @@ void DivEngine::runExportThread() { logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); totalProcessed=EXPORT_BUFSIZE; } - if (totalProcessed!=EXPORT_BUFSIZE) { - logW("wait what? %d != %d",totalProcessed,EXPORT_BUFSIZE); - } for (int i=0; i<(int)totalProcessed; i++) { total++; if (isFadingOut) { @@ -310,7 +307,10 @@ void DivEngine::runExportThread() { float* outBuf[2]; outBuf[0]=new float[EXPORT_BUFSIZE]; outBuf[1]=new float[EXPORT_BUFSIZE]; - short* sysBuf=new short[EXPORT_BUFSIZE*2]; + short* sysBuf[32]; + for (int i=0; iisStereo()) { - sysBuf[j]=disCont[i].bbOut[0][j]; - } else { - sysBuf[j<<1]=disCont[i].bbOut[0][j]; - sysBuf[1+(j<<1)]=disCont[i].bbOut[1][j]; + if (totalProcessed>EXPORT_BUFSIZE) { + logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); + totalProcessed=EXPORT_BUFSIZE; + } + for (int j=0; j<(int)totalProcessed; j++) { + total++; + if (isFadingOut) { + double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); + for (int i=0; iisStereo()) { + sysBuf[i][j]=(double)disCont[i].bbOut[0][j]*mul; + } else { + sysBuf[i][j<<1]=(double)disCont[i].bbOut[0][j]*mul; + sysBuf[i][1+(j<<1)]=(double)disCont[i].bbOut[1][j]*mul; + } + } + if (++curFadeOutSample>=fadeOutSamples) { + playing=false; + break; + } + } else { + for (int i=0; iisStereo()) { + sysBuf[i][j]=disCont[i].bbOut[0][j]; + } else { + sysBuf[i][j<<1]=disCont[i].bbOut[0][j]; + sysBuf[i][1+(j<<1)]=disCont[i].bbOut[1][j]; + } + } + if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) { + logD("start fading out..."); + isFadingOut=true; } } - if (totalProcessed>EXPORT_BUFSIZE) { - logE("error: total processed is bigger than export bufsize! (%d) %d>%d",i,totalProcessed,EXPORT_BUFSIZE); - } - if (sf_writef_short(sf[i],sysBuf,totalProcessed)!=(int)totalProcessed) { + } + for (int i=0; iEXPORT_BUFSIZE) { logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); + totalProcessed=EXPORT_BUFSIZE; } - if (sf_writef_float(sf,outBuf[2],totalProcessed)!=(int)totalProcessed) { + for (int j=0; j<(int)totalProcessed; j++) { + total++; + if (isFadingOut) { + double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); + outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j]))*mul; + outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]))*mul; + if (++curFadeOutSample>=fadeOutSamples) { + playing=false; + break; + } + } else { + outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j])); + outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j])); + if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) { + logD("start fading out..."); + isFadingOut=true; + } + } + } + if (sf_writef_float(sf,outBuf[2],total)!=(int)total) { logE("error: failed to write entire buffer!"); break; } From 9edc4818b5a03230325428200f0d5e7f5aa9ca7f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 6 Jun 2022 05:03:19 -0500 Subject: [PATCH 52/52] prepare for find and replace window --- CMakeLists.txt | 1 + src/gui/doAction.cpp | 6 ++++++ src/gui/findReplace.cpp | 19 ++++++++++++++++ src/gui/gui.cpp | 48 ++++++++++++++++------------------------- src/gui/gui.h | 15 +++++-------- src/gui/guiConst.cpp | 1 + 6 files changed, 51 insertions(+), 39 deletions(-) create mode 100644 src/gui/findReplace.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bbaf81eb..fe6a12fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -494,6 +494,7 @@ src/gui/doAction.cpp src/gui/editing.cpp src/gui/editControls.cpp src/gui/effectList.cpp +src/gui/findReplace.cpp src/gui/insEdit.cpp src/gui/log.cpp src/gui/mixer.cpp diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 83fdad38..60c9d5c3 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -250,6 +250,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WINDOW_CHAN_OSC: nextWindow=GUI_WINDOW_CHAN_OSC; break; + case GUI_ACTION_WINDOW_FIND: + nextWindow=GUI_WINDOW_FIND; + break; case GUI_ACTION_COLLAPSE_WINDOW: collapseWindow=true; @@ -331,6 +334,9 @@ void FurnaceGUI::doAction(int what) { case GUI_WINDOW_CHAN_OSC: chanOscOpen=false; break; + case GUI_WINDOW_FIND: + findOpen=false; + break; default: break; } diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp new file mode 100644 index 00000000..3a5ec75f --- /dev/null +++ b/src/gui/findReplace.cpp @@ -0,0 +1,19 @@ +#include "gui.h" +#include "imgui.h" +#include "IconsFontAwesome4.h" +#include "misc/cpp/imgui_stdlib.h" + +void FurnaceGUI::drawFindReplace() { + if (nextWindow==GUI_WINDOW_FIND) { + findOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!findOpen) return; + ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); + if (ImGui::Begin("Find/Replace",&findOpen,globalWinFlags)) { + ImGui::Text("What am I gonna do with you?"); + } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_FIND; + ImGui::End(); +} diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 6e464184..20d3436b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1899,6 +1899,12 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { void FurnaceGUI::editOptions(bool topMenu) { char id[4096]; editOptsVisible=true; + + if (topMenu) { + ImGui::Text("..."); + ImGui::Separator(); + } + if (ImGui::MenuItem("cut",BIND_FOR(GUI_ACTION_PAT_CUT))) doCopy(true); if (ImGui::MenuItem("copy",BIND_FOR(GUI_ACTION_PAT_COPY))) doCopy(false); if (ImGui::MenuItem("paste",BIND_FOR(GUI_ACTION_PAT_PASTE))) doPaste(); @@ -2200,6 +2206,17 @@ void FurnaceGUI::editOptions(bool topMenu) { if (ImGui::MenuItem("collapse",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_ROWS))) doCollapse(2); if (ImGui::MenuItem("expand",BIND_FOR(GUI_ACTION_PAT_EXPAND_ROWS))) doExpand(2); + if (topMenu) { + ImGui::Separator(); + if (ImGui::MenuItem("find/replace",BIND_FOR(GUI_ACTION_WINDOW_FIND),findOpen)) { + if (findOpen) { + findOpen=false; + } else { + nextWindow=GUI_WINDOW_FIND; + } + } + } + /*if (topMenu) { ImGui::Separator(); ImGui::MenuItem("collapse pattern",BIND_FOR(GUI_ACTION_PAT_COLLAPSE_PAT)); @@ -3084,6 +3101,7 @@ bool FurnaceGUI::loop() { ImGui::DockSpaceOverViewport(NULL,lockLayout?(ImGuiDockNodeFlags_NoWindowMenuButton|ImGuiDockNodeFlags_NoMove|ImGuiDockNodeFlags_NoResize|ImGuiDockNodeFlags_NoCloseButton|ImGuiDockNodeFlags_NoDocking|ImGuiDockNodeFlags_NoDockingSplitMe|ImGuiDockNodeFlags_NoDockingSplitOther):0); drawSubSongs(); + drawFindReplace(); drawPattern(); drawEditControls(); drawSongInfo(); @@ -4382,35 +4400,7 @@ FurnaceGUI::FurnaceGUI(): effectListOpen(false), chanOscOpen(false), subSongsOpen(true), - /* - editControlsDocked(false), - ordersDocked(false), - insListDocked(false), - songInfoDocked(false), - patternDocked(false), - insEditDocked(false), - waveListDocked(false), - waveEditDocked(false), - sampleListDocked(false), - sampleEditDocked(false), - aboutDocked(false), - settingsDocked(false), - mixerDocked(false), - debugDocked(false), - inspectorDocked(false), - oscDocked(false), - volMeterDocked(false), - statsDocked(false), - compatFlagsDocked(false), - pianoDocked(false), - notesDocked(false), - channelsDocked(false), - regViewDocked(false), - logDocked(false), - effectListDocked(false), - chanOscDocked(false), - subSongsDocked(false), - */ + findOpen(false), selecting(false), selectingFull(false), curNibble(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 7001c88e..a1ff2b3d 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -245,7 +245,8 @@ enum FurnaceGUIWindows { GUI_WINDOW_LOG, GUI_WINDOW_EFFECT_LIST, GUI_WINDOW_CHAN_OSC, - GUI_WINDOW_SUBSONGS + GUI_WINDOW_SUBSONGS, + GUI_WINDOW_FIND }; enum FurnaceGUIFileDialogs { @@ -354,6 +355,7 @@ enum FurnaceGUIActions { GUI_ACTION_WINDOW_EFFECT_LIST, GUI_ACTION_WINDOW_CHAN_OSC, GUI_ACTION_WINDOW_SUBSONGS, + GUI_ACTION_WINDOW_FIND, GUI_ACTION_COLLAPSE_WINDOW, GUI_ACTION_CLOSE_WINDOW, @@ -1078,15 +1080,7 @@ class FurnaceGUI { bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen; - bool subSongsOpen; - - /* there ought to be a better way... - bool editControlsDocked, ordersDocked, insListDocked, songInfoDocked, patternDocked, insEditDocked; - bool waveListDocked, waveEditDocked, sampleListDocked, sampleEditDocked, aboutDocked, settingsDocked; - bool mixerDocked, debugDocked, inspectorDocked, oscDocked, volMeterDocked, statsDocked, compatFlagsDocked; - bool pianoDocked, notesDocked, channelsDocked, regViewDocked, logDocked, effectListDocked, chanOscDocked; - bool subSongsDocked; - */ + bool subSongsOpen, findOpen; SelectionPoint selStart, selEnd, cursor; bool selecting, selectingFull, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI; @@ -1355,6 +1349,7 @@ class FurnaceGUI { void drawLog(); void drawEffectList(); void drawSubSongs(); + void drawFindReplace(); void parseKeybinds(); void promptKey(int which); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index a9541222..80f9b5d8 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -492,6 +492,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_SUBSONGS", "Subsongs", 0), D("EFFECT_LIST", "Effect List", 0), D("WINDOW_CHAN_OSC", "Oscilloscope (per-channel)", 0), + D("WINDOW_FIND", "Find/Replace", FURKMOD_CMD|SDLK_f), D("COLLAPSE_WINDOW", "Collapse/expand current window", 0), D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE),