Merge branch 'master' into gui-pretty

This commit is contained in:
tildearrow 2023-08-10 00:18:16 -05:00
commit 457fb785b0
26 changed files with 1596 additions and 109 deletions

BIN
demos/gameboy/freedom.fur Normal file

Binary file not shown.

BIN
demos/gameboy/minos.fur Normal file

Binary file not shown.

BIN
demos/gameboy/spreadtro.fur Normal file

Binary file not shown.

Binary file not shown.

View file

@ -11,21 +11,19 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **Render backend** - **Render backend**
- changing this may help with performace issues. - changing this may help with performace issues.
- **Late render clear** - **Late render clear**
- **Power-saving mode** - **Power-saving mode**: saves power by lowering the frame rate to 2fps when idle.
- saves power by lowering the frame rate to 2fps when idle.
- may cause issues under Mesa drivers! - may cause issues under Mesa drivers!
- **Disable threaded input (restart after changing!)** - **Disable threaded input (restart after changing!)**: processes key presses for note preview on a separate thread (on supported platforms), which reduces latency.
- threaded input processes key presses for note preview on a separate thread (on supported platforms), which reduces latency.
- however, crashes have been reported when threaded input is on. enable this option if that is the case. - however, crashes have been reported when threaded input is on. enable this option if that is the case.
- **Enable event delay** - **Enable event delay**
- may cause issues with high-polling-rate mice when previewing notes. - may cause issues with high-polling-rate mice when previewing notes.
### File ### File
- **Use system file picker**: use native OS file dialog instead of Furnace's. - **Use system file picker**: uses native OS file dialog instead of Furnace's.
- **Number of recent files** - **Number of recent files**: number of files to show in the _open recent..._ menu.
- **Compress when saving** - **Compress when saving**
- use zlib to compress saved songs. - uses zlib to compress saved songs.
- **Save unused patterns** - **Save unused patterns**
- **Use new pattern format when saving** - **Use new pattern format when saving**
- **Don't apply compatibility flags when loading .dmf** - **Don't apply compatibility flags when loading .dmf**
@ -39,11 +37,11 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **Initial system**: the system of chips loaded on starting Furnace. - **Initial system**: the system of chips loaded on starting Furnace.
- **Current system**: sets current chips as default. - **Current system**: sets current chips as default.
- **Randomize**: set default to a random system. - **Randomize**: sets default to a random system.
- this will not choose a random system at each start. - this will not choose a random system at each start.
- **Reset to defaults**: sets default to "Sega Genesis/Mega Drive". - **Reset to defaults**: sets default to "Sega Genesis/Mega Drive".
- **Name**: name for the default system. may be set to any text. - **Name**: name for the default system. may be set to any text.
- system configuration: same as in the [chip manager](../8-advanced/chip-manager.md) and [mixer](../8-advanced/mixer.md). - **Configure:**: same as in the [chip manager](../8-advanced/chip-manager.md) and [mixer](../8-advanced/mixer.md).
- **When creating new song**: - **When creating new song**:
- **Display system preset selector** - **Display system preset selector**
- **Start with initial system** - **Start with initial system**
@ -70,12 +68,12 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
### Output ### Output
- **Backend**: select SDL or JACK for audio output. - **Backend**: selects SDL or JACK for audio output.
- only appears on Linux, or MacOS compiled with JACK support - only appears on Linux, or MacOS compiled with JACK support
- **Driver** - **Driver**
- **Device**: audio device for playback. - **Device**: audio device for playback.
- **Sample rate** - **Sample rate**
- **Outputs**: select number of audio outputs created, up to 16. - **Outputs**: number of audio outputs created, up to 16.
- only appears when Backend is JACK. - only appears when Backend is JACK.
- **Channels**: number of output channels to use. - **Channels**: number of output channels to use.
- **Buffer size**: size of buffer in both samples and milliseconds. - **Buffer size**: size of buffer in both samples and milliseconds.
@ -209,8 +207,7 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **Export**: writes current layout to a .ini file. - **Export**: writes current layout to a .ini file.
- **Reset**: resets layout to default. - **Reset**: resets layout to default.
- **Allow docking editors** - **Allow docking editors**
- **Remember window position** - **Remember window position**: remembers the window's last position on start-up.
- remembers the window's last position on start-up.
- **Only allow window movement when clicking on title bar** - **Only allow window movement when clicking on title bar**
- **Play/edit controls layout:** - **Play/edit controls layout:**
- **Classic** - **Classic**
@ -236,7 +233,7 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **No** - **No**
- **Yes** - **Yes**
- **Yes (while holding Ctrl only)** - **Yes (while holding Ctrl only)**
- **Toggle channel solo on:** select which interactions with a channel header will toggle solo for that channel. - **Toggle channel solo on:** selects which interactions with a channel header will toggle solo for that channel.
- Right-click or double click - Right-click or double click
- Right-click - Right-click
- Double-click - Double-click
@ -248,13 +245,15 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **Pull delete affects entire channel row** - **Pull delete affects entire channel row**
- **Push value when overwriting instead of clearing it**: in the order list and pattern editors, typing into an already-filled value will shift digits instead of starting fresh. - **Push value when overwriting instead of clearing it**: in the order list and pattern editors, typing into an already-filled value will shift digits instead of starting fresh.
- if off: moving the cursor onto the value `A5` and typing a "B" results in `0B`. - if off: moving the cursor onto the value `A5` and typing a "B" results in `0B`.
- if on: with the cursor on the value `A5` and typing a "B" results in `5B`. - if on: moving the cursor onto the value `A5` and typing a "B" results in `5B`.
- **Effect input behavior:** - **Effect input behavior:**
- **Move down** - **Move down**
- **Move to effect value (otherwise move down)** - **Move to effect value (otherwise move down)**
- **Move to effect value/next effect and wrap around** - **Move to effect value/next effect and wrap around**
- **Delete effect value when deleting effect** - **Delete effect value when deleting effect**
- **Change current instrument when changing instrument column (absorb)** - **Change current instrument when changing instrument column (absorb)**
- **Remove instrument value when inserting note off/release**
- **Remove volume value when inserting note off/release**
### Cursor movement ### Cursor movement
@ -293,16 +292,17 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
### Scaling ### Scaling
- **Automatic UI scaling factor**: automatically match the OS's UI scaling. - **Automatic UI scaling factor**: automatically matches the OS's UI scaling.
- **UI scaling factor**: only if "Automatic UI scaling factor" is off. - **UI scaling factor**: only appears if "Automatic UI scaling factor" is off.
- **Icon size** - **Icon size**
### Text ### Text
- **Main font**: if "Custom...", a file path selector will appear beneath. - **Main font**: overall interface font.\
- **Size** **Header font**: font for section headers.\
- **Pattern font**: if "Custom...", a file path selector will appear beneath. **Pattern font** font for the pattern view, the order list, and related.
- **Size** - if "Custom...", a file path selector will appear.
- **Size**: font size.
- **Display Japanese characters**\ - **Display Japanese characters**\
**Display Chinese (Simplified) characters**\ **Display Chinese (Simplified) characters**\
**Display Chinese (Traditional) characters**\ **Display Chinese (Traditional) characters**\
@ -358,7 +358,7 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
### Channel ### Channel
- **Channel style:** - **Channel style:** sets the appearance of channel headers in pattern view.
- **Classic** - **Classic**
- **Line** - **Line**
- **Round** - **Round**
@ -428,11 +428,11 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **Between Decay and Sustain Rate** - **Between Decay and Sustain Rate**
- **After Release Rate** - **After Release Rate**
- **Use separate colors for carriers/modulators in FM editor** - **Use separate colors for carriers/modulators in FM editor**
- **Unsigned FM detune values** - **Unsigned FM detune values**: uses the internal representation of detune values, such that detune amounts of -1, -2, and -3 are shown as 5, 6, and 7.
### Statistics ### Statistics
- **Chip memory usage unit:** - **Chip memory usage unit:** unit for displaying memory usage in the Statistics window.
- **Bytes** - **Bytes**
- **Kilobytes** - **Kilobytes**
@ -440,15 +440,20 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **Rounded corners** - **Rounded corners**
- **Border** - **Border**
- **Fill entire window** - **Mono**: displays a single monaural waveform of all sound mixed together.
- **Waveform goes out of bounds** - if turned off, waves will be drawn on top of each other for each output channel.
- all colors are configurable via _Settings > Color > Color scheme > Oscilloscope > Wave (non-mono)._
- **Anti-aliased**: smoothes the lines of the waveform.
- slight performance cost and slightly buggy.
- **Fill entire window**: removes the gap between the waveform and the edge of the window.
- **Waveform goes out of bounds**: allows the waveform to draw past the top and bottom of the oscilloscope.
### Windows ### Windows
- **Rounded window corners** - **Rounded window corners**
- **Rounded buttons** - **Rounded buttons**
- **Rounded menu corners** - **Rounded menu corners**
- **Borders around widgets** - **Borders around widgets**: draws thin borders on buttons, checkboxes, text widgets, and the like.

View file

@ -532,6 +532,9 @@ nfdresult_t NFD_OpenDialogMultiple( const std::vector<std::string>& filterList,
nfdselcallback_t selCallback ) nfdselcallback_t selCallback )
{ {
nfdresult_t nfdResult = NFD_ERROR; nfdresult_t nfdResult = NFD_ERROR;
NFDWinEvents* winEvents;
bool hasEvents=true;
DWORD eventID=0;
HRESULT coResult = COMInit(); HRESULT coResult = COMInit();
@ -566,6 +569,16 @@ nfdresult_t NFD_OpenDialogMultiple( const std::vector<std::string>& filterList,
goto end; goto end;
} }
// Pass the callback
winEvents=new NFDWinEvents(selCallback);
if ( !SUCCEEDED(fileOpenDialog->Advise(winEvents,&eventID)) ) {
// error... ignore
hasEvents=false;
winEvents->Release();
} else {
winEvents->Release();
}
// Set a flag for multiple options // Set a flag for multiple options
DWORD dwFlags; DWORD dwFlags;
result = fileOpenDialog->GetOptions(&dwFlags); result = fileOpenDialog->GetOptions(&dwFlags);
@ -613,8 +626,12 @@ nfdresult_t NFD_OpenDialogMultiple( const std::vector<std::string>& filterList,
} }
end: end:
if ( fileOpenDialog ) if (fileOpenDialog) {
if (hasEvents) {
fileOpenDialog->Unadvise(eventID);
}
fileOpenDialog->Release(); fileOpenDialog->Release();
}
COMUninit(coResult); COMUninit(coResult);

1306
res/icons.sfd Normal file

File diff suppressed because it is too large Load diff

BIN
res/icons.ttf Normal file

Binary file not shown.

View file

@ -485,6 +485,12 @@ class DivDispatch {
*/ */
virtual bool keyOffAffectsPorta(int ch); virtual bool keyOffAffectsPorta(int ch);
/**
* test whether volume is global.
* @return whether it is.
*/
virtual bool isVolGlobal();
/** /**
* get the lowest note in a portamento. * get the lowest note in a portamento.
* @param ch the channel in question. * @param ch the channel in question.

View file

@ -216,13 +216,6 @@ void DivDispatchContainer::clear() {
if (dispatch->getDCOffRequired()) { if (dispatch->getDCOffRequired()) {
dcOffCompensation=true; dcOffCompensation=true;
} }
// run for one cycle to determine DC offset
// TODO: SAA1099 doesn't like that
/*dispatch->acquire(bbIn[0],bbIn[1],0,1);
temp[0]=bbIn[0][0];
temp[1]=bbIn[1][0];
prevSample[0]=temp[0];
prevSample[1]=temp[1];*/
} }
void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, const DivConfig& flags) { void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, const DivConfig& flags) {
@ -479,7 +472,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
break; break;
case DIV_SYSTEM_NAMCO: case DIV_SYSTEM_NAMCO:
dispatch=new DivPlatformNamcoWSG; dispatch=new DivPlatformNamcoWSG;
// Pac-Man (TODO: support Pole Position?) // Pac-Man
((DivPlatformNamcoWSG*)dispatch)->setDeviceType(1); ((DivPlatformNamcoWSG*)dispatch)->setDeviceType(1);
break; break;
case DIV_SYSTEM_NAMCO_15XX: case DIV_SYSTEM_NAMCO_15XX:

View file

@ -86,6 +86,10 @@ bool DivDispatch::keyOffAffectsPorta(int ch) {
return false; return false;
} }
bool DivDispatch::isVolGlobal() {
return false;
}
int DivDispatch::getPortaFloor(int ch) { int DivDispatch::getPortaFloor(int ch) {
return 0x00; return 0x00;
} }

View file

@ -566,6 +566,10 @@ bool DivPlatformC64::getWantPreNote() {
return true; return true;
} }
bool DivPlatformC64::isVolGlobal() {
return true;
}
float DivPlatformC64::getPostAmp() { float DivPlatformC64::getPostAmp() {
return (sidCore==1)?3.0f:1.0f; return (sidCore==1)?3.0f:1.0f;
} }

View file

@ -105,6 +105,7 @@ class DivPlatformC64: public DivDispatch {
void notifyInsChange(int ins); void notifyInsChange(int ins);
bool getDCOffRequired(); bool getDCOffRequired();
bool getWantPreNote(); bool getWantPreNote();
bool isVolGlobal();
float getPostAmp(); float getPostAmp();
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
void notifyInsDeletion(void* ins); void notifyInsDeletion(void* ins);

View file

@ -28,6 +28,8 @@
#define CHIP_FREQBASE 1180068 #define CHIP_FREQBASE 1180068
#define DRUM_VOL(_x) (drumActivated[_x]?drumVol[_x]:15)
const unsigned char cycleMapOPLL[18]={ const unsigned char cycleMapOPLL[18]={
8, 7, 6, 7, 8, 7, 8, 6, 0, 1, 2, 7, 8, 9, 3, 4, 5, 9 8, 7, 6, 7, 8, 7, 8, 6, 0, 1, 2, 7, 8, 9, 3, 4, 5, 9
}; };
@ -52,7 +54,7 @@ void DivPlatformOPLL::acquire_nuked(short** buf, size_t len) {
QueuedWrite& w=writes.front(); QueuedWrite& w=writes.front();
if (w.addrOrVal) { if (w.addrOrVal) {
OPLL_Write(&fm,1,w.val); OPLL_Write(&fm,1,w.val);
//printf("write: %x = %.2x\n",w.addr,w.val); //logV("write: %x = %.2x",w.addr,w.val);
regPool[w.addr&0xff]=w.val; regPool[w.addr&0xff]=w.val;
writes.pop(); writes.pop();
delay=21; delay=21;
@ -104,10 +106,10 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (i>=6 && properDrums) { if (i>=6 && properDrums) {
drumVol[i-6]=15-chan[i].outVol; drumVol[i-6]=15-chan[i].outVol;
rWrite(0x36,drumVol[0]); rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,drumVol[1]|(drumVol[4]<<4)); rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,drumVol[3]|(drumVol[2]<<4)); rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
} else if (i<6 || !drums) { } else if (i<6 || !crapDrums) {
if (i<9) { if (i<9) {
rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4)); rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
} }
@ -230,16 +232,16 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (i>=6 && properDrums) { if (i>=6 && properDrums) {
drumState&=~(0x10>>(i-6)); drumState&=~(0x10>>(i-6));
immWrite(0x0e,0x20|drumState); immWrite(0x0e,0x20|drumState);
logV("properDrums %d",i); //logV("properDrums %d",i);
} else if (i>=6 && drums) { } else if (i>=6 && crapDrums) {
drumState&=~(0x10>>(chan[i].note%12)); drumState&=~(0x10>>(chan[i].note%12));
immWrite(0x0e,0x20|drumState); immWrite(0x0e,0x20|drumState);
logV("drums %d",i); //logV("drums %d",i);
} else { } else {
if (i<9) { if (i<9) {
immWrite(0x20+i,(chan[i].freqH)|(chan[i].state.alg?0x20:0)); immWrite(0x20+i,(chan[i].freqH)|(chan[i].state.alg?0x20:0));
} }
logV("normal %d",i); //logV("normal %d",i);
} }
//chan[i].keyOn=false; //chan[i].keyOn=false;
chan[i].keyOff=false; chan[i].keyOff=false;
@ -265,7 +267,21 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (i>=6 && properDrums && (i<9 || !noTopHatFreq)) { if (i>=6 && properDrums && (i<9 || !noTopHatFreq)) {
immWrite(0x10+drumSlot[i],freqt&0xff); immWrite(0x10+drumSlot[i],freqt&0xff);
immWrite(0x20+drumSlot[i],freqt>>8); immWrite(0x20+drumSlot[i],freqt>>8);
} else if (i<6 || !drums) { switch (i) {
case 7:
lastFreqSH=0;
break;
case 8:
lastFreqTT=0;
break;
case 9:
lastFreqTT=1;
break;
case 19:
lastFreqSH=1;
break;
}
} else if (i<6 || !crapDrums) {
if (i<9) { if (i<9) {
immWrite(0x10+i,freqt&0xff); immWrite(0x10+i,freqt&0xff);
} }
@ -278,7 +294,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
immWrite(0x0e,0x20|drumState); immWrite(0x0e,0x20|drumState);
} }
chan[i].keyOn=false; chan[i].keyOn=false;
} else if (chan[i].keyOn && i>=6 && drums) { } else if (chan[i].keyOn && i>=6 && crapDrums) {
//printf("%d\n",chan[i].note%12); //printf("%d\n",chan[i].note%12);
drumState|=(0x10>>(chan[i].note%12)); drumState|=(0x10>>(chan[i].note%12));
immWrite(0x0e,0x20|drumState); immWrite(0x0e,0x20|drumState);
@ -365,7 +381,8 @@ void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) {
} }
if (chan[ch].state.opllPreset==16) { // compatible drums mode if (chan[ch].state.opllPreset==16) { // compatible drums mode
if (ch>=6) { if (ch>=6) {
drums=true; if (!properDrumsSys) {
crapDrums=true;
immWrite(0x16,0x20); immWrite(0x16,0x20);
immWrite(0x26,0x05); immWrite(0x26,0x05);
immWrite(0x16,0x20); immWrite(0x16,0x20);
@ -377,10 +394,11 @@ void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) {
immWrite(0x18,0xC0); immWrite(0x18,0xC0);
immWrite(0x28,0x01); immWrite(0x28,0x01);
} }
}
} else { } else {
if (ch>=6) { if (ch>=6) {
if (drums) { if (crapDrums) {
drums=false; crapDrums=false;
immWrite(0x0e,0); immWrite(0x0e,0);
drumState=0; drumState=0;
} }
@ -395,10 +413,40 @@ void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) {
void DivPlatformOPLL::switchMode(bool mode) { void DivPlatformOPLL::switchMode(bool mode) {
if (mode==properDrums) return; if (mode==properDrums) return;
if (mode) { if (mode) {
//logV("mode switch to DRUMS");
} else { for (int i=0; i<5; i++) {
drumActivated[i]=chan[6+i].keyOn;
} }
immWrite(0x26,0);
immWrite(0x27,0);
immWrite(0x28,0);
immWrite(0x16,0);
immWrite(0x17,0);
immWrite(0x18,0);
immWrite(0x0e,0x20);
rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
oldWrites[0x36]=-1;
oldWrites[0x37]=-1;
oldWrites[0x38]=-1;
} else {
//logV("mode switch to NORMAL");
immWrite(0x0e,0x20);
immWrite(0x0e,0x00);
for (int i=6; i<9; i++) {
if (chan[i].active) {
chan[i].freqChanged=true;
chan[i].keyOff=false;
chan[i].keyOn=true;
oldWrites[0x30+i]=-1;
}
chan[i].insChanged=true;
}
}
properDrums=mode;
drumState=0;
} }
int DivPlatformOPLL::dispatch(DivCommand c) { int DivPlatformOPLL::dispatch(DivCommand c) {
@ -417,8 +465,20 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
if (c.chan>=6 && properDrums) { // drums mode if (c.chan>=6 && properDrums) { // drums mode
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
drumActivated[c.chan-6]=true;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
if (chan[c.chan].state.opllPreset==16 && chan[c.chan].state.fixedDrums) { if (chan[c.chan].state.opllPreset==16 && chan[c.chan].state.fixedDrums) {
if (fixedAll) {
chan[6].fixedFreq=(chan[c.chan].state.kickFreq&511)<<(chan[c.chan].state.kickFreq>>9);
chan[7].fixedFreq=(chan[c.chan].state.snareHatFreq&511)<<(chan[c.chan].state.snareHatFreq>>9);
chan[8].fixedFreq=(chan[c.chan].state.tomTopFreq&511)<<(chan[c.chan].state.tomTopFreq>>9);
chan[9].fixedFreq=(chan[c.chan].state.tomTopFreq&511)<<(chan[c.chan].state.tomTopFreq>>9);
chan[10].fixedFreq=(chan[c.chan].state.snareHatFreq&511)<<(chan[c.chan].state.snareHatFreq>>9);
chan[7].freqChanged=true;
chan[8].freqChanged=true;
chan[9].freqChanged=true;
} else {
switch (c.chan) { switch (c.chan) {
case 6: case 6:
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&511)<<(chan[c.chan].state.kickFreq>>9); chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&511)<<(chan[c.chan].state.kickFreq>>9);
@ -430,6 +490,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&511)<<(chan[c.chan].state.tomTopFreq>>9); chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&511)<<(chan[c.chan].state.tomTopFreq>>9);
break; break;
} }
}
} else { } else {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
} }
@ -438,6 +499,10 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
} }
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].active=true; chan[c.chan].active=true;
rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
break; break;
} }
@ -448,7 +513,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
if (c.chan>=6 && drums) { if (c.chan>=6 && crapDrums) {
switch (chan[c.chan].note%12) { switch (chan[c.chan].note%12) {
case 0: // kick case 0: // kick
drumVol[0]=(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15); drumVol[0]=(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15);
@ -466,9 +531,9 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
drumVol[4]=(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15); drumVol[4]=(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15);
break; break;
} }
rWrite(0x36,drumVol[0]); rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,drumVol[1]|(drumVol[4]<<4)); rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,drumVol[3]|(drumVol[2]<<4)); rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
} }
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
} }
@ -503,11 +568,11 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
} }
if (c.chan>=6 && properDrums) { if (c.chan>=6 && properDrums) {
drumVol[c.chan-6]=15-chan[c.chan].outVol; drumVol[c.chan-6]=15-chan[c.chan].outVol;
rWrite(0x36,drumVol[0]); rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,drumVol[1]|(drumVol[4]<<4)); rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,drumVol[3]|(drumVol[2]<<4)); rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
break; break;
} else if (c.chan<6 || !drums) { } else if (c.chan<6 || !crapDrums) {
if (c.chan<9) { if (c.chan<9) {
rWrite(0x30+c.chan,((15-VOL_SCALE_LOG_BROKEN(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_BROKEN(chan[c.chan].outVol,15-chan[c.chan].state.op[1].tl,15))&15)|(chan[c.chan].state.opllPreset<<4));
} }
@ -565,7 +630,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
} }
case DIV_CMD_LEGATO: { case DIV_CMD_LEGATO: {
if (c.chan>=9 && !properDrums) return 0; if (c.chan>=9 && !properDrums) return 0;
if (c.chan<6 || (!drums && !properDrums)) { if (c.chan<6 || (!crapDrums && !properDrums)) {
if (chan[c.chan].insChanged) { if (chan[c.chan].insChanged) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL); DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL);
commitState(c.chan,ins); commitState(c.chan,ins);
@ -780,12 +845,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
case DIV_CMD_FM_EXTCH: case DIV_CMD_FM_EXTCH:
if (!properDrumsSys) break; if (!properDrumsSys) break;
if ((int)properDrums==c.value) break; if ((int)properDrums==c.value) break;
if (c.value) { switchMode(c.value);
properDrums=true;
} else {
properDrums=false;
}
switchMode(properDrums);
break; break;
case DIV_CMD_MACRO_OFF: case DIV_CMD_MACRO_OFF:
chan[c.chan].std.mask(c.value,true); chan[c.chan].std.mask(c.value,true);
@ -840,7 +900,7 @@ void DivPlatformOPLL::forceIns() {
} }
} }
} }
if (drums) { // WHAT?! FIX THIS! if (crapDrums) { // WHAT?! FIX THIS!
immWrite(0x16,0x20); immWrite(0x16,0x20);
immWrite(0x26,0x05); immWrite(0x26,0x05);
immWrite(0x16,0x20); immWrite(0x16,0x20);
@ -852,11 +912,25 @@ void DivPlatformOPLL::forceIns() {
immWrite(0x18,0xC0); immWrite(0x18,0xC0);
immWrite(0x28,0x01); immWrite(0x28,0x01);
} }
// restore drum volumes // restore drum volumes and state
if (properDrums) { if (properDrums) {
rWrite(0x36,drumVol[0]); rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,drumVol[1]|(drumVol[4]<<4)); rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,drumVol[3]|(drumVol[2]<<4)); rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
if (lastFreqSH==0) {
chan[7].freqChanged=true;
} else if (lastFreqSH==1) {
chan[10].freqChanged=true;
}
if (lastFreqTT==0) {
chan[8].freqChanged=true;
} else if (lastFreqTT==1) {
chan[9].freqChanged=true;
}
chan[6].freqChanged=true;
} }
drumState=0; drumState=0;
} }
@ -937,16 +1011,18 @@ void DivPlatformOPLL::reset() {
drumState=0; drumState=0;
lastCustomMemory=-1; lastCustomMemory=-1;
drumVol[0]=0; for (int i=0; i<5; i++) {
drumVol[1]=0; drumVol[i]=0;
drumVol[2]=0; drumActivated[i]=true;
drumVol[3]=0; }
drumVol[4]=0;
delay=0; delay=0;
drums=false; crapDrums=false;
properDrums=properDrumsSys; properDrums=properDrumsSys;
lastFreqSH=-1;
lastFreqTT=-1;
if (properDrums) { if (properDrums) {
immWrite(0x0e,0x20); immWrite(0x0e,0x20);
} }
@ -1012,6 +1088,7 @@ void DivPlatformOPLL::setFlags(const DivConfig& flags) {
oscBuf[i]->rate=rate/2; oscBuf[i]->rate=rate/2;
} }
noTopHatFreq=flags.getBool("noTopHatFreq",false); noTopHatFreq=flags.getBool("noTopHatFreq",false);
fixedAll=flags.getBool("fixedAll",false);
} }
int DivPlatformOPLL::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { int DivPlatformOPLL::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {

View file

@ -59,12 +59,18 @@ class DivPlatformOPLL: public DivDispatch {
unsigned char lastBusy; unsigned char lastBusy;
unsigned char drumState; unsigned char drumState;
unsigned char drumVol[5]; unsigned char drumVol[5];
bool drumActivated[5];
// -1: undefined
// 0: snare/tom
// 1: hi-hat/top
signed char lastFreqSH, lastFreqTT;
unsigned char regPool[256]; unsigned char regPool[256];
bool useYMFM; bool useYMFM;
bool drums; bool crapDrums;
bool properDrums, properDrumsSys, noTopHatFreq; bool properDrums, properDrumsSys, noTopHatFreq, fixedAll;
bool vrc7; bool vrc7;
unsigned char patchSet; unsigned char patchSet;

View file

@ -257,6 +257,10 @@ void DivPlatformTED::forceIns() {
updateCtrl=true; updateCtrl=true;
} }
bool DivPlatformTED::isVolGlobal() {
return true;
}
void* DivPlatformTED::getChanState(int ch) { void* DivPlatformTED::getChanState(int ch) {
return &chan[ch]; return &chan[ch];
} }

View file

@ -54,6 +54,7 @@ class DivPlatformTED: public DivDispatch {
public: public:
void acquire(short** buf, size_t len); void acquire(short** buf, size_t len);
int dispatch(DivCommand c); int dispatch(DivCommand c);
bool isVolGlobal();
void* getChanState(int chan); void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan); DivDispatchOscBuffer* getOscBuffer(int chan);

View file

@ -278,6 +278,10 @@ void DivPlatformVIC20::forceIns() {
} }
} }
bool DivPlatformVIC20::isVolGlobal() {
return true;
}
void* DivPlatformVIC20::getChanState(int ch) { void* DivPlatformVIC20::getChanState(int ch) {
return &chan[ch]; return &chan[ch];
} }

View file

@ -46,6 +46,7 @@ class DivPlatformVIC20: public DivDispatch {
public: public:
void acquire(short** buf, size_t len); void acquire(short** buf, size_t len);
int dispatch(DivCommand c); int dispatch(DivCommand c);
bool isVolGlobal();
void* getChanState(int chan); void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan); DivDispatchOscBuffer* getOscBuffer(int chan);

View file

@ -1307,7 +1307,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
} else { } else {
DivMacroInt* macroInt=disCont[dispatchOfChan[note.channel]].dispatch->getChanMacroInt(dispatchChanOfChan[note.channel]); DivMacroInt* macroInt=disCont[dispatchOfChan[note.channel]].dispatch->getChanMacroInt(dispatchChanOfChan[note.channel]);
if (macroInt!=NULL) { if (macroInt!=NULL) {
if (macroInt->hasRelease) { if (macroInt->hasRelease && !disCont[dispatchOfChan[note.channel]].dispatch->isVolGlobal()) {
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF_ENV,note.channel)); dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF_ENV,note.channel));
} else { } else {
dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel)); dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,note.channel));

View file

@ -609,6 +609,14 @@ void FurnaceGUI::doAction(int what) {
break; break;
case GUI_ACTION_INS_LIST_ADD: case GUI_ACTION_INS_LIST_ADD:
if (settings.insTypeMenu) {
makeInsTypeList=e->getPossibleInsTypes();
if (makeInsTypeList.size()>1) {
displayInsTypeList=true;
displayInsTypeListMakeInsSample=-1;
break;
}
}
curIns=e->addInstrument(cursor.xCoarse); curIns=e->addInstrument(cursor.xCoarse);
if (curIns==-1) { if (curIns==-1) {
showError("too many instruments!"); showError("too many instruments!");

View file

@ -3919,7 +3919,7 @@ bool FurnaceGUI::loop() {
if (!mobileUI) { if (!mobileUI) {
ImGui::BeginMainMenuBar(); ImGui::BeginMainMenuBar();
if (ImGui::BeginMenu("file")) { if (ImGui::BeginMenu(settings.capitalMenuBar?"File":"file")) {
if (ImGui::MenuItem("new...",BIND_FOR(GUI_ACTION_NEW))) { if (ImGui::MenuItem("new...",BIND_FOR(GUI_ACTION_NEW))) {
if (modified) { if (modified) {
showWarning("Unsaved changes! Save changes before creating a new song?",GUI_WARN_NEW); showWarning("Unsaved changes! Save changes before creating a new song?",GUI_WARN_NEW);
@ -4245,7 +4245,7 @@ bool FurnaceGUI::loop() {
} else { } else {
exitDisabledTimer=0; exitDisabledTimer=0;
} }
if (ImGui::BeginMenu("edit")) { if (ImGui::BeginMenu(settings.capitalMenuBar?"Edit":"edit")) {
ImGui::Text("..."); ImGui::Text("...");
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("undo",BIND_FOR(GUI_ACTION_UNDO))) doUndo(); if (ImGui::MenuItem("undo",BIND_FOR(GUI_ACTION_UNDO))) doUndo();
@ -4258,7 +4258,7 @@ bool FurnaceGUI::loop() {
} }
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("settings")) { if (ImGui::BeginMenu(settings.capitalMenuBar?"Settings":"settings")) {
#ifndef IS_MOBILE #ifndef IS_MOBILE
if (ImGui::MenuItem("full screen",BIND_FOR(GUI_ACTION_FULLSCREEN),fullScreen)) { if (ImGui::MenuItem("full screen",BIND_FOR(GUI_ACTION_FULLSCREEN),fullScreen)) {
doAction(GUI_ACTION_FULLSCREEN); doAction(GUI_ACTION_FULLSCREEN);
@ -4294,7 +4294,7 @@ bool FurnaceGUI::loop() {
} }
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("window")) { if (ImGui::BeginMenu(settings.capitalMenuBar?"Window":"window")) {
if (ImGui::MenuItem("song information",BIND_FOR(GUI_ACTION_WINDOW_SONG_INFO),songInfoOpen)) songInfoOpen=!songInfoOpen; if (ImGui::MenuItem("song information",BIND_FOR(GUI_ACTION_WINDOW_SONG_INFO),songInfoOpen)) songInfoOpen=!songInfoOpen;
if (ImGui::MenuItem("subsongs",BIND_FOR(GUI_ACTION_WINDOW_SUBSONGS),subSongsOpen)) subSongsOpen=!subSongsOpen; if (ImGui::MenuItem("subsongs",BIND_FOR(GUI_ACTION_WINDOW_SUBSONGS),subSongsOpen)) subSongsOpen=!subSongsOpen;
if (ImGui::MenuItem("speed",BIND_FOR(GUI_ACTION_WINDOW_SPEED),speedOpen)) speedOpen=!speedOpen; if (ImGui::MenuItem("speed",BIND_FOR(GUI_ACTION_WINDOW_SPEED),speedOpen)) speedOpen=!speedOpen;
@ -4336,7 +4336,7 @@ bool FurnaceGUI::loop() {
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("help")) { if (ImGui::BeginMenu(settings.capitalMenuBar?"Help":"help")) {
if (ImGui::MenuItem("effect list",BIND_FOR(GUI_ACTION_WINDOW_EFFECT_LIST),effectListOpen)) effectListOpen=!effectListOpen; if (ImGui::MenuItem("effect list",BIND_FOR(GUI_ACTION_WINDOW_EFFECT_LIST),effectListOpen)) effectListOpen=!effectListOpen;
if (ImGui::MenuItem("debug menu",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) debugOpen=!debugOpen; if (ImGui::MenuItem("debug menu",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) debugOpen=!debugOpen;
if (ImGui::MenuItem("inspector",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) inspectorOpen=!inspectorOpen; if (ImGui::MenuItem("inspector",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) inspectorOpen=!inspectorOpen;
@ -5630,6 +5630,19 @@ bool FurnaceGUI::loop() {
wavePreviewInit=true; wavePreviewInit=true;
updateFMPreview=true; updateFMPreview=true;
} }
if (settings.blankIns) {
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;
}
}
MARK_MODIFIED; MARK_MODIFIED;
} }
} }

View file

@ -1548,6 +1548,8 @@ class FurnaceGUI {
int removeInsOff; int removeInsOff;
int removeVolOff; int removeVolOff;
int playOnLoad; int playOnLoad;
int insTypeMenu;
int capitalMenuBar;
unsigned int maxUndoSteps; unsigned int maxUndoSteps;
String mainFontPath; String mainFontPath;
String headFontPath; String headFontPath;
@ -1710,6 +1712,8 @@ class FurnaceGUI {
removeInsOff(0), removeInsOff(0),
removeVolOff(0), removeVolOff(0),
playOnLoad(0), playOnLoad(0),
insTypeMenu(1),
capitalMenuBar(0),
maxUndoSteps(100), maxUndoSteps(100),
mainFontPath(""), mainFontPath(""),
headFontPath(""), headFontPath(""),

View file

@ -1407,28 +1407,40 @@ void FurnaceGUI::initSystemPresets() {
"Sega System 32", { "Sega System 32", {
CH(DIV_SYSTEM_YM2612, 1.0f, 0, "clockSel=4"), // discrete 8.05MHz YM3438 CH(DIV_SYSTEM_YM2612, 1.0f, 0, "clockSel=4"), // discrete 8.05MHz YM3438
CH(DIV_SYSTEM_YM2612, 1.0f, 0, "clockSel=4"), // ^^ CH(DIV_SYSTEM_YM2612, 1.0f, 0, "clockSel=4"), // ^^
CH(DIV_SYSTEM_RF5C68, 1.0f, 0, "clockSel=2") // 12.5MHz CH(DIV_SYSTEM_RF5C68, 1.0f, 0,
"clockSel=2\n"
"chipType=1\n"
) // 12.5MHz
} }
); );
ENTRY( ENTRY(
"Sega System 32 (extended channel 3 on first OPN2C)", { "Sega System 32 (extended channel 3 on first OPN2C)", {
CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, "clockSel=4"), // discrete 8.05MHz YM3438 CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, "clockSel=4"), // discrete 8.05MHz YM3438
CH(DIV_SYSTEM_YM2612, 1.0f, 0, "clockSel=4"), // ^^ CH(DIV_SYSTEM_YM2612, 1.0f, 0, "clockSel=4"), // ^^
CH(DIV_SYSTEM_RF5C68, 1.0f, 0, "clockSel=2") // 12.5MHz CH(DIV_SYSTEM_RF5C68, 1.0f, 0,
"clockSel=2\n"
"chipType=1\n"
) // 12.5MHz
} }
); );
ENTRY( ENTRY(
"Sega System 32 (extended channel 3 on second OPN2C)", { "Sega System 32 (extended channel 3 on second OPN2C)", {
CH(DIV_SYSTEM_YM2612, 1.0f, 0, "clockSel=4"), // discrete 8.05MHz YM3438 CH(DIV_SYSTEM_YM2612, 1.0f, 0, "clockSel=4"), // discrete 8.05MHz YM3438
CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, "clockSel=4"), // ^^ CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, "clockSel=4"), // ^^
CH(DIV_SYSTEM_RF5C68, 1.0f, 0, "clockSel=2") // 12.5MHz CH(DIV_SYSTEM_RF5C68, 1.0f, 0,
"clockSel=2\n"
"chipType=1\n"
) // 12.5MHz
} }
); );
ENTRY( ENTRY(
"Sega System 32 (extended channel 3 on both OPN2Cs)", { "Sega System 32 (extended channel 3 on both OPN2Cs)", {
CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, "clockSel=4"), // discrete 8.05MHz YM3438 CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, "clockSel=4"), // discrete 8.05MHz YM3438
CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, "clockSel=4"), // ^^ CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, "clockSel=4"), // ^^
CH(DIV_SYSTEM_RF5C68, 1.0f, 0, "clockSel=2") // 12.5MHz CH(DIV_SYSTEM_RF5C68, 1.0f, 0,
"clockSel=2\n"
"chipType=1\n"
) // 12.5MHz
} }
); );
ENTRY( ENTRY(

View file

@ -2090,6 +2090,11 @@ void FurnaceGUI::drawSettings() {
} }
ImGui::Unindent(); ImGui::Unindent();
bool capitalMenuBarB=settings.capitalMenuBar;
if (ImGui::Checkbox("Capitalize menu bar",&capitalMenuBarB)) {
settings.capitalMenuBar=capitalMenuBarB;
}
// SUBSECTION ORDERS // SUBSECTION ORDERS
CONFIG_SUBSECTION("Orders"); CONFIG_SUBSECTION("Orders");
// sorry. temporarily disabled until ImGui has a way to add separators in tables arbitrarily. // sorry. temporarily disabled until ImGui has a way to add separators in tables arbitrarily.
@ -2312,6 +2317,11 @@ void FurnaceGUI::drawSettings() {
settings.insEditColorize=insEditColorizeB; settings.insEditColorize=insEditColorizeB;
} }
bool insTypeMenuB=settings.insTypeMenu;
if (ImGui::Checkbox("Display instrument type menu when adding instrument",&insTypeMenuB)) {
settings.insTypeMenu=insTypeMenuB;
}
// SUBSECTION MACRO EDITOR // SUBSECTION MACRO EDITOR
CONFIG_SUBSECTION("Macro Editor"); CONFIG_SUBSECTION("Macro Editor");
ImGui::Text("Macro editor layout:"); ImGui::Text("Macro editor layout:");
@ -3048,6 +3058,8 @@ void FurnaceGUI::syncSettings() {
settings.removeInsOff=e->getConfInt("removeInsOff",0); settings.removeInsOff=e->getConfInt("removeInsOff",0);
settings.removeVolOff=e->getConfInt("removeVolOff",0); settings.removeVolOff=e->getConfInt("removeVolOff",0);
settings.playOnLoad=e->getConfInt("playOnLoad",0); settings.playOnLoad=e->getConfInt("playOnLoad",0);
settings.insTypeMenu=e->getConfInt("insTypeMenu",1);
settings.capitalMenuBar=e->getConfInt("capitalMenuBar",0);
clampSetting(settings.mainFontSize,2,96); clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.headFontSize,2,96); clampSetting(settings.headFontSize,2,96);
@ -3182,6 +3194,8 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.removeInsOff,0,1); clampSetting(settings.removeInsOff,0,1);
clampSetting(settings.removeVolOff,0,1); clampSetting(settings.removeVolOff,0,1);
clampSetting(settings.playOnLoad,0,2); clampSetting(settings.playOnLoad,0,2);
clampSetting(settings.insTypeMenu,0,1);
clampSetting(settings.capitalMenuBar,0,1);
if (settings.exportLoops<0.0) settings.exportLoops=0.0; if (settings.exportLoops<0.0) settings.exportLoops=0.0;
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0; if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
@ -3416,6 +3430,8 @@ void FurnaceGUI::commitSettings() {
e->setConf("removeInsOff",settings.removeInsOff); e->setConf("removeInsOff",settings.removeInsOff);
e->setConf("removeVolOff",settings.removeVolOff); e->setConf("removeVolOff",settings.removeVolOff);
e->setConf("playOnLoad",settings.playOnLoad); e->setConf("playOnLoad",settings.playOnLoad);
e->setConf("insTypeMenu",settings.insTypeMenu);
e->setConf("capitalMenuBar",settings.capitalMenuBar);
// colors // colors
for (int i=0; i<GUI_COLOR_MAX; i++) { for (int i=0; i<GUI_COLOR_MAX; i++) {

View file

@ -395,6 +395,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
int clockSel=flags.getInt("clockSel",0); int clockSel=flags.getInt("clockSel",0);
int patchSet=flags.getInt("patchSet",0); int patchSet=flags.getInt("patchSet",0);
bool noTopHatFreq=flags.getBool("noTopHatFreq",false); bool noTopHatFreq=flags.getBool("noTopHatFreq",false);
bool fixedAll=flags.getBool("fixedAll",false);
ImGui::Text("Clock rate:"); ImGui::Text("Clock rate:");
ImGui::Indent(); ImGui::Indent();
@ -441,6 +442,9 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
if (ImGui::Checkbox("Ignore top/hi-hat frequency changes",&noTopHatFreq)) { if (ImGui::Checkbox("Ignore top/hi-hat frequency changes",&noTopHatFreq)) {
altered=true; altered=true;
} }
if (ImGui::Checkbox("Apply fixed frequency to all drums at once",&fixedAll)) {
altered=true;
}
} }
if (altered) { if (altered) {
@ -450,6 +454,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
flags.set("patchSet",patchSet); flags.set("patchSet",patchSet);
} }
flags.set("noTopHatFreq",noTopHatFreq); flags.set("noTopHatFreq",noTopHatFreq);
flags.set("fixedAll",fixedAll);
}); });
} }
break; break;