From 34c34733891a599a782b6699a452d46226d43c5e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 28 Apr 2022 14:03:58 -0500 Subject: [PATCH 01/12] improvements to swap/stomp channel --- src/engine/engine.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index b5b60b90..3d48c16c 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -664,6 +664,20 @@ void DivEngine::swapChannels(int src, int dest) { song.pat[src].effectCols^=song.pat[dest].effectCols; song.pat[dest].effectCols^=song.pat[src].effectCols; song.pat[src].effectCols^=song.pat[dest].effectCols; + + String prevChanName=song.chanName[src]; + String prevChanShortName=song.chanShortName[src]; + bool prevChanShow=song.chanShow[src]; + bool prevChanCollapse=song.chanCollapse[src]; + + song.chanName[src]=song.chanName[dest]; + song.chanShortName[src]=song.chanShortName[dest]; + song.chanShow[src]=song.chanShow[dest]; + song.chanCollapse[src]=song.chanCollapse[dest]; + song.chanName[dest]=prevChanName; + song.chanShortName[dest]=prevChanShortName; + song.chanShow[dest]=prevChanShow; + song.chanCollapse[dest]=prevChanCollapse; } void DivEngine::stompChannel(int ch) { @@ -673,6 +687,10 @@ void DivEngine::stompChannel(int ch) { } song.pat[ch].wipePatterns(); song.pat[ch].effectCols=1; + song.chanName[ch]=""; + song.chanShortName[ch]=""; + song.chanShow[ch]=true; + song.chanCollapse[ch]=false; } void DivEngine::swapChannelsP(int src, int dest) { From 2a1d45fa355c1444804cc8236cad9c7f96587c54 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 28 Apr 2022 15:07:28 -0500 Subject: [PATCH 02/12] update format.md for eventual ExtCh extra systems --- papers/format.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/papers/format.md b/papers/format.md index feafbe60..570529c4 100644 --- a/papers/format.md +++ b/papers/format.md @@ -213,6 +213,8 @@ size | description | - 0xb3: Yamaha Y8950 drums - 12 channels | - 0xb4: Konami SCC+ - 5 channels | - 0xb5: tildearrow Sound Unit - 8 channels + | - 0xb6: OPN extended - 9 channels + | - 0xb7: PC-98 extended - 19 channels | - 0xde: YM2610B extended - 19 channels | - 0xe0: QSound - 19 channels | - 0xfd: Dummy System - 8 channels From 2ac0e8af424c7bdb9ba8a0bb863a126b1da68e50 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 28 Apr 2022 18:32:24 -0500 Subject: [PATCH 03/12] further improve channel allocation --- src/engine/engine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 3d48c16c..c728e215 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2158,6 +2158,7 @@ void DivEngine::noteOff(int chan) { void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { bool isViable[DIV_MAX_CHANS]; bool canPlayAnyway=false; + bool notInViableChannel=false; if (midiBaseChan<0) midiBaseChan=0; if (midiBaseChan>=chans) midiBaseChan=chans-1; int finalChan=midiBaseChan; @@ -2171,6 +2172,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { // 1. check which channels are viable for this instrument DivInstrument* insInst=getIns(ins); + if (getPreferInsType(finalChan)!=insInst->type && getPreferInsSecondType(finalChan)!=insInst->type) notInViableChannel=true; for (int i=0; i=song.insLen || getPreferInsType(i)==insInst->type || getPreferInsSecondType(i)==insInst->type) { if (insInst->type==DIV_INS_OPL) { @@ -2193,7 +2195,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)) { + if (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)); @@ -2207,7 +2209,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { // 3. find the oldest channel int candidate=finalChan; do { - if (isViable[finalChan] && (insInst->type==DIV_INS_OPL || getChannelType(finalChan)==finalChanType) && chan[finalChan].midiAgetype==DIV_INS_OPL || getChannelType(finalChan)==finalChanType || notInViableChannel) && chan[finalChan].midiAge=chans) { From 5567746e0bec407a2f1bba376c701a8c3a4cb76d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 28 Apr 2022 23:58:11 -0500 Subject: [PATCH 04/12] QSound: implement panning macro - PLEASE READ the panning strategy for QSound has changed! it's now 08xy where x is left and y is right (muting is not possible though!) this makes it consistent with other chips, plus QSound's pan range was 32 anyway in order to toggle the QSound effect use effect 12xx --- TODO.md | 2 -- papers/doc/7-systems/qsound.md | 9 +++++---- src/engine/dispatch.h | 1 + src/engine/engine.cpp | 25 +++++++++++++++++++++++++ src/engine/engine.h | 4 ++++ src/engine/platform/qsound.cpp | 19 ++++++++++++++++++- src/engine/platform/qsound.h | 4 +++- src/engine/playback.cpp | 4 ++++ src/engine/song.h | 4 +++- src/gui/insEdit.cpp | 26 ++++++++++++++++++++++++-- 10 files changed, 87 insertions(+), 11 deletions(-) diff --git a/TODO.md b/TODO.md index 341d66dd..77eb864f 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,5 @@ # to-do for 0.6pre1 -- panning macro - - QSound? - piano/input pad - note input via piano - input pad diff --git a/papers/doc/7-systems/qsound.md b/papers/doc/7-systems/qsound.md index 9da79d82..5d6078aa 100644 --- a/papers/doc/7-systems/qsound.md +++ b/papers/doc/7-systems/qsound.md @@ -12,7 +12,8 @@ There are also 3 ADPCM channels, however they cannot be used in Furnace yet. The # effects -- `08xx`: Set panning. Valid range is 00-20. 00 for full left, 10 for center and 20 for full right. It is also possible to bypass the QSound algorithm by using the range 30-50. -- `10xx`: Set echo feedback level. This effect will apply to all channels. -- `11xx`: Set echo level. -- `3xxx`: Set the length of the echo delay buffer. +- `10xx`: set echo feedback level. + - this effect will apply to all channels. +- `11xx`: set echo level. +- `12xx`: toggle QSound algorithm (on by default). +- `3xxx`: set the length of the echo delay buffer. diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 1ab4cba1..d86f1b20 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -125,6 +125,7 @@ enum DivDispatchCmds { DIV_CMD_QSOUND_ECHO_FEEDBACK, DIV_CMD_QSOUND_ECHO_DELAY, DIV_CMD_QSOUND_ECHO_LEVEL, + DIV_CMD_QSOUND_SURROUND, DIV_CMD_X1_010_ENVELOPE_SHAPE, DIV_CMD_X1_010_ENVELOPE_ENABLE, diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index c728e215..c42f5cc5 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1041,6 +1041,28 @@ int DivEngine::calcFreq(int base, int pitch, bool period, int octave, int pitch2 base+((pitch*octave)>>1)+pitch2; } +int DivEngine::convertPanSplitToLinear(unsigned int val, unsigned char bits, int range) { + int panL=val>>bits; + int panR=val&((1<range) val=range; + int maxV=(1<maxV) panL=maxV; + if (panR>maxV) panR=maxV; + return (panL<name=fmt::sprintf("Instrument %d",insCount); ins->type=prefType; saveLock.lock(); diff --git a/src/engine/engine.h b/src/engine/engine.h index 441096a2..9f971d7a 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -475,6 +475,10 @@ class DivEngine { // calculate frequency/period int calcFreq(int base, int pitch, bool period=false, int octave=0, int pitch2=0); + // convert panning formats + int convertPanSplitToLinear(unsigned int val, unsigned char bits, int range); + unsigned int convertPanLinearToSplit(int val, unsigned char bits, int range); + // find song loop position void walkSong(int& loopOrder, int& loopRow, int& loopEnd); diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 8450d965..9dd34589 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -257,6 +257,9 @@ const char* DivPlatformQSound::getEffectName(unsigned char effect) { case 0x11: return "11xx: Set channel echo level (00 to FF)"; break; + case 0x12: + return "12xx: Toggle QSound algorithm (0: disabled; 1: enabled)"; + break; default: if ((effect & 0xf0) == 0x30) { return "3xxx: Set echo delay buffer length (000 to AA5)"; @@ -335,6 +338,15 @@ void DivPlatformQSound::tick(bool sysTick) { } chan[i].freqChanged=true; } + if (chan[i].std.panL.had) { // panning + chan[i].panning=chan[i].std.panL.val+16; + } + if (chan[i].std.panR.had) { // surround + chan[i].surround=chan[i].std.panR.val; + } + if (chan[i].std.panL.had || chan[i].std.panR.had) { + immWrite(Q1_PAN+i,chan[i].panning+0x110+(chan[i].surround?0:0x30)); + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2); @@ -429,7 +441,8 @@ int DivPlatformQSound::dispatch(DivCommand c) { return chan[c.chan].outVol; break; case DIV_CMD_PANNING: - immWrite(Q1_PAN+c.chan, c.value + 0x110); + chan[c.chan].panning=parent->convertPanSplitToLinear(c.value,4,32); + immWrite(Q1_PAN+c.chan,chan[c.chan].panning+0x110+(chan[c.chan].surround?0:0x30)); break; case DIV_CMD_QSOUND_ECHO_LEVEL: immWrite(Q1_ECHO+c.chan, c.value << 7); @@ -440,6 +453,10 @@ int DivPlatformQSound::dispatch(DivCommand c) { case DIV_CMD_QSOUND_ECHO_DELAY: immWrite(Q1_ECHO_LENGTH, (c.value > 2725 ? 0xfff : 0xfff - (2725 - c.value))); break; + case DIV_CMD_QSOUND_SURROUND: + chan[c.chan].surround=c.value; + immWrite(Q1_PAN+c.chan,chan[c.chan].panning+0x110+(chan[c.chan].surround?0:0x30)); + break; case DIV_CMD_PITCH: chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index 1eb9b275..6eb178d0 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -33,7 +33,7 @@ class DivPlatformQSound: public DivDispatch { int sample, wave, ins; int note; int panning; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround; int vol, outVol; DivMacroInt std; void macroInit(DivInstrument* which) { @@ -57,6 +57,8 @@ class DivPlatformQSound: public DivDispatch { keyOn(false), keyOff(false), inPorta(false), + useWave(false), + surround(true), vol(255), outVol(255) {} }; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 13cc495b..5fd03116 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -127,6 +127,7 @@ const char* cmdName[]={ "QSOUND_ECHO_FEEDBACK", "QSOUND_ECHO_DELAY", "QSOUND_ECHO_LEVEL", + "QSOUND_SURROUND", "X1_010_ENVELOPE_SHAPE", "X1_010_ENVELOPE_ENABLE", @@ -434,6 +435,9 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe case 0x11: // echo level dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal)); break; + case 0x12: // surround + dispatchCmd(DivCommand(DIV_CMD_QSOUND_SURROUND,ch,effectVal)); + break; default: if ((effect&0xf0)==0x30) { dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal)); diff --git a/src/engine/song.h b/src/engine/song.h index 087d8c7b..8e67cce8 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -347,7 +347,7 @@ struct DivSong { bool chanShow[DIV_MAX_CHANS]; bool chanCollapse[DIV_MAX_CHANS]; - DivInstrument nullIns, nullInsOPLL, nullInsOPL; + DivInstrument nullIns, nullInsOPLL, nullInsOPL, nullInsQSound; DivWavetable nullWave; DivSample nullSample; @@ -473,6 +473,8 @@ struct DivSong { nullInsOPL.fm.op[1].rr=12; nullInsOPL.fm.op[1].mult=1; nullInsOPL.name="This is a bug! Report!"; + + nullInsQSound.std.panLMacro.mode=true; } }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 71668335..fbd84358 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -212,6 +212,7 @@ const char* dualWSEffects[7]={ const char* macroAbsoluteMode="Fixed"; const char* macroRelativeMode="Relative"; +const char* macroQSoundMode="QSound"; const char* macroDummyMode="Bug"; @@ -2839,8 +2840,10 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_SAA1099) ex1Max=8; + int panMin=0; int panMax=0; bool panSingle=false; + bool panSingleNoBit=false; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_GB || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_VERA) { panMax=1; panSingle=true; @@ -2851,6 +2854,15 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099) { panMax=15; } + if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { + panMin=-16; + panMax=16; + } + if (ins->type==DIV_INS_SU) { + panMin=-127; + panMax=127; + panSingleNoBit=true; + } if (settings.macroView==0) { // modern view MACRO_BEGIN(28*dpiScale); @@ -2872,8 +2884,18 @@ void FurnaceGUI::drawInsEdit() { if (panSingle) { NORMAL_MACRO(ins->std.panLMacro,0,2,"panL","Panning",32,ins->std.panLMacro.open,true,panBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); } else { - NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",(31+panMax),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); - NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",(31+panMax),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false); + if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) { + NORMAL_MACRO(ins->std.panLMacro,panMin,panMax,"panL","Panning",(31+panMax-panMin),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,(ins->type==DIV_INS_AMIGA),(ins->type==DIV_INS_AMIGA?1:0),macroQSoundMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],panMin,panMax,NULL,false); + } else { + NORMAL_MACRO(ins->std.panLMacro,panMin,panMax,"panL","Panning (left)",(31+panMax-panMin),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,(ins->type==DIV_INS_AMIGA),(ins->type==DIV_INS_AMIGA?1:0),macroQSoundMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],panMin,panMax,NULL,false); + } + if (!panSingleNoBit) { + if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) { + NORMAL_MACRO(ins->std.panRMacro,0,1,"panR","Surround",32,ins->std.panRMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,1,NULL,false); + } else { + NORMAL_MACRO(ins->std.panRMacro,panMin,panMax,"panR","Panning (right)",(31+panMax-panMin),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],panMin,panMax,NULL,false); + } + } } } NORMAL_MACRO(ins->std.pitchMacro,pitchMacroScroll,pitchMacroScroll+160,"pitch","Pitch",160,ins->std.pitchMacro.open,false,NULL,true,&pitchMacroScroll,-2048,2047,0,0,true,1,macroRelativeMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[15],-2048,2047,NULL,!ins->std.pitchMacro.mode); From abd42cbb03c42e68a40b993df9175cbeb9ce6990 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 29 Apr 2022 00:08:56 -0500 Subject: [PATCH 05/12] SoundUnit: implement panning --- src/engine/platform/su.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 6efa0a48..4733e5b2 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -270,7 +270,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { break; } case DIV_CMD_PANNING: { - chan[c.chan].pan=c.value; + chan[c.chan].pan=parent->convertPanSplitToLinear(c.value,4,254)-127; chWrite(c.chan,0x03,chan[c.chan].pan); break; } From 8500fa4c4ced13f4c57f942ace59afaf1c8648ab Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 29 Apr 2022 00:18:51 -0500 Subject: [PATCH 06/12] NES: add DMC write effect --- papers/doc/7-systems/nes.md | 7 +++++-- src/engine/dispatch.h | 1 + src/engine/platform/nes.cpp | 6 ++++++ src/engine/playback.cpp | 4 ++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/papers/doc/7-systems/nes.md b/papers/doc/7-systems/nes.md index 3de0e307..8ce5d808 100644 --- a/papers/doc/7-systems/nes.md +++ b/papers/doc/7-systems/nes.md @@ -2,10 +2,13 @@ the console from Nintendo that plays Super Mario Bros. and helped revive the agonizing video game market in the US during mid-80s. -also known as Famicom. It is a five-channel PSG: first two channels play pulse wave with three different duty cycles, third is a fixed-volume triangle channel, fourth is a noise channel (can work in both pseudo-random and periodic modes) and fifth is a (D)PCM sample channel +also known as Famicom. It is a five-channel PSG: first two channels play pulse wave with three different duty cycles, third is a fixed-volume triangle channel, fourth is a noise channel (can work in both pseudo-random and periodic modes) and fifth is a (D)PCM sample channel # effects +- `11xx`: write to delta modulation counter. + - this may be used to attenuate the triangle and noise channels. + - will not work if a sample is playing. - `12xx`: set duty cycle or noise mode of channel. - may be 0-3 for the pulse channels and 0-1 for the noise channel. - `13xy`: setup sweep up. @@ -15,4 +18,4 @@ also known as Famicom. It is a five-channel PSG: first two channels play pulse w - `14xy`: setup sweep down. - `x` is the time. - `y` is the shift. - - set to 0 to disable it. + - set to 0 to disable it. \ No newline at end of file diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index d86f1b20..a12ccbfe 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -86,6 +86,7 @@ enum DivDispatchCmds { DIV_CMD_PCE_LFO_SPEED, // (speed) DIV_CMD_NES_SWEEP, // (direction, value) + DIV_CMD_NES_DMC, // (value) DIV_CMD_C64_CUTOFF, // (value) DIV_CMD_C64_RESONANCE, // (value) diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index b61abde0..f7a29066 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -59,6 +59,9 @@ const char** DivPlatformNES::getRegisterSheet() { const char* DivPlatformNES::getEffectName(unsigned char effect) { switch (effect) { + case 0x11: + return "Write to delta modulation counter (0 to 7F)"; + break; case 0x12: return "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"; break; @@ -420,6 +423,9 @@ int DivPlatformNES::dispatch(DivCommand c) { } rWrite(0x4001+(c.chan*4),chan[c.chan].sweep); break; + case DIV_CMD_NES_DMC: + rWrite(0x4011,c.value&0x7f); + break; case DIV_CMD_SAMPLE_BANK: sampleBank=c.value; if (sampleBank>(parent->song.sample.size()/12)) { diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 5fd03116..29899f0d 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -88,6 +88,7 @@ const char* cmdName[]={ "PCE_LFO_SPEED", "NES_SWEEP", + "NES_DMC", "C64_CUTOFF", "C64_RESONANCE", @@ -317,6 +318,9 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe case DIV_SYSTEM_NES: case DIV_SYSTEM_MMC5: switch (effect) { + case 0x11: // DMC write + dispatchCmd(DivCommand(DIV_CMD_NES_DMC,ch,effectVal)); + break; case 0x12: // duty or noise mode dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); break; From 3a354ea42b50531028aac8abe49bfe1df2927883 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 29 Apr 2022 00:18:55 -0500 Subject: [PATCH 07/12] oops --- papers/doc/7-systems/nes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/nes.md b/papers/doc/7-systems/nes.md index 8ce5d808..45ce95bc 100644 --- a/papers/doc/7-systems/nes.md +++ b/papers/doc/7-systems/nes.md @@ -2,7 +2,7 @@ the console from Nintendo that plays Super Mario Bros. and helped revive the agonizing video game market in the US during mid-80s. -also known as Famicom. It is a five-channel PSG: first two channels play pulse wave with three different duty cycles, third is a fixed-volume triangle channel, fourth is a noise channel (can work in both pseudo-random and periodic modes) and fifth is a (D)PCM sample channel +also known as Famicom. It is a five-channel PSG: first two channels play pulse wave with three different duty cycles, third is a fixed-volume triangle channel, fourth is a noise channel (can work in both pseudo-random and periodic modes) and fifth is a (D)PCM sample channel. # effects From 2583b18f86d23be88cb3cd1eef59a75f57aaaf8b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 29 Apr 2022 02:24:27 -0500 Subject: [PATCH 08/12] update to-do list --- TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.md b/TODO.md index 77eb864f..c813fbfe 100644 --- a/TODO.md +++ b/TODO.md @@ -39,3 +39,4 @@ - Apply button in settings - better FM chip names (number and codename) - find and replace +- precise panning effects (80xx linear, 81xx/82xx per-channel) From ee4d4c42513be9b78f5f2374ca40089de9c75f86 Mon Sep 17 00:00:00 2001 From: Zumi Daxuya Date: Fri, 29 Apr 2022 15:54:10 +0700 Subject: [PATCH 09/12] GUI: add chip randomizer button --- src/gui/newSong.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gui/newSong.cpp b/src/gui/newSong.cpp index d6188b3e..06aeb4bd 100644 --- a/src/gui/newSong.cpp +++ b/src/gui/newSong.cpp @@ -70,6 +70,14 @@ void FurnaceGUI::drawNewSong() { ImGui::CloseCurrentPopup(); } + ImGui::SameLine(); + + if (ImGui::Button("I'm feeling lucky")) { + FurnaceGUISysCategory* newSystemCat=&sysCategories[rand()%sysCategories.size()]; + nextDesc=newSystemCat->systems[rand()%newSystemCat->systems.size()].definition.data(); + accepted=true; + } + if (accepted) { e->createNew(nextDesc); undoHist.clear(); From 0817fdeb84b964022882541f7b623e1b972d1986 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 29 Apr 2022 04:34:20 -0500 Subject: [PATCH 10/12] GUI: possibly fix an instrument saving issue --- src/gui/gui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 56e046f0..41c7b955 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2903,6 +2903,10 @@ bool FurnaceGUI::loop() { if (fileDialog->render(ImVec2(600.0f*dpiScale,400.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale))) { bool openOpen=false; //ImGui::GetIO().ConfigFlags&=~ImGuiConfigFlags_NavEnableKeyboard; + if (curFileDialog==GUI_FILE_INS_OPEN && prevIns!=-3) { + curIns=prevIns; + prevIns=-3; + } switch (curFileDialog) { case GUI_FILE_OPEN: case GUI_FILE_SAVE: @@ -2947,9 +2951,6 @@ bool FurnaceGUI::loop() { workingDirLayout=fileDialog->getPath()+DIR_SEPARATOR_STR; break; } - if (prevIns!=-3) { - curIns=prevIns; - } if (fileDialog->accepted()) { fileName=fileDialog->getFileName(); if (fileName!="") { From aeea8a49128f0efb5ef4de28e5ff562c138e24b1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 29 Apr 2022 04:42:18 -0500 Subject: [PATCH 11/12] GUI: prevent division by zero --- src/gui/newSong.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/gui/newSong.cpp b/src/gui/newSong.cpp index 06aeb4bd..2bf11fb5 100644 --- a/src/gui/newSong.cpp +++ b/src/gui/newSong.cpp @@ -66,16 +66,24 @@ void FurnaceGUI::drawNewSong() { ImGui::EndTable(); } - if (ImGui::Button("Cancel")) { - ImGui::CloseCurrentPopup(); + if (ImGui::Button("I'm feeling lucky")) { + if (sysCategories.size()==0) { + ImGui::CloseCurrentPopup(); + } else { + FurnaceGUISysCategory* newSystemCat=&sysCategories[rand()%sysCategories.size()]; + if (newSystemCat->systems.size()==0) { + ImGui::CloseCurrentPopup(); + } else { + nextDesc=newSystemCat->systems[rand()%newSystemCat->systems.size()].definition.data(); + accepted=true; + } + } } ImGui::SameLine(); - if (ImGui::Button("I'm feeling lucky")) { - FurnaceGUISysCategory* newSystemCat=&sysCategories[rand()%sysCategories.size()]; - nextDesc=newSystemCat->systems[rand()%newSystemCat->systems.size()].definition.data(); - accepted=true; + if (ImGui::Button("Cancel")) { + ImGui::CloseCurrentPopup(); } if (accepted) { @@ -95,4 +103,4 @@ void FurnaceGUI::drawNewSong() { updateWindowTitle(); ImGui::CloseCurrentPopup(); } -} \ No newline at end of file +} From 635bd72904ec83fba8855936595e767a16c1df68 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 29 Apr 2022 05:39:18 -0500 Subject: [PATCH 12/12] GUI: sample/macro zoom with ctrl-wheel --- src/gui/gui.cpp | 1 + src/gui/gui.h | 1 + src/gui/insEdit.cpp | 7 ++++++- src/gui/sampleEdit.cpp | 11 +++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 41c7b955..74a30354 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3788,6 +3788,7 @@ FurnaceGUI::FurnaceGUI(): preserveChanPos(false), vgmExportVersion(0x171), drawHalt(10), + macroPointSize(16), curFileDialog(GUI_FILE_OPEN), warnAction(GUI_WARN_OPEN), postWarnAction(GUI_WARN_GENERIC), diff --git a/src/gui/gui.h b/src/gui/gui.h index 14b735b2..31ab566f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -739,6 +739,7 @@ class FurnaceGUI { bool willExport[32]; int vgmExportVersion; int drawHalt; + int macroPointSize; FurnaceGUIFileDialogs curFileDialog; FurnaceGUIWarnings warnAction; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index fbd84358..0355e7fe 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1128,6 +1128,11 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ } \ if (displayLoop) { \ + if (ImGui::IsItemHovered() && ctrlWheeling) { \ + macroPointSize+=wheelY; \ + if (macroPointSize<1) macroPointSize=1; \ + if (macroPointSize>256) macroPointSize=256; \ + } \ if (drawSlider) { \ ImGui::SameLine(); \ CWVSliderInt("##IMacroPos_" macroName,ImVec2(20.0f*dpiScale,displayHeight*dpiScale),sliderVal,sliderLow,sliderHigh); \ @@ -1262,7 +1267,7 @@ if (ImGui::BeginTable("MacroSpace",2)) { \ ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale)); \ ImGui::TableNextColumn(); \ float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; \ - int totalFit=MIN(127,availableWidth/(16*dpiScale)); \ + int totalFit=MIN(127,availableWidth/MAX(1,macroPointSize*dpiScale)); \ if (macroDragScroll>127-totalFit) { \ macroDragScroll=127-totalFit; \ } \ diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 53379c99..7882e53c 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -1268,6 +1268,17 @@ void FurnaceGUI::drawSampleEdit() { } if (ImGui::IsItemHovered()) { + if (ctrlWheeling) { + double zoomPercent=100.0/sampleZoom; + zoomPercent+=wheelY*10.0; + if (zoomPercent>10000.0) zoomPercent=10000.0; + if (zoomPercent<1.0) zoomPercent=1.0; + sampleZoom=100.0/zoomPercent; + if (sampleZoom<0.01) sampleZoom=0.01; + sampleZoomAuto=false; + updateSampleTex=true; + } + int posX=-1; int posY=0; ImVec2 pos=ImGui::GetMousePos();