Merge branch 'master' into doc-general

This commit is contained in:
Electric Keet 2023-08-10 16:51:01 -07:00
commit 9f53463ec2
47 changed files with 1800 additions and 143 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**
- changing this may help with performace issues.
- **Late render clear**
- **Power-saving mode**
- saves power by lowering the frame rate to 2fps when idle.
- **Power-saving mode**: saves power by lowering the frame rate to 2fps when idle.
- may cause issues under Mesa drivers!
- **Disable threaded input (restart after changing!)**
- threaded input processes key presses for note preview on a separate thread (on supported platforms), which reduces latency.
- **Disable threaded input (restart after changing!)**: 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.
- **Enable event delay**
- may cause issues with high-polling-rate mice when previewing notes.
### File
- **Use system file picker**: use native OS file dialog instead of Furnace's.
- **Number of recent files**
- **Use system file picker**: uses native OS file dialog instead of Furnace's.
- **Number of recent files**: number of files to show in the _open recent..._ menu.
- **Compress when saving**
- use zlib to compress saved songs.
- uses zlib to compress saved songs.
- **Save unused patterns**
- **Use new pattern format when saving**
- **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.
- **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.
- **Reset to defaults**: sets default to "Sega Genesis/Mega Drive".
- **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**:
- **Display system preset selector**
- **Start with initial system**
@ -70,12 +68,12 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
### 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
- **Driver**
- **Device**: audio device for playback.
- **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.
- **Channels**: number of output channels to use.
- **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.
- **Reset**: resets layout to default.
- **Allow docking editors**
- **Remember window position**
- remembers the window's last position on start-up.
- **Remember window position**: remembers the window's last position on start-up.
- **Only allow window movement when clicking on title bar**
- **Play/edit controls layout:**
- **Classic**
@ -236,7 +233,7 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **No**
- **Yes**
- **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
- 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**
- **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 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:**
- **Move down**
- **Move to effect value (otherwise move down)**
- **Move to effect value/next effect and wrap around**
- **Delete effect value when deleting effect**
- **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
@ -293,16 +292,17 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
### Scaling
- **Automatic UI scaling factor**: automatically match the OS's UI scaling.
- **UI scaling factor**: only if "Automatic UI scaling factor" is off.
- **Automatic UI scaling factor**: automatically matches the OS's UI scaling.
- **UI scaling factor**: only appears if "Automatic UI scaling factor" is off.
- **Icon size**
### Text
- **Main font**: if "Custom...", a file path selector will appear beneath.
- **Size**
- **Pattern font**: if "Custom...", a file path selector will appear beneath.
- **Size**
- **Main font**: overall interface font.\
**Header font**: font for section headers.\
**Pattern font** font for the pattern view, the order list, and related.
- if "Custom...", a file path selector will appear.
- **Size**: font size.
- **Display Japanese characters**\
**Display Chinese (Simplified) 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 style:**
- **Channel style:** sets the appearance of channel headers in pattern view.
- **Classic**
- **Line**
- **Round**
@ -428,11 +428,11 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **Between Decay and Sustain Rate**
- **After Release Rate**
- **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
- **Chip memory usage unit:**
- **Chip memory usage unit:** unit for displaying memory usage in the Statistics window.
- **Bytes**
- **Kilobytes**
@ -440,15 +440,20 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
- **Rounded corners**
- **Border**
- **Fill entire window**
- **Waveform goes out of bounds**
- **Mono**: displays a single monaural waveform of all sound mixed together.
- 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
- **Rounded window corners**
- **Rounded buttons**
- **Rounded menu corners**
- **Borders around widgets**
- **Borders around widgets**: draws thin borders on buttons, checkboxes, text widgets, and the like.

View File

@ -97,7 +97,9 @@
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
#ifndef IS_MOBILE
#define ImDrawIdx unsigned int
#endif
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;

View File

@ -96,7 +96,9 @@
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
#ifndef IS_MOBILE
#define ImDrawIdx unsigned int
#endif
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;

View File

@ -532,6 +532,9 @@ nfdresult_t NFD_OpenDialogMultiple( const std::vector<std::string>& filterList,
nfdselcallback_t selCallback )
{
nfdresult_t nfdResult = NFD_ERROR;
NFDWinEvents* winEvents;
bool hasEvents=true;
DWORD eventID=0;
HRESULT coResult = COMInit();
@ -566,6 +569,16 @@ nfdresult_t NFD_OpenDialogMultiple( const std::vector<std::string>& filterList,
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
DWORD dwFlags;
result = fileOpenDialog->GetOptions(&dwFlags);
@ -613,8 +626,12 @@ nfdresult_t NFD_OpenDialogMultiple( const std::vector<std::string>& filterList,
}
end:
if ( fileOpenDialog )
if (fileOpenDialog) {
if (hasEvents) {
fileOpenDialog->Unadvise(eventID);
}
fileOpenDialog->Release();
}
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);
/**
* test whether volume is global.
* @return whether it is.
*/
virtual bool isVolGlobal();
/**
* get the lowest note in a portamento.
* @param ch the channel in question.

View File

@ -216,13 +216,6 @@ void DivDispatchContainer::clear() {
if (dispatch->getDCOffRequired()) {
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) {
@ -479,7 +472,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
break;
case DIV_SYSTEM_NAMCO:
dispatch=new DivPlatformNamcoWSG;
// Pac-Man (TODO: support Pole Position?)
// Pac-Man
((DivPlatformNamcoWSG*)dispatch)->setDeviceType(1);
break;
case DIV_SYSTEM_NAMCO_15XX:

View File

@ -2346,7 +2346,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
}
}
if (ds.version>=136) song.patchbayAuto=reader.readC();
if (ds.version>=136) ds.patchbayAuto=reader.readC();
if (ds.version>=138) {
ds.brokenPortaLegato=reader.readC();

View File

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

View File

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

View File

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

View File

@ -28,6 +28,8 @@
#define CHIP_FREQBASE 1180068
#define DRUM_VOL(_x) (drumActivated[_x]?drumVol[_x]:15)
const unsigned char cycleMapOPLL[18]={
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();
if (w.addrOrVal) {
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;
writes.pop();
delay=21;
@ -104,10 +106,10 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (i>=6 && properDrums) {
drumVol[i-6]=15-chan[i].outVol;
rWrite(0x36,drumVol[0]);
rWrite(0x37,drumVol[1]|(drumVol[4]<<4));
rWrite(0x38,drumVol[3]|(drumVol[2]<<4));
} else if (i<6 || !drums) {
rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
} else if (i<6 || !crapDrums) {
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));
}
@ -230,16 +232,16 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (i>=6 && properDrums) {
drumState&=~(0x10>>(i-6));
immWrite(0x0e,0x20|drumState);
logV("properDrums %d",i);
} else if (i>=6 && drums) {
//logV("properDrums %d",i);
} else if (i>=6 && crapDrums) {
drumState&=~(0x10>>(chan[i].note%12));
immWrite(0x0e,0x20|drumState);
logV("drums %d",i);
//logV("drums %d",i);
} else {
if (i<9) {
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].keyOff=false;
@ -265,7 +267,21 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (i>=6 && properDrums && (i<9 || !noTopHatFreq)) {
immWrite(0x10+drumSlot[i],freqt&0xff);
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) {
immWrite(0x10+i,freqt&0xff);
}
@ -278,7 +294,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
immWrite(0x0e,0x20|drumState);
}
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);
drumState|=(0x10>>(chan[i].note%12));
immWrite(0x0e,0x20|drumState);
@ -365,22 +381,24 @@ void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) {
}
if (chan[ch].state.opllPreset==16) { // compatible drums mode
if (ch>=6) {
drums=true;
immWrite(0x16,0x20);
immWrite(0x26,0x05);
immWrite(0x16,0x20);
immWrite(0x26,0x05);
immWrite(0x17,0x50);
immWrite(0x27,0x05);
immWrite(0x17,0x50);
immWrite(0x27,0x05);
immWrite(0x18,0xC0);
immWrite(0x28,0x01);
if (!properDrumsSys) {
crapDrums=true;
immWrite(0x16,0x20);
immWrite(0x26,0x05);
immWrite(0x16,0x20);
immWrite(0x26,0x05);
immWrite(0x17,0x50);
immWrite(0x27,0x05);
immWrite(0x17,0x50);
immWrite(0x27,0x05);
immWrite(0x18,0xC0);
immWrite(0x28,0x01);
}
}
} else {
if (ch>=6) {
if (drums) {
drums=false;
if (crapDrums) {
crapDrums=false;
immWrite(0x0e,0);
drumState=0;
}
@ -395,10 +413,40 @@ void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) {
void DivPlatformOPLL::switchMode(bool mode) {
if (mode==properDrums) return;
if (mode) {
//logV("mode switch to DRUMS");
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) {
@ -417,18 +465,31 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
if (c.chan>=6 && properDrums) { // drums mode
chan[c.chan].insChanged=false;
drumActivated[c.chan-6]=true;
if (c.value!=DIV_NOTE_NULL) {
if (chan[c.chan].state.opllPreset==16 && chan[c.chan].state.fixedDrums) {
switch (c.chan) {
case 6:
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&511)<<(chan[c.chan].state.kickFreq>>9);
break;
case 7: case 10:
chan[c.chan].fixedFreq=(chan[c.chan].state.snareHatFreq&511)<<(chan[c.chan].state.snareHatFreq>>9);
break;
case 8: case 9:
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&511)<<(chan[c.chan].state.tomTopFreq>>9);
break;
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) {
case 6:
chan[c.chan].fixedFreq=(chan[c.chan].state.kickFreq&511)<<(chan[c.chan].state.kickFreq>>9);
break;
case 7: case 10:
chan[c.chan].fixedFreq=(chan[c.chan].state.snareHatFreq&511)<<(chan[c.chan].state.snareHatFreq>>9);
break;
case 8: case 9:
chan[c.chan].fixedFreq=(chan[c.chan].state.tomTopFreq&511)<<(chan[c.chan].state.tomTopFreq>>9);
break;
}
}
} else {
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].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;
}
@ -448,7 +513,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].note=c.value;
if (c.chan>=6 && drums) {
if (c.chan>=6 && crapDrums) {
switch (chan[c.chan].note%12) {
case 0: // kick
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);
break;
}
rWrite(0x36,drumVol[0]);
rWrite(0x37,drumVol[1]|(drumVol[4]<<4));
rWrite(0x38,drumVol[3]|(drumVol[2]<<4));
rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
}
chan[c.chan].freqChanged=true;
}
@ -503,11 +568,11 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
}
if (c.chan>=6 && properDrums) {
drumVol[c.chan-6]=15-chan[c.chan].outVol;
rWrite(0x36,drumVol[0]);
rWrite(0x37,drumVol[1]|(drumVol[4]<<4));
rWrite(0x38,drumVol[3]|(drumVol[2]<<4));
rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<4));
rWrite(0x38,DRUM_VOL(3)|(DRUM_VOL(2)<<4));
break;
} else if (c.chan<6 || !drums) {
} else if (c.chan<6 || !crapDrums) {
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));
}
@ -565,7 +630,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
}
case DIV_CMD_LEGATO: {
if (c.chan>=9 && !properDrums) return 0;
if (c.chan<6 || (!drums && !properDrums)) {
if (c.chan<6 || (!crapDrums && !properDrums)) {
if (chan[c.chan].insChanged) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL);
commitState(c.chan,ins);
@ -780,12 +845,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
case DIV_CMD_FM_EXTCH:
if (!properDrumsSys) break;
if ((int)properDrums==c.value) break;
if (c.value) {
properDrums=true;
} else {
properDrums=false;
}
switchMode(properDrums);
switchMode(c.value);
break;
case DIV_CMD_MACRO_OFF:
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(0x26,0x05);
immWrite(0x16,0x20);
@ -852,11 +912,25 @@ void DivPlatformOPLL::forceIns() {
immWrite(0x18,0xC0);
immWrite(0x28,0x01);
}
// restore drum volumes
// restore drum volumes and state
if (properDrums) {
rWrite(0x36,drumVol[0]);
rWrite(0x37,drumVol[1]|(drumVol[4]<<4));
rWrite(0x38,drumVol[3]|(drumVol[2]<<4));
rWrite(0x36,DRUM_VOL(0));
rWrite(0x37,DRUM_VOL(1)|(DRUM_VOL(4)<<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;
}
@ -937,16 +1011,18 @@ void DivPlatformOPLL::reset() {
drumState=0;
lastCustomMemory=-1;
drumVol[0]=0;
drumVol[1]=0;
drumVol[2]=0;
drumVol[3]=0;
drumVol[4]=0;
for (int i=0; i<5; i++) {
drumVol[i]=0;
drumActivated[i]=true;
}
delay=0;
drums=false;
crapDrums=false;
properDrums=properDrumsSys;
lastFreqSH=-1;
lastFreqTT=-1;
if (properDrums) {
immWrite(0x0e,0x20);
}
@ -1012,6 +1088,7 @@ void DivPlatformOPLL::setFlags(const DivConfig& flags) {
oscBuf[i]->rate=rate/2;
}
noTopHatFreq=flags.getBool("noTopHatFreq",false);
fixedAll=flags.getBool("fixedAll",false);
}
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 drumState;
unsigned char drumVol[5];
bool drumActivated[5];
// -1: undefined
// 0: snare/tom
// 1: hi-hat/top
signed char lastFreqSH, lastFreqTT;
unsigned char regPool[256];
bool useYMFM;
bool drums;
bool properDrums, properDrumsSys, noTopHatFreq;
bool crapDrums;
bool properDrums, properDrumsSys, noTopHatFreq, fixedAll;
bool vrc7;
unsigned char patchSet;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -131,6 +131,7 @@ void FurnaceGUI::drawChanOsc() {
if (ImGui::BeginTable("ChanOscSettings",3)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Columns");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -154,6 +155,7 @@ void FurnaceGUI::drawChanOsc() {
}
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Automatic columns");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -169,6 +171,7 @@ void FurnaceGUI::drawChanOsc() {
ImGui::EndTable();
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Amplitude");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -261,6 +264,7 @@ void FurnaceGUI::drawChanOsc() {
if (ImGui::ColorPicker4("Color",(float*)&i.color)) {
updateChanOscGradTex=true;
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Distance");
ImGui::SameLine();
float pDist=i.distance*100.0f;
@ -269,6 +273,7 @@ void FurnaceGUI::drawChanOsc() {
updateChanOscGradTex=true;
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Spread");
ImGui::SameLine();
float pSpread=i.spread*100.0f;
@ -313,6 +318,7 @@ void FurnaceGUI::drawChanOsc() {
ImGui::ColorPicker4("Color",(float*)&chanOscColor);
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Text format:");
ImGui::SameLine();
ImGui::InputText("##TextFormat",&chanOscTextFormat);

View File

@ -199,6 +199,7 @@ void FurnaceGUI::drawCompatFlags() {
}
if (ImGui::BeginTabItem("Pitch/Playback")) {
ImGui::Text("Pitch linearity:");
ImGui::Indent();
if (ImGui::RadioButton("None",e->song.linearPitch==0)) {
e->song.linearPitch=0;
}
@ -217,6 +218,7 @@ void FurnaceGUI::drawCompatFlags() {
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("like Impulse Tracker");
}
ImGui::Unindent();
if (e->song.linearPitch==2) {
ImGui::SameLine();
@ -228,6 +230,7 @@ void FurnaceGUI::drawCompatFlags() {
}
ImGui::Text("Loop modality:");
ImGui::Indent();
if (ImGui::RadioButton("Reset channels",e->song.loopModality==0)) {
e->song.loopModality=0;
}
@ -246,8 +249,10 @@ void FurnaceGUI::drawCompatFlags() {
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("select to not reset channels on loop.");
}
ImGui::Unindent();
ImGui::Text("Cut/delay effect policy:");
ImGui::Indent();
if (ImGui::RadioButton("Strict",e->song.delayBehavior==0)) {
e->song.delayBehavior=0;
}
@ -266,8 +271,10 @@ void FurnaceGUI::drawCompatFlags() {
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("no checks");
}
ImGui::Unindent();
ImGui::Text("Simultaneous jump (0B+0D) treatment:");
ImGui::Indent();
if (ImGui::RadioButton("Normal",e->song.jumpTreatment==0)) {
e->song.jumpTreatment=0;
}
@ -286,6 +293,7 @@ void FurnaceGUI::drawCompatFlags() {
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("only accept 0Dxx");
}
ImGui::Unindent();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Other")) {

View File

@ -486,6 +486,7 @@ void FurnaceGUI::drawDebug() {
pgProgram.clear();
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Address");
ImGui::SameLine();
ImGui::SetNextItemWidth(100.0f*dpiScale);

View File

@ -589,14 +589,34 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_PAT_EXPAND_SONG:
doExpandSong(collapseAmount);
break;
case GUI_ACTION_PAT_LATCH: // TODO
case GUI_ACTION_PAT_LATCH: {
DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],true);
latchIns=pat->data[cursor.y][2];
latchVol=pat->data[cursor.y][3];
latchEffect=pat->data[cursor.y][4];
latchEffectVal=pat->data[cursor.y][5];
latchTarget=0;
latchNibble=false;
break;
case GUI_ACTION_PAT_SCROLL_MODE: // TODO
break;
case GUI_ACTION_PAT_CLEAR_LATCH: // TODO
}
case GUI_ACTION_PAT_CLEAR_LATCH:
latchIns=-2;
latchVol=-1;
latchEffect=-1;
latchEffectVal=-1;
latchTarget=0;
latchNibble=false;
break;
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);
if (curIns==-1) {
showError("too many instruments!");
@ -1265,7 +1285,7 @@ void FurnaceGUI::doAction(int what) {
} else if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
for (unsigned int i=start; i<end; i++) {
sample->data8[i]=-sample->data8[i];
if (sample->data16[i]==-128) sample->data16[i]=127;
if (sample->data8[i]==-128) sample->data8[i]=127;
}
}

View File

@ -619,6 +619,7 @@ void FurnaceGUI::drawMobileControls() {
"Furnace Amiga emulator is working properly by\n"
"comparing it with real Amiga output."
);
ImGui::AlignTextToFramePadding();
ImGui::Text("Directory");
ImGui::SameLine();
ImGui::InputText("##AVDPath",&workingDirROMExport);
@ -717,6 +718,7 @@ void FurnaceGUI::drawEditControls() {
e->setMetronome(metro);
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Follow");
ImGui::SameLine();
unimportant(ImGui::Checkbox("Orders",&followOrders));
@ -1063,6 +1065,7 @@ void FurnaceGUI::drawEditControls() {
if (ImGui::Begin("Edit Controls",&editControlsOpen,globalWinFlags)) {
ImGui::Columns(2);
ImGui::AlignTextToFramePadding();
ImGui::Text("Octave");
ImGui::SameLine();
float cursor=ImGui::GetCursorPosX();
@ -1078,6 +1081,7 @@ void FurnaceGUI::drawEditControls() {
}
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Step");
ImGui::SameLine();
ImGui::SetCursorPosX(cursor);

View File

@ -68,7 +68,7 @@ void FurnaceGUI::prepareUndo(ActionType action) {
}
break;
case GUI_UNDO_PATTERN_COLLAPSE_SONG:
case GUI_UNDO_PATTERN_EXPAND_SONG: // TODO
case GUI_UNDO_PATTERN_EXPAND_SONG: // this is handled by doCollapseSong/doExpandSong
break;
case GUI_UNDO_REPLACE: // this is handled by doReplace()
break;
@ -134,7 +134,7 @@ void FurnaceGUI::makeUndo(ActionType action) {
}
break;
case GUI_UNDO_PATTERN_COLLAPSE_SONG:
case GUI_UNDO_PATTERN_EXPAND_SONG: // TODO
case GUI_UNDO_PATTERN_EXPAND_SONG: // this is handled by doCollapseSong/doExpandSong
break;
case GUI_UNDO_REPLACE: // this is handled by doReplace()
break;

View File

@ -47,22 +47,56 @@ void FurnaceGUI::drawEffectList() {
const char* prevName=NULL;
for (int i=0; i<256; i++) {
const char* name=e->getEffectDesc(i,cursor.xCoarse);
bool effectShow = true;
bool effectShow=true;
if (name==prevName) {
continue;
}
prevName=name;
switch (fxColors[i]) {
case GUI_COLOR_PATTERN_EFFECT_MISC: effectShow = effectsShow[8]; break;
case GUI_COLOR_PATTERN_EFFECT_SONG: effectShow = effectsShow[1]; break;
case GUI_COLOR_PATTERN_EFFECT_SPEED: effectShow = effectsShow[3]; break;
case GUI_COLOR_PATTERN_EFFECT_TIME: effectShow = effectsShow[2]; break;
case GUI_COLOR_PATTERN_EFFECT_PITCH: effectShow = effectsShow[0]; break;
case GUI_COLOR_PATTERN_EFFECT_PANNING: effectShow = effectsShow[4]; break;
case GUI_COLOR_PATTERN_EFFECT_VOLUME: effectShow = effectsShow[5]; break;
case GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY: effectShow = effectsShow[6]; break;
case GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY: effectShow = effectsShow[7]; break;
default: effectShow = true; break;
case GUI_COLOR_PATTERN_EFFECT_MISC:
effectShow=effectsShow[8];
break;
case GUI_COLOR_PATTERN_EFFECT_SONG:
effectShow=effectsShow[1];
break;
case GUI_COLOR_PATTERN_EFFECT_SPEED:
effectShow=effectsShow[3];
break;
case GUI_COLOR_PATTERN_EFFECT_TIME:
effectShow=effectsShow[2];
break;
case GUI_COLOR_PATTERN_EFFECT_PITCH:
effectShow=effectsShow[0];
break;
case GUI_COLOR_PATTERN_EFFECT_PANNING:
effectShow=effectsShow[4];
break;
case GUI_COLOR_PATTERN_EFFECT_VOLUME:
effectShow=effectsShow[5];
break;
case GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY:
effectShow=effectsShow[6];
break;
case GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY:
effectShow=effectsShow[7];
break;
default:
effectShow=true;
break;
}
if (fxColors[i]==GUI_COLOR_PATTERN_EFFECT_PANNING) {
DivDispatch* dispatch=e->getDispatch(e->dispatchOfChan[cursor.xCoarse]);
if (dispatch!=NULL) {
int outputs=dispatch->getOutputCount();
if (outputs<2) {
effectShow=false;
}
if (outputs<3) {
if (i>=0x88 && i<=0x8f) {
effectShow=false;
}
}
}
}
if (name!=NULL && effectShow) {
ImGui::TableNextRow();

View File

@ -28,7 +28,6 @@ struct NFDState {
}
};
// TODO: filter
void _nfdThread(const NFDState state, std::atomic<bool>* ok, std::vector<String>* result, bool* errorOutput) {
nfdchar_t* out=NULL;
nfdresult_t ret=NFD_CANCEL;

View File

@ -595,6 +595,7 @@ void FurnaceGUI::drawFindReplace() {
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.25);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Note");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -662,6 +663,7 @@ void FurnaceGUI::drawFindReplace() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Ins");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -697,6 +699,7 @@ void FurnaceGUI::drawFindReplace() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Volume");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -734,6 +737,7 @@ void FurnaceGUI::drawFindReplace() {
ImGui::PushID(0x1000+j);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Effect");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -769,6 +773,7 @@ void FurnaceGUI::drawFindReplace() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Value");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);

View File

@ -77,6 +77,14 @@ bool Particle::update(float frameTime) {
return (life>0);
}
void FurnaceGUI::centerNextWindow(const char* name, float w, float h) {
if (ImGui::IsPopupOpen(name)) {
if (settings.centerPopup) {
ImGui::SetNextWindowPos(ImVec2(w*0.5,h*0.5),ImGuiCond_Always,ImVec2(0.5,0.5));
}
}
}
void FurnaceGUI::bindEngine(DivEngine* eng) {
e=eng;
wavePreview.setEngine(e);
@ -2783,6 +2791,7 @@ void FurnaceGUI::editOptions(bool topMenu) {
if (ImGui::MenuItem("values up (+16)",BIND_FOR(GUI_ACTION_PAT_VALUE_UP_COARSE))) doTranspose(16,opMaskTransposeValue);
if (ImGui::MenuItem("values down (-16)",BIND_FOR(GUI_ACTION_PAT_VALUE_DOWN_COARSE))) doTranspose(-16,opMaskTransposeValue);
ImGui::Separator();
ImGui::AlignTextToFramePadding();
ImGui::Text("transpose");
ImGui::SameLine();
ImGui::SetNextItemWidth(120.0f*dpiScale);
@ -3918,7 +3927,7 @@ bool FurnaceGUI::loop() {
if (!mobileUI) {
ImGui::BeginMainMenuBar();
if (ImGui::BeginMenu("file")) {
if (ImGui::BeginMenu(settings.capitalMenuBar?"File":"file")) {
if (ImGui::MenuItem("new...",BIND_FOR(GUI_ACTION_NEW))) {
if (modified) {
showWarning("Unsaved changes! Save changes before creating a new song?",GUI_WARN_NEW);
@ -4013,6 +4022,7 @@ bool FurnaceGUI::loop() {
ImGui::Checkbox("loop",&vgmExportLoop);
if (vgmExportLoop && e->song.loopModality==2) {
ImGui::Text("loop trail:");
ImGui::Indent();
if (ImGui::RadioButton("auto-detect",vgmExportTrailingTicks==-1)) {
vgmExportTrailingTicks=-1;
}
@ -4028,6 +4038,7 @@ bool FurnaceGUI::loop() {
if (vgmExportTrailingTicks<0) vgmExportTrailingTicks=0;
}
}
ImGui::Unindent();
}
ImGui::Checkbox("add pattern change hints",&vgmExportPatternHints);
if (ImGui::IsItemHovered()) {
@ -4116,6 +4127,7 @@ bool FurnaceGUI::loop() {
"Furnace Amiga emulator is working properly by\n"
"comparing it with real Amiga output."
);
ImGui::AlignTextToFramePadding();
ImGui::Text("Directory");
ImGui::SameLine();
ImGui::InputText("##AVDPath",&workingDirROMExport);
@ -4241,7 +4253,7 @@ bool FurnaceGUI::loop() {
} else {
exitDisabledTimer=0;
}
if (ImGui::BeginMenu("edit")) {
if (ImGui::BeginMenu(settings.capitalMenuBar?"Edit":"edit")) {
ImGui::Text("...");
ImGui::Separator();
if (ImGui::MenuItem("undo",BIND_FOR(GUI_ACTION_UNDO))) doUndo();
@ -4254,7 +4266,7 @@ bool FurnaceGUI::loop() {
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("settings")) {
if (ImGui::BeginMenu(settings.capitalMenuBar?"Settings":"settings")) {
#ifndef IS_MOBILE
if (ImGui::MenuItem("full screen",BIND_FOR(GUI_ACTION_FULLSCREEN),fullScreen)) {
doAction(GUI_ACTION_FULLSCREEN);
@ -4290,7 +4302,7 @@ bool FurnaceGUI::loop() {
}
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("subsongs",BIND_FOR(GUI_ACTION_WINDOW_SUBSONGS),subSongsOpen)) subSongsOpen=!subSongsOpen;
if (ImGui::MenuItem("speed",BIND_FOR(GUI_ACTION_WINDOW_SPEED),speedOpen)) speedOpen=!speedOpen;
@ -4332,7 +4344,7 @@ bool FurnaceGUI::loop() {
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("debug menu",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) debugOpen=!debugOpen;
if (ImGui::MenuItem("inspector",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) inspectorOpen=!inspectorOpen;
@ -5233,6 +5245,7 @@ bool FurnaceGUI::loop() {
MEASURE_BEGIN(popup);
centerNextWindow("Rendering...",canvasW,canvasH);
if (ImGui::BeginPopupModal("Rendering...",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Please wait...");
if (ImGui::Button("Abort")) {
@ -5260,6 +5273,7 @@ bool FurnaceGUI::loop() {
ImGui::EndPopup();
}
centerNextWindow("Error",canvasW,canvasH);
if (ImGui::BeginPopupModal("Error",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("%s",errorString.c_str());
if (ImGui::Button("OK")) {
@ -5268,6 +5282,7 @@ bool FurnaceGUI::loop() {
ImGui::EndPopup();
}
centerNextWindow("Warning",canvasW,canvasH);
if (ImGui::BeginPopupModal("Warning",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("%s",warnString.c_str());
switch (warnAction) {
@ -5626,6 +5641,19 @@ bool FurnaceGUI::loop() {
wavePreviewInit=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;
}
}
@ -5636,11 +5664,13 @@ bool FurnaceGUI::loop() {
// TODO:
// - multiple selection
// - replace instrument
centerNextWindow("Select Instrument",canvasW,canvasH);
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::AlignTextToFramePadding();
ImGui::Text("this is an instrument bank! select which ones to load:");
ImGui::SameLine();
if (ImGui::Button("All")) {
@ -5713,6 +5743,7 @@ bool FurnaceGUI::loop() {
ImGui::EndPopup();
}
centerNextWindow("Import Raw Sample",canvasW,canvasH);
if (ImGui::BeginPopupModal("Import Raw Sample",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Data type:");
for (int i=0; i<DIV_SAMPLE_DEPTH_MAX; i++) {
@ -5728,6 +5759,7 @@ bool FurnaceGUI::loop() {
}
ImGui::BeginDisabled(pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT);
ImGui::AlignTextToFramePadding();
ImGui::Text("Channels");
ImGui::SameLine();
if (ImGui::InputInt("##RSChans",&pendingRawSampleChannels)) {

View File

@ -1548,6 +1548,9 @@ class FurnaceGUI {
int removeInsOff;
int removeVolOff;
int playOnLoad;
int insTypeMenu;
int capitalMenuBar;
int centerPopup;
unsigned int maxUndoSteps;
String mainFontPath;
String headFontPath;
@ -1710,6 +1713,9 @@ class FurnaceGUI {
removeInsOff(0),
removeVolOff(0),
playOnLoad(0),
insTypeMenu(1),
capitalMenuBar(0),
centerPopup(1),
maxUndoSteps(100),
mainFontPath(""),
headFontPath(""),
@ -2135,6 +2141,8 @@ class FurnaceGUI {
ImVec4 channelColor(int ch);
ImVec4 channelTextColor(int ch);
void centerNextWindow(const char* name, float w, float h);
void readOsc();
void calcChanOsc();

View File

@ -4264,6 +4264,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::EndTabItem();
}
if (ins->type==DIV_INS_C64) if (ImGui::BeginTabItem("C64")) {
ImGui::AlignTextToFramePadding();
ImGui::Text("Waveform");
ImGui::SameLine();
pushToggleColors(ins->c64.triOn);
@ -4348,6 +4349,7 @@ void FurnaceGUI::drawInsEdit() {
P(CWSliderScalar("Cutoff",ImGuiDataType_U16,&ins->c64.cut,&_ZERO,&_TWO_THOUSAND_FORTY_SEVEN)); rightClickable
P(CWSliderScalar("Resonance",ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_FIFTEEN)); rightClickable
ImGui::AlignTextToFramePadding();
ImGui::Text("Filter Mode");
ImGui::SameLine();
pushToggleColors(ins->c64.lp);
@ -5250,6 +5252,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Wave 1");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -5260,6 +5263,7 @@ void FurnaceGUI::drawInsEdit() {
}
if (isSingleWaveFX) {
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Wave 2");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);

View File

@ -244,6 +244,7 @@ void FurnaceGUI::drawMixer() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("%d. %s",i+1,getSystemName(e->song.system[i]));
ImGui::TableNextColumn();
if (ImGui::Checkbox("Invert",&doInvert)) {

View File

@ -100,6 +100,7 @@ void FurnaceGUI::drawPiano() {
}
if (ImGui::BeginPopupContextItem("PianoOptions",ImGuiPopupFlags_MouseButtonLeft)) {
ImGui::Text("Key layout:");
ImGui::Indent();
if (ImGui::RadioButton("Automatic",pianoView==PIANO_LAYOUT_AUTOMATIC)) {
pianoView=PIANO_LAYOUT_AUTOMATIC;
}
@ -109,7 +110,9 @@ void FurnaceGUI::drawPiano() {
if (ImGui::RadioButton("Continuous",pianoView==PIANO_LAYOUT_CONTINUOUS)) {
pianoView=PIANO_LAYOUT_CONTINUOUS;
}
ImGui::Unindent();
ImGui::Text("Value input pad:");
ImGui::Indent();
if (ImGui::RadioButton("Disabled",pianoInputPadMode==PIANO_INPUT_PAD_DISABLE)) {
pianoInputPadMode=PIANO_INPUT_PAD_DISABLE;
}
@ -122,6 +125,7 @@ void FurnaceGUI::drawPiano() {
if (ImGui::RadioButton("Split (always visible)",pianoInputPadMode==PIANO_INPUT_PAD_SPLIT_VISIBLE)) {
pianoInputPadMode=PIANO_INPUT_PAD_SPLIT_VISIBLE;
}
ImGui::Unindent();
ImGui::Checkbox("Share play/edit offset/range",&pianoSharePosition);
ImGui::Checkbox("Read-only (can't input notes)",&pianoReadonly);
ImGui::EndPopup();
@ -377,7 +381,6 @@ void FurnaceGUI::drawPiano() {
pianoOptions=!pianoOptions;
}
// TODO: wave and sample preview
// first check released keys
for (int i=0; i<180; i++) {
int note=i-60;

View File

@ -1407,28 +1407,40 @@ void FurnaceGUI::initSystemPresets() {
"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"), // ^^
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(
"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, 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(
"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_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(
"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"), // ^^
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(

View File

@ -372,6 +372,7 @@ void FurnaceGUI::drawSampleEdit() {
if (sampleInfo) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Type");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -445,6 +446,7 @@ void FurnaceGUI::drawSampleEdit() {
bool coarseChanged=false;
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Hz");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -459,6 +461,7 @@ void FurnaceGUI::drawSampleEdit() {
}
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Note");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -501,6 +504,7 @@ void FurnaceGUI::drawSampleEdit() {
}
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Fine");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -537,6 +541,7 @@ void FurnaceGUI::drawSampleEdit() {
ImGui::TableNextColumn();
ImGui::BeginDisabled(!(doLoop || keepLoopAlive));
keepLoopAlive=false;
ImGui::AlignTextToFramePadding();
ImGui::Text("Mode");
ImGui::SameLine();
pushWarningColor(!warnLoopMode.empty());
@ -560,6 +565,7 @@ void FurnaceGUI::drawSampleEdit() {
popWarningColor();
pushWarningColor(!warnLoopPos.empty());
ImGui::AlignTextToFramePadding();
ImGui::Text("Start");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -585,6 +591,7 @@ void FurnaceGUI::drawSampleEdit() {
ImGui::SetTooltip("%s",warnLoopPos.c_str());
}
ImGui::AlignTextToFramePadding();
ImGui::Text("End");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -1018,6 +1025,7 @@ void FurnaceGUI::drawSampleEdit() {
if (sampleFilterRes<0.0f) sampleFilterRes=0.0f;
if (sampleFilterRes>0.99f) sampleFilterRes=0.99f;
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Power");
ImGui::SameLine();
if (ImGui::RadioButton("1x",sampleFilterPower==1)) {
@ -1601,7 +1609,7 @@ void FurnaceGUI::drawSampleEdit() {
posX=samplePos+pos.x*sampleZoom;
if (posX>(int)sample->samples) posX=-1;
}
posY=(0.5-pos.y/rectSize.y)*((sample->depth==DIV_SAMPLE_DEPTH_8BIT)?255:32767);
posY=(0.5-pos.y/rectSize.y)*((sample->depth==DIV_SAMPLE_DEPTH_8BIT)?255:65535);
if (posX>=0) {
statusBar2=fmt::sprintf("(%d, %d)",posX,posY);
}

View File

@ -239,6 +239,7 @@ const char* specificControls[18]={
#define UI_KEYBIND_CONFIG(what) \
ImGui::TableNextRow(); \
ImGui::TableNextColumn(); \
ImGui::AlignTextToFramePadding();\
ImGui::TextUnformatted(guiActions[what].friendlyName); \
ImGui::TableNextColumn(); \
if (ImGui::Button(fmt::sprintf("%s##KC_" #what,(bindSetPending && bindSetTarget==what)?"Press key...":getKeyName(actionKeys[what])).c_str())) { \
@ -474,6 +475,7 @@ void FurnaceGUI::drawSettings() {
// SUBSECTION CHIP
CONFIG_SUBSECTION("Chip");
ImGui::AlignTextToFramePadding();
ImGui::Text("Initial system:");
ImGui::SameLine();
if (ImGui::Button("Current system")) {
@ -552,6 +554,7 @@ void FurnaceGUI::drawSettings() {
settings.initialSysName="Sega Genesis/Mega Drive";
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Name");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -720,6 +723,7 @@ void FurnaceGUI::drawSettings() {
// SUBSECTION OUTPUT
CONFIG_SUBSECTION("Output");
#ifdef HAVE_JACK
ImGui::AlignTextToFramePadding();
ImGui::Text("Backend");
ImGui::SameLine();
int prevAudioEngine=settings.audioEngine;
@ -731,6 +735,7 @@ void FurnaceGUI::drawSettings() {
#endif
if (settings.audioEngine==DIV_AUDIO_SDL) {
ImGui::AlignTextToFramePadding();
ImGui::Text("Driver");
ImGui::SameLine();
if (ImGui::BeginCombo("##SDLADriver",settings.sdlAudioDriver.empty()?"Automatic":settings.sdlAudioDriver.c_str())) {
@ -749,6 +754,7 @@ void FurnaceGUI::drawSettings() {
}
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Device");
ImGui::SameLine();
String audioDevName=settings.audioDevice.empty()?"<System default>":settings.audioDevice;
@ -764,6 +770,7 @@ void FurnaceGUI::drawSettings() {
ImGui::EndCombo();
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Sample rate");
ImGui::SameLine();
String sr=fmt::sprintf("%d",settings.audioRate);
@ -788,6 +795,7 @@ void FurnaceGUI::drawSettings() {
if (settings.audioChans>16) settings.audioChans=16;
}
} else {
ImGui::AlignTextToFramePadding();
ImGui::Text("Channels");
ImGui::SameLine();
String chStr=(settings.audioChans<1 || settings.audioChans>8)?"What?":nonProAudioOuts[settings.audioChans-1];
@ -801,6 +809,7 @@ void FurnaceGUI::drawSettings() {
}
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Buffer size");
ImGui::SameLine();
String bs=fmt::sprintf("%d (latency: ~%.1fms)",settings.audioBufSize,2000.0*(double)settings.audioBufSize/(double)MAX(1,settings.audioRate));
@ -835,6 +844,7 @@ void FurnaceGUI::drawSettings() {
// SUBSECTION MIXING
CONFIG_SUBSECTION("Mixing");
ImGui::AlignTextToFramePadding();
ImGui::Text("Quality");
ImGui::SameLine();
ImGui::Combo("##Quality",&settings.audioQuality,audioQualities,2);
@ -846,6 +856,7 @@ void FurnaceGUI::drawSettings() {
// SUBSECTION METRONOME
CONFIG_SUBSECTION("Metronome");
ImGui::AlignTextToFramePadding();
ImGui::Text("Metronome volume");
ImGui::SameLine();
if (ImGui::SliderInt("##MetroVol",&settings.metroVol,0,200,"%d%%")) {
@ -859,6 +870,7 @@ void FurnaceGUI::drawSettings() {
CONFIG_SECTION("MIDI") {
// SUBSECTION MIDI INPUT
CONFIG_SUBSECTION("MIDI input");
ImGui::AlignTextToFramePadding();
ImGui::Text("MIDI input");
ImGui::SameLine();
String midiInName=settings.midiInDevice.empty()?"<disabled>":settings.midiInDevice;
@ -947,6 +959,7 @@ void FurnaceGUI::drawSettings() {
}
ImGui::PlotLines("##VolCurveDisplay",curve,128,0,"Volume curve",0.0,127.0,ImVec2(200.0f*dpiScale,200.0f*dpiScale));
ImGui::AlignTextToFramePadding();
ImGui::Text("Actions:");
ImGui::SameLine();
if (ImGui::Button(ICON_FA_PLUS "##AddAction")) {
@ -1109,6 +1122,7 @@ void FurnaceGUI::drawSettings() {
// SUBSECTION MIDI OUTPUT
CONFIG_SUBSECTION("MIDI output");
ImGui::AlignTextToFramePadding();
ImGui::Text("MIDI output");
ImGui::SameLine();
String midiOutName=settings.midiOutDevice.empty()?"<disabled>":settings.midiOutDevice;
@ -1179,40 +1193,49 @@ void FurnaceGUI::drawSettings() {
CONFIG_SECTION("Emulation") {
// SUBSECTION LAYOUT
CONFIG_SUBSECTION("Cores");
ImGui::AlignTextToFramePadding();
ImGui::Text("Arcade/YM2151 core");
ImGui::SameLine();
ImGui::Combo("##ArcadeCore",&settings.arcadeCore,arcadeCores,2);
ImGui::AlignTextToFramePadding();
ImGui::Text("Genesis/YM2612 core");
ImGui::SameLine();
ImGui::Combo("##YM2612Core",&settings.ym2612Core,ym2612Cores,2);
ImGui::AlignTextToFramePadding();
ImGui::Text("SN76489 core");
ImGui::SameLine();
ImGui::Combo("##SNCore",&settings.snCore,snCores,2);
ImGui::AlignTextToFramePadding();
ImGui::Text("NES core");
ImGui::SameLine();
ImGui::Combo("##NESCore",&settings.nesCore,nesCores,2);
ImGui::AlignTextToFramePadding();
ImGui::Text("FDS core");
ImGui::SameLine();
ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2);
ImGui::AlignTextToFramePadding();
ImGui::Text("SID core");
ImGui::SameLine();
ImGui::Combo("##C64Core",&settings.c64Core,c64Cores,3);
ImGui::AlignTextToFramePadding();
ImGui::Text("POKEY core");
ImGui::SameLine();
ImGui::Combo("##POKEYCore",&settings.pokeyCore,pokeyCores,2);
ImGui::AlignTextToFramePadding();
ImGui::Text("OPN/OPNA/OPNB cores");
ImGui::SameLine();
ImGui::Combo("##OPNCore",&settings.opnCore,opnCores,2);
ImGui::Separator();
ImGui::AlignTextToFramePadding();
ImGui::Text("PC Speaker strategy");
ImGui::SameLine();
ImGui::Combo("##PCSOutMethod",&settings.pcSpeakerOutMethod,pcspkrOutMethods,5);
@ -1220,6 +1243,7 @@ void FurnaceGUI::drawSettings() {
ImGui::Separator();
ImGui::Text("Sample ROMs:");
ImGui::AlignTextToFramePadding();
ImGui::Text("OPL4 YRW801 path");
ImGui::SameLine();
ImGui::InputText("##YRW801Path",&settings.yrw801Path);
@ -1228,6 +1252,7 @@ void FurnaceGUI::drawSettings() {
openFileDialog(GUI_FILE_YRW801_ROM_OPEN);
}
ImGui::AlignTextToFramePadding();
ImGui::Text("MultiPCM TG100 path");
ImGui::SameLine();
ImGui::InputText("##TG100Path",&settings.tg100Path);
@ -1236,6 +1261,7 @@ void FurnaceGUI::drawSettings() {
openFileDialog(GUI_FILE_TG100_ROM_OPEN);
}
ImGui::AlignTextToFramePadding();
ImGui::Text("MultiPCM MU5 path");
ImGui::SameLine();
ImGui::InputText("##MU5Path",&settings.mu5Path);
@ -1478,6 +1504,7 @@ void FurnaceGUI::drawSettings() {
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_COLLAPSE_SONG);
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_SONG);
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_LATCH);
UI_KEYBIND_CONFIG(GUI_ACTION_PAT_CLEAR_LATCH);
KEYBIND_CONFIG_END;
ImGui::TreePop();
@ -1604,6 +1631,7 @@ void FurnaceGUI::drawSettings() {
CONFIG_SECTION("Interface") {
// SUBSECTION LAYOUT
CONFIG_SUBSECTION("Layout");
ImGui::AlignTextToFramePadding();
ImGui::Text("Workspace layout:");
ImGui::SameLine();
if (ImGui::Button("Import")) {
@ -1639,6 +1667,11 @@ void FurnaceGUI::drawSettings() {
applyUISettings(false);
}
bool centerPopupB=settings.centerPopup;
if (ImGui::Checkbox("Center pop-up windows",&centerPopupB)) {
settings.centerPopup=centerPopupB;
}
ImGui::Text("Play/edit controls layout:");
ImGui::Indent();
if (ImGui::RadioButton("Classic##ecl0",settings.controlLayout==0)) {
@ -1908,6 +1941,7 @@ void FurnaceGUI::drawSettings() {
// SUBSECTION TEXT
CONFIG_SUBSECTION("Text");
ImGui::AlignTextToFramePadding();
ImGui::Text("Main font");
ImGui::SameLine();
ImGui::Combo("##MainFont",&settings.mainFont,mainFonts,7);
@ -1924,6 +1958,7 @@ void FurnaceGUI::drawSettings() {
if (settings.mainFontSize>96) settings.mainFontSize=96;
}
ImGui::Unindent();
ImGui::AlignTextToFramePadding();
ImGui::Text("Header font");
ImGui::SameLine();
ImGui::Combo("##HeadFont",&settings.headFont,headFonts,7);
@ -1940,6 +1975,7 @@ void FurnaceGUI::drawSettings() {
if (settings.headFontSize>96) settings.headFontSize=96;
}
ImGui::Unindent();
ImGui::AlignTextToFramePadding();
ImGui::Text("Pattern font");
ImGui::SameLine();
ImGui::Combo("##PatFont",&settings.patFont,patFonts,7);
@ -2059,6 +2095,11 @@ void FurnaceGUI::drawSettings() {
}
ImGui::Unindent();
bool capitalMenuBarB=settings.capitalMenuBar;
if (ImGui::Checkbox("Capitalize menu bar",&capitalMenuBarB)) {
settings.capitalMenuBar=capitalMenuBarB;
}
// SUBSECTION ORDERS
CONFIG_SUBSECTION("Orders");
// sorry. temporarily disabled until ImGui has a way to add separators in tables arbitrarily.
@ -2281,6 +2322,11 @@ void FurnaceGUI::drawSettings() {
settings.insEditColorize=insEditColorizeB;
}
bool insTypeMenuB=settings.insTypeMenu;
if (ImGui::Checkbox("Display instrument type menu when adding instrument",&insTypeMenuB)) {
settings.insTypeMenu=insTypeMenuB;
}
// SUBSECTION MACRO EDITOR
CONFIG_SUBSECTION("Macro Editor");
ImGui::Text("Macro editor layout:");
@ -3017,6 +3063,9 @@ void FurnaceGUI::syncSettings() {
settings.removeInsOff=e->getConfInt("removeInsOff",0);
settings.removeVolOff=e->getConfInt("removeVolOff",0);
settings.playOnLoad=e->getConfInt("playOnLoad",0);
settings.insTypeMenu=e->getConfInt("insTypeMenu",1);
settings.capitalMenuBar=e->getConfInt("capitalMenuBar",0);
settings.centerPopup=e->getConfInt("centerPopup",1);
clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.headFontSize,2,96);
@ -3151,6 +3200,9 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.removeInsOff,0,1);
clampSetting(settings.removeVolOff,0,1);
clampSetting(settings.playOnLoad,0,2);
clampSetting(settings.insTypeMenu,0,1);
clampSetting(settings.capitalMenuBar,0,1);
clampSetting(settings.centerPopup,0,1);
if (settings.exportLoops<0.0) settings.exportLoops=0.0;
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
@ -3385,6 +3437,9 @@ void FurnaceGUI::commitSettings() {
e->setConf("removeInsOff",settings.removeInsOff);
e->setConf("removeVolOff",settings.removeVolOff);
e->setConf("playOnLoad",settings.playOnLoad);
e->setConf("insTypeMenu",settings.insTypeMenu);
e->setConf("capitalMenuBar",settings.capitalMenuBar);
e->setConf("centerPopup",settings.centerPopup);
// colors
for (int i=0; i<GUI_COLOR_MAX; i++) {
@ -3813,14 +3868,10 @@ void FurnaceGUI::popWarningColor() {
#ifdef _WIN32
#define SYSTEM_FONT_PATH_1 "C:\\Windows\\Fonts\\segoeui.ttf"
#define SYSTEM_FONT_PATH_2 "C:\\Windows\\Fonts\\tahoma.ttf"
// TODO!
#define SYSTEM_FONT_PATH_3 "C:\\Windows\\Fonts\\tahoma.ttf"
// TODO!
#define SYSTEM_FONT_PATH_3 "C:\\Windows\\Fonts\\micross.ttf"
#define SYSTEM_HEAD_FONT_PATH_1 "C:\\Windows\\Fonts\\segoeui.ttf"
#define SYSTEM_HEAD_FONT_PATH_2 "C:\\Windows\\Fonts\\tahoma.ttf"
// TODO!
#define SYSTEM_HEAD_FONT_PATH_3 "C:\\Windows\\Fonts\\tahoma.ttf"
// TODO!
#define SYSTEM_HEAD_FONT_PATH_3 "C:\\Windows\\Fonts\\micross.ttf"
#define SYSTEM_PAT_FONT_PATH_1 "C:\\Windows\\Fonts\\consola.ttf"
#define SYSTEM_PAT_FONT_PATH_2 "C:\\Windows\\Fonts\\cour.ttf"
// GOOD LUCK WITH THIS ONE - UNTESTED
@ -4234,7 +4285,6 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
mainFont->EllipsisCharCount=3;
}
// TODO: allow changing these colors.
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir,"",uiColors[GUI_COLOR_FILE_DIR],ICON_FA_FOLDER_O);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile,"",uiColors[GUI_COLOR_FILE_OTHER],ICON_FA_FILE_O);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fur",uiColors[GUI_COLOR_FILE_SONG_NATIVE],ICON_FA_FILE);

View File

@ -36,6 +36,7 @@ void FurnaceGUI::drawSongInfo(bool asChild) {
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Name");
ImGui::TableNextColumn();
float avail=ImGui::GetContentRegionAvail().x;
@ -59,6 +60,7 @@ void FurnaceGUI::drawSongInfo(bool asChild) {
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Author");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
@ -68,6 +70,7 @@ void FurnaceGUI::drawSongInfo(bool asChild) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Album");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
@ -77,6 +80,7 @@ void FurnaceGUI::drawSongInfo(bool asChild) {
if (!basicMode) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("System");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(MAX(16.0f*dpiScale,avail-autoButtonSize-ImGui::GetStyle().ItemSpacing.x));
@ -112,6 +116,7 @@ void FurnaceGUI::drawSongInfo(bool asChild) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Tuning (A-4)");
ImGui::TableNextColumn();
float tune=e->song.tuning;

View File

@ -37,6 +37,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
if (ImGui::SmallButton(tempoView?"Base Tempo##TempoOrHz":"Tick Rate##TempoOrHz")) {
tempoView=!tempoView;
}
@ -74,6 +75,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
if (keepGrooveAlive || e->curSubSong->speeds.len>2) {
if (ImGui::SmallButton("Groove")) {
e->lockEngine([this]() {
@ -163,6 +165,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
if (!basicMode) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Virtual Tempo");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(halfAvail);
@ -185,6 +188,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Divider");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(halfAvail);
@ -200,6 +204,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Highlight");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(halfAvail);
@ -222,6 +227,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Pattern Length");
ImGui::TableNextColumn();
float avail=ImGui::GetContentRegionAvail().x;
@ -236,6 +242,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
if (!basicMode) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Song Length");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);

View File

@ -32,6 +32,7 @@ void FurnaceGUI::drawStats() {
size_t lastProcTime=e->processTime;
double maxGot=1000000000.0*(double)e->getAudioDescGot().bufsize/(double)e->getAudioDescGot().rate;
String procStr=fmt::sprintf("%.1f%%",100.0*((double)lastProcTime/(double)maxGot));
ImGui::AlignTextToFramePadding();
ImGui::Text("Audio load");
ImGui::SameLine();
ImGui::ProgressBar((double)lastProcTime/maxGot,ImVec2(-FLT_MIN,0),procStr.c_str());
@ -47,6 +48,7 @@ void FurnaceGUI::drawStats() {
} else {
usageStr=fmt::sprintf("%d/%d",usage,capacity);
}
ImGui::AlignTextToFramePadding();
ImGui::Text("%s [%d]", e->getSystemName(e->song.system[i]), j);
ImGui::SameLine();
ImGui::ProgressBar(((float)usage)/((float)capacity),ImVec2(-FLT_MIN,0),usageStr.c_str());

View File

@ -127,6 +127,7 @@ void FurnaceGUI::drawSubSongs(bool asChild) {
ImGui::SetTooltip("Remove");
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Name");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);

View File

@ -395,6 +395,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
int clockSel=flags.getInt("clockSel",0);
int patchSet=flags.getInt("patchSet",0);
bool noTopHatFreq=flags.getBool("noTopHatFreq",false);
bool fixedAll=flags.getBool("fixedAll",false);
ImGui::Text("Clock rate:");
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)) {
altered=true;
}
if (ImGui::Checkbox("Apply fixed frequency to all drums at once",&fixedAll)) {
altered=true;
}
}
if (altered) {
@ -450,6 +454,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
flags.set("patchSet",patchSet);
}
flags.set("noTopHatFreq",noTopHatFreq);
flags.set("fixedAll",fixedAll);
});
}
break;
@ -1602,7 +1607,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
}
break;
}
case DIV_SYSTEM_SNES: { // TODO: echo
case DIV_SYSTEM_SNES: {
char temp[64];
int vsL=127-(flags.getInt("volScaleL",0)&127);
int vsR=127-(flags.getInt("volScaleR",0)&127);

View File

@ -60,8 +60,7 @@ bool FurnaceGUI::parseSysEx(unsigned char* data, size_t len) {
op.rs=reader.readC();
reader.readC(); // EBS - ignore
op.am=reader.readC();
// TODO: don't ignore after I add KVS to Furnace
reader.readC(); // KVS - ignore
op.kvs=(reader.readC()>2)?1:0;
op.tl=3+((99-reader.readC())*124)/99;
unsigned char freq=reader.readC();
logV("OP%d freq: %d",i,freq);

View File

@ -593,6 +593,7 @@ void FurnaceGUI::drawWaveEdit() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Duty");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -602,6 +603,7 @@ void FurnaceGUI::drawWaveEdit() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Exponent");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -611,6 +613,7 @@ void FurnaceGUI::drawWaveEdit() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("XOR Point");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
@ -630,6 +633,7 @@ void FurnaceGUI::drawWaveEdit() {
for (int i=0; i<16; i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("%d",i+1);
ImGui::TableNextColumn();
ImGui::PushID(140+i);
@ -683,6 +687,7 @@ void FurnaceGUI::drawWaveEdit() {
for (int i=0; i<4; i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("%d",i+1);
ImGui::TableNextColumn();
@ -727,6 +732,7 @@ void FurnaceGUI::drawWaveEdit() {
for (int i=0; i<4; i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("%d",i+1);
ImGui::TableNextColumn();
@ -760,6 +766,7 @@ void FurnaceGUI::drawWaveEdit() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("1");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##ConO1",&waveGenFMCon0[0])) {
@ -784,6 +791,7 @@ void FurnaceGUI::drawWaveEdit() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("2");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con11",&waveGenFMCon1[0])) {
@ -808,6 +816,7 @@ void FurnaceGUI::drawWaveEdit() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("3");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con21",&waveGenFMCon2[0])) {
@ -832,6 +841,7 @@ void FurnaceGUI::drawWaveEdit() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("4");
ImGui::TableNextColumn();
if (ImGui::Checkbox("##Con31",&waveGenFMCon3[0])) {