Merge branch 'master' into feature/More-OPL-Patch-Support
This commit is contained in:
commit
ac656f07bb
|
@ -11,6 +11,8 @@ this is a multi-system chiptune tracker.
|
||||||
|
|
||||||
check out the [Releases](https://github.com/tildearrow/furnace/releases) page. available for Windows, macOS and Linux (AppImage).
|
check out the [Releases](https://github.com/tildearrow/furnace/releases) page. available for Windows, macOS and Linux (AppImage).
|
||||||
|
|
||||||
|
[see here](https://nightly.link/tildearrow/furnace/workflows/build/master) for unstable developer builds.
|
||||||
|
|
||||||
## features
|
## features
|
||||||
|
|
||||||
- supports the following systems:
|
- supports the following systems:
|
||||||
|
@ -64,6 +66,8 @@ some people have provided packages for Unix/Unix-like distributions. here's a li
|
||||||
|
|
||||||
[![Build furnace](https://github.com/tildearrow/furnace/actions/workflows/build.yml/badge.svg)](https://github.com/tildearrow/furnace/actions/workflows/build.yml)
|
[![Build furnace](https://github.com/tildearrow/furnace/actions/workflows/build.yml/badge.svg)](https://github.com/tildearrow/furnace/actions/workflows/build.yml)
|
||||||
|
|
||||||
|
if you can't download these artifacts (because GitHub requires you to be logged in), [go here](https://nightly.link/tildearrow/furnace/workflows/build/master) instead.
|
||||||
|
|
||||||
**NOTE: do not download the project's source as a .zip or .tar.gz as these do not include the project's submodules which are necessary to proceed with building. please instead use Git as shown below.**
|
**NOTE: do not download the project's source as a .zip or .tar.gz as these do not include the project's submodules which are necessary to proceed with building. please instead use Git as shown below.**
|
||||||
|
|
||||||
## dependencies
|
## dependencies
|
||||||
|
|
5
TODO.md
5
TODO.md
|
@ -1,7 +1,11 @@
|
||||||
# to-do for 0.6pre1
|
# to-do for 0.6pre1
|
||||||
|
|
||||||
- panning macro
|
- panning macro
|
||||||
|
- single macro for hard-panned chips
|
||||||
|
- two macros for soft-panned ones
|
||||||
- pitch macro
|
- pitch macro
|
||||||
|
- relative mode
|
||||||
|
- test
|
||||||
- piano/input pad
|
- piano/input pad
|
||||||
- note input via piano
|
- note input via piano
|
||||||
- input pad
|
- input pad
|
||||||
|
@ -43,3 +47,4 @@
|
||||||
- settings: OK/Cancel buttons should be always visible
|
- settings: OK/Cancel buttons should be always visible
|
||||||
- Apply button in settings
|
- Apply button in settings
|
||||||
- better FM chip names (number and codename)
|
- better FM chip names (number and codename)
|
||||||
|
- find and replace
|
||||||
|
|
|
@ -274,6 +274,19 @@ size | description
|
||||||
|
|
||||||
# instrument
|
# instrument
|
||||||
|
|
||||||
|
notes:
|
||||||
|
|
||||||
|
- the entire instrument is stored, regardless of instrument type.
|
||||||
|
- the macro range varies depending on the instrument type.
|
||||||
|
- "macro open" indicates whether the macro is collapsed or not in the instrument editor.
|
||||||
|
- FM operator order is:
|
||||||
|
- 1/3/2/4 (internal order) for OPN, OPM, OPZ and OPL 4-op
|
||||||
|
- 1/2/?/? (? = unused) for OPL 2-op and OPLL
|
||||||
|
- meaning of extended macros varies depending on instrument type.
|
||||||
|
- meaning of panning macros varies depending on instrument type:
|
||||||
|
- for hard-panned chips (e.g. FM and Game Boy): left panning is 2-bit panning macro (left/right)
|
||||||
|
- otherwise both left and right panning macros are used
|
||||||
|
|
||||||
```
|
```
|
||||||
size | description
|
size | description
|
||||||
-----|------------------------------------
|
-----|------------------------------------
|
||||||
|
@ -282,17 +295,39 @@ size | description
|
||||||
2 | format version (see header)
|
2 | format version (see header)
|
||||||
1 | instrument type
|
1 | instrument type
|
||||||
| - 0: standard
|
| - 0: standard
|
||||||
| - 1: FM
|
| - 1: FM (OPM/OPN)
|
||||||
| - 2: Game Boy
|
| - 2: Game Boy
|
||||||
| - 3: C64
|
| - 3: C64
|
||||||
| - 4: Amiga/sample
|
| - 4: Amiga/sample
|
||||||
|
| - 5: PC Engine
|
||||||
|
| - 6: AY-3-8910
|
||||||
|
| - 7: AY8930
|
||||||
|
| - 8: TIA
|
||||||
|
| - 9: SAA1099
|
||||||
|
| - 10: VIC
|
||||||
|
| - 11: PET
|
||||||
|
| - 12: VRC6
|
||||||
|
| - 13: OPLL
|
||||||
|
| - 14: OPL
|
||||||
|
| - 15: FDS
|
||||||
|
| - 16: Virtual Boy
|
||||||
|
| - 17: Namco 163
|
||||||
|
| - 18: SCC
|
||||||
|
| - 19: OPZ
|
||||||
|
| - 20: POKEY
|
||||||
|
| - 21: PC Speaker
|
||||||
|
| - 22: WonderSwan
|
||||||
|
| - 23: Lynx
|
||||||
|
| - 24: VERA
|
||||||
|
| - 25: X1-010
|
||||||
|
| - 26: VRC6 (saw)
|
||||||
1 | reserved
|
1 | reserved
|
||||||
STR | instrument name
|
STR | instrument name
|
||||||
--- | **FM instrument data**
|
--- | **FM instrument data**
|
||||||
1 | alg
|
1 | alg (SUS on OPLL)
|
||||||
1 | feedback
|
1 | feedback
|
||||||
1 | fms
|
1 | fms (DC on OPLL)
|
||||||
1 | ams
|
1 | ams (DM on OPLL)
|
||||||
1 | operator count
|
1 | operator count
|
||||||
| - this is either 2 or 4, and is ignored on non-OPL systems.
|
| - this is either 2 or 4, and is ignored on non-OPL systems.
|
||||||
| - always read 4 ops regardless of this value.
|
| - always read 4 ops regardless of this value.
|
||||||
|
@ -314,10 +349,12 @@ size | description
|
||||||
1 | dt
|
1 | dt
|
||||||
1 | d2r
|
1 | d2r
|
||||||
1 | ssgEnv
|
1 | ssgEnv
|
||||||
1 | dam
|
| - bit 4: on (EG-S on OPLL)
|
||||||
1 | dvb
|
| - bit 0-3: envelope type
|
||||||
1 | egt
|
1 | dam (for YMU759 compat; REV on OPZ)
|
||||||
1 | ksl
|
1 | dvb (for YMU759 compat; FINE on OPZ)
|
||||||
|
1 | egt (for YMU759 compat; FixedFreq on OPZ)
|
||||||
|
1 | ksl (EGShift on OPZ)
|
||||||
1 | sus
|
1 | sus
|
||||||
1 | vib
|
1 | vib
|
||||||
1 | ws
|
1 | ws
|
||||||
|
@ -690,15 +727,18 @@ size | description
|
||||||
| - 10: A#
|
| - 10: A#
|
||||||
| - 11: B
|
| - 11: B
|
||||||
| - 12: C (of next octave)
|
| - 12: C (of next octave)
|
||||||
|
| - this is actually a leftover of the .dmf format.
|
||||||
| - 100: note off
|
| - 100: note off
|
||||||
| - 100: note release
|
| - 100: note release
|
||||||
| - 100: macro release
|
| - 100: macro release
|
||||||
| - octave
|
| - octave
|
||||||
| - this is an signed char stored in a short.
|
| - this is an signed char stored in a short.
|
||||||
| - therefore octave value 255 is actually octave -1.
|
| - therefore octave value 255 is actually octave -1.
|
||||||
|
| - yep, another leftover of the .dmf format...
|
||||||
| - instrument
|
| - instrument
|
||||||
| - volume
|
| - volume
|
||||||
| - effect and effect data...
|
| - effect and effect data (× effect columns)
|
||||||
|
| - for note/octave, if both values are 0 then it means empty.
|
||||||
| - for instrument, volume, effect and effect data, a value of -1 means empty.
|
| - for instrument, volume, effect and effect data, a value of -1 means empty.
|
||||||
STR | pattern name (>=51)
|
STR | pattern name (>=51)
|
||||||
```
|
```
|
||||||
|
|
|
@ -853,6 +853,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
|
||||||
}
|
}
|
||||||
if (!preserveDrift) {
|
if (!preserveDrift) {
|
||||||
ticks=1;
|
ticks=1;
|
||||||
|
subticks=1;
|
||||||
}
|
}
|
||||||
skipping=false;
|
skipping=false;
|
||||||
cmdStream.clear();
|
cmdStream.clear();
|
||||||
|
@ -1970,7 +1971,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ((ins==-1 || getPreferInsType(finalChan)==getIns(ins)->type) && chan[finalChan].midiNote==-1) {
|
if ((ins==-1 || getPreferInsType(finalChan)==getIns(ins)->type || getIns(ins)->type==DIV_INS_AMIGA) && chan[finalChan].midiNote==-1) {
|
||||||
chan[finalChan].midiNote=note;
|
chan[finalChan].midiNote=note;
|
||||||
pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true));
|
pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true));
|
||||||
break;
|
break;
|
||||||
|
@ -1996,6 +1997,20 @@ void DivEngine::autoNoteOff(int ch, int note, int vol) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivEngine::autoNoteOffAll() {
|
||||||
|
if (!playing) {
|
||||||
|
reset();
|
||||||
|
freelance=true;
|
||||||
|
playing=true;
|
||||||
|
}
|
||||||
|
for (int i=0; i<chans; i++) {
|
||||||
|
if (chan[i].midiNote!=-1) {
|
||||||
|
pendingNotes.push(DivNoteEvent(i,-1,-1,-1,false));
|
||||||
|
chan[i].midiNote=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DivEngine::setOrder(unsigned char order) {
|
void DivEngine::setOrder(unsigned char order) {
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
curOrder=order;
|
curOrder=order;
|
||||||
|
|
|
@ -271,7 +271,7 @@ class DivEngine {
|
||||||
void nextRow();
|
void nextRow();
|
||||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond);
|
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond);
|
||||||
// returns true if end of song.
|
// returns true if end of song.
|
||||||
bool nextTick(bool noAccum=false);
|
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||||
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
|
bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||||
void recalcChans();
|
void recalcChans();
|
||||||
|
@ -572,6 +572,7 @@ class DivEngine {
|
||||||
|
|
||||||
void autoNoteOn(int chan, int ins, int note, int vol=-1);
|
void autoNoteOn(int chan, int ins, int note, int vol=-1);
|
||||||
void autoNoteOff(int chan, int note, int vol=-1);
|
void autoNoteOff(int chan, int note, int vol=-1);
|
||||||
|
void autoNoteOffAll();
|
||||||
|
|
||||||
// go to order
|
// go to order
|
||||||
void setOrder(unsigned char order);
|
void setOrder(unsigned char order);
|
||||||
|
|
|
@ -264,6 +264,20 @@ void DivPlatformArcade::tick(bool sysTick) {
|
||||||
rWrite(0x1b,chan[i].std.wave.val&3);
|
rWrite(0x1b,chan[i].std.wave.val&3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.panL.had) {
|
||||||
|
chan[i].chVolL=(chan[i].std.panL.val&2)>>1;
|
||||||
|
chan[i].chVolR=chan[i].std.panL.val&1;
|
||||||
|
if (isMuted[i]) {
|
||||||
|
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
|
||||||
|
} else {
|
||||||
|
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
|
|
@ -215,6 +215,9 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
oldWrites[0x08+i]=-1;
|
oldWrites[0x08+i]=-1;
|
||||||
|
|
|
@ -226,6 +226,9 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
||||||
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
|
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
oldWrites[0x08+i]=-1;
|
oldWrites[0x08+i]=-1;
|
||||||
|
|
|
@ -110,6 +110,9 @@ void DivPlatformBubSysWSG::tick(bool sysTick) {
|
||||||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].active) {
|
if (chan[i].active) {
|
||||||
if (chan[i].ws.tick()) {
|
if (chan[i].ws.tick()) {
|
||||||
updateWave(i);
|
updateWave(i);
|
||||||
|
|
|
@ -181,6 +181,9 @@ void DivPlatformC64::tick(bool sysTick) {
|
||||||
chan[i].wave=chan[i].std.wave.val;
|
chan[i].wave=chan[i].std.wave.val;
|
||||||
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
|
rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].std.ex1.had) {
|
if (chan[i].std.ex1.had) {
|
||||||
filtControl=chan[i].std.ex1.val&15;
|
filtControl=chan[i].std.ex1.val&15;
|
||||||
updateFilter();
|
updateFilter();
|
||||||
|
|
|
@ -107,21 +107,11 @@ void DivPlatformFDS::tick(bool sysTick) {
|
||||||
rWrite(0x4080,0x80|chan[i].outVol);
|
rWrite(0x4080,0x80|chan[i].outVol);
|
||||||
}
|
}
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
if (i==3) { // noise
|
if (!chan[i].inPorta) {
|
||||||
if (chan[i].std.arp.mode) {
|
if (chan[i].std.arp.mode) {
|
||||||
chan[i].baseFreq=chan[i].std.arp.val;
|
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||||
} else {
|
} else {
|
||||||
chan[i].baseFreq=chan[i].note+chan[i].std.arp.val;
|
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||||
}
|
|
||||||
if (chan[i].baseFreq>255) chan[i].baseFreq=255;
|
|
||||||
if (chan[i].baseFreq<0) chan[i].baseFreq=0;
|
|
||||||
} else {
|
|
||||||
if (!chan[i].inPorta) {
|
|
||||||
if (chan[i].std.arp.mode) {
|
|
||||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
|
||||||
} else {
|
|
||||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
|
@ -155,6 +145,9 @@ void DivPlatformFDS::tick(bool sysTick) {
|
||||||
//if (!chan[i].keyOff) chan[i].keyOn=true;
|
//if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].active) {
|
if (chan[i].active) {
|
||||||
if (ws.tick()) {
|
if (ws.tick()) {
|
||||||
updateWave();
|
updateWave();
|
||||||
|
|
|
@ -192,6 +192,9 @@ void DivPlatformGB::tick(bool sysTick) {
|
||||||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
|
|
@ -258,6 +258,10 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
|
|
@ -171,6 +171,10 @@ void DivPlatformLynx::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
if (chan[i].lfsr >= 0) {
|
if (chan[i].lfsr >= 0) {
|
||||||
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
||||||
|
@ -184,8 +188,8 @@ void DivPlatformLynx::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
||||||
WRITE_BACKUP( i, chan[i].fd.backup );
|
WRITE_BACKUP( i, chan[i].fd.backup );
|
||||||
}
|
chan[i].freqChanged=false;
|
||||||
else if (chan[i].std.duty.had) {
|
} else if (chan[i].std.duty.had) {
|
||||||
chan[i].duty = chan[i].std.duty.val;
|
chan[i].duty = chan[i].std.duty.val;
|
||||||
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
||||||
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
||||||
|
|
|
@ -123,6 +123,9 @@ void DivPlatformMMC5::tick(bool sysTick) {
|
||||||
chan[i].duty=chan[i].std.duty.val;
|
chan[i].duty=chan[i].std.duty.val;
|
||||||
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
|
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
|
|
|
@ -261,6 +261,9 @@ void DivPlatformN163::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].std.ex1.had) {
|
if (chan[i].std.ex1.had) {
|
||||||
if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) {
|
if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) {
|
||||||
chan[i].waveLen=chan[i].std.ex1.val&0xfc;
|
chan[i].waveLen=chan[i].std.ex1.val&0xfc;
|
||||||
|
|
|
@ -195,6 +195,9 @@ void DivPlatformNES::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].sweepChanged) {
|
if (chan[i].sweepChanged) {
|
||||||
chan[i].sweepChanged=false;
|
chan[i].sweepChanged=false;
|
||||||
if (i==0) {
|
if (i==0) {
|
||||||
|
|
|
@ -269,6 +269,10 @@ void DivPlatformOPL::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
|
|
@ -145,6 +145,10 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
|
|
@ -196,6 +196,9 @@ void DivPlatformPCE::tick(bool sysTick) {
|
||||||
if (!chan[i].keyOff) chan[i].keyOn=true;
|
if (!chan[i].keyOff) chan[i].keyOn=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].active) {
|
if (chan[i].active) {
|
||||||
if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) {
|
if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) {
|
||||||
updateWave(i);
|
updateWave(i);
|
||||||
|
|
|
@ -186,6 +186,9 @@ void DivPlatformPCSpeaker::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val;
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val;
|
||||||
if (chan[i].freq<0) chan[i].freq=0;
|
if (chan[i].freq<0) chan[i].freq=0;
|
||||||
|
|
|
@ -112,6 +112,9 @@ void DivPlatformPET::tick(bool sysTick) {
|
||||||
rWrite(10,chan.wave);
|
rWrite(10,chan.wave);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan.std.pitch.had) {
|
||||||
|
chan.freqChanged=true;
|
||||||
|
}
|
||||||
if (chan.freqChanged || chan.keyOn || chan.keyOff) {
|
if (chan.freqChanged || chan.keyOn || chan.keyOff) {
|
||||||
chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true)+chan.std.pitch.val;
|
chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true)+chan.std.pitch.val;
|
||||||
if (chan.freq>257) chan.freq=257;
|
if (chan.freq>257) chan.freq=257;
|
||||||
|
|
|
@ -326,6 +326,9 @@ void DivPlatformQSound::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
//DivInstrument* ins=parent->getIns(chan[i].ins);
|
//DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val;
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val;
|
||||||
|
|
|
@ -166,6 +166,9 @@ void DivPlatformSAA1099::tick(bool sysTick) {
|
||||||
if (chan[i].std.wave.had) {
|
if (chan[i].std.wave.had) {
|
||||||
chan[i].psgMode=chan[i].std.wave.val&3;
|
chan[i].psgMode=chan[i].std.wave.val&3;
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].std.ex1.had) {
|
if (chan[i].std.ex1.had) {
|
||||||
saaEnv[i/3]=chan[i].std.ex1.val;
|
saaEnv[i/3]=chan[i].std.ex1.val;
|
||||||
rWrite(0x18+(i/3),saaEnv[i/3]);
|
rWrite(0x18+(i/3),saaEnv[i/3]);
|
||||||
|
|
|
@ -99,6 +99,10 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
/*if (chan[i].keyOn || chan[i].keyOff) {
|
/*if (chan[i].keyOn || chan[i].keyOff) {
|
||||||
chan[i].keyOff=false;
|
chan[i].keyOff=false;
|
||||||
}*/
|
}*/
|
||||||
|
|
|
@ -98,6 +98,9 @@ void DivPlatformSMS::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
|
|
|
@ -173,6 +173,9 @@ void DivPlatformSwan::tick(bool sysTick) {
|
||||||
chan[i].ws.changeWave1(chan[i].wave);
|
chan[i].ws.changeWave1(chan[i].wave);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].active) {
|
if (chan[i].active) {
|
||||||
sndCtrl|=(1<<i);
|
sndCtrl|=(1<<i);
|
||||||
if (chan[i].ws.tick()) {
|
if (chan[i].ws.tick()) {
|
||||||
|
|
|
@ -116,6 +116,9 @@ void DivPlatformTIA::tick(bool sysTick) {
|
||||||
rWrite(0x15+i,chan[i].shape);
|
rWrite(0x15+i,chan[i].shape);
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
if (chan[i].insChanged) {
|
if (chan[i].insChanged) {
|
||||||
if (!chan[i].std.wave.will) {
|
if (!chan[i].std.wave.will) {
|
||||||
|
|
|
@ -228,6 +228,10 @@ void DivPlatformTX81Z::tick(bool sysTick) {
|
||||||
rWrite(0x1b,chan[i].std.wave.val&3);
|
rWrite(0x1b,chan[i].std.wave.val&3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
|
|
@ -184,6 +184,9 @@ void DivPlatformVERA::tick(bool sysTick) {
|
||||||
if (chan[i].std.wave.had) {
|
if (chan[i].std.wave.had) {
|
||||||
rWriteHi(i,3,chan[i].std.wave.val);
|
rWriteHi(i,3,chan[i].std.wave.val);
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8)+chan[i].std.pitch.val;
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8)+chan[i].std.pitch.val;
|
||||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||||
|
|
|
@ -119,6 +119,9 @@ void DivPlatformVIC20::tick(bool sysTick) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
|
||||||
if (i<3) {
|
if (i<3) {
|
||||||
|
|
|
@ -178,6 +178,9 @@ void DivPlatformVRC6::tick(bool sysTick) {
|
||||||
chWrite(i,0,(chan[i].outVol&0xf)|((chan[i].duty&7)<<4));
|
chWrite(i,0,(chan[i].outVol&0xf)|((chan[i].duty&7)<<4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
if (i==2) { // sawtooth
|
if (i==2) { // sawtooth
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val;
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val;
|
||||||
|
|
|
@ -372,6 +372,9 @@ void DivPlatformX1_010::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
if (chan[i].std.ex1.had) {
|
if (chan[i].std.ex1.had) {
|
||||||
bool nextEnable=(chan[i].std.ex1.val&1);
|
bool nextEnable=(chan[i].std.ex1.val&1);
|
||||||
if (nextEnable!=(chan[i].env.flag.envEnable)) {
|
if (nextEnable!=(chan[i].env.flag.envEnable)) {
|
||||||
|
|
|
@ -408,6 +408,10 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
|
|
@ -472,6 +472,10 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan[i].std.pitch.had) {
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
|
|
@ -1472,19 +1472,21 @@ void DivEngine::nextRow() {
|
||||||
firstTick=true;
|
firstTick=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivEngine::nextTick(bool noAccum) {
|
bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
bool ret=false;
|
bool ret=false;
|
||||||
if (divider<10) divider=10;
|
if (divider<10) divider=10;
|
||||||
|
|
||||||
if (lowLatency) {
|
if (lowLatency && !skipping && !inhibitLowLat) {
|
||||||
tickMult=1000/divider;
|
tickMult=1000/divider;
|
||||||
if (tickMult<1) tickMult=1;
|
if (tickMult<1) tickMult=1;
|
||||||
|
} else {
|
||||||
|
tickMult=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/(divider*tickMult);
|
cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/(divider*tickMult);
|
||||||
clockDrift+=fmod(got.rate*pow(2,MASTER_CLOCK_PREC),(double)divider);
|
clockDrift+=fmod(got.rate*pow(2,MASTER_CLOCK_PREC),(double)(divider*tickMult));
|
||||||
if (clockDrift>=divider) {
|
if (clockDrift>=(divider*tickMult)) {
|
||||||
clockDrift-=divider;
|
clockDrift-=(divider*tickMult);
|
||||||
cycles++;
|
cycles++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1384,7 +1384,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
||||||
writeLoop=true;
|
writeLoop=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nextTick() || !playing) {
|
if (nextTick(false,true) || !playing) {
|
||||||
done=true;
|
done=true;
|
||||||
if (!loop) {
|
if (!loop) {
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
|
|
|
@ -226,6 +226,26 @@ void FurnaceGUI::drawDebug() {
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
if (ImGui::TreeNode("ADSR Test Area")) {
|
||||||
|
static int tl, ar, dr, d2r, sl, rr, sus, egt, algOrGlobalSus, instType;
|
||||||
|
static float maxArDr, maxTl;
|
||||||
|
ImGui::Text("This window was done out of frustration");
|
||||||
|
drawFMEnv(tl,ar,dr,d2r,rr,sl,sus,egt,algOrGlobalSus,maxTl,maxArDr,ImVec2(200.0f*dpiScale,100.0f*dpiScale),instType);
|
||||||
|
|
||||||
|
ImGui::InputInt("tl",&tl);
|
||||||
|
ImGui::InputInt("ar",&ar);
|
||||||
|
ImGui::InputInt("dr",&dr);
|
||||||
|
ImGui::InputInt("d2r",&d2r);
|
||||||
|
ImGui::InputInt("sl",&sl);
|
||||||
|
ImGui::InputInt("rr",&rr);
|
||||||
|
ImGui::InputInt("sus",&sus);
|
||||||
|
ImGui::InputInt("egt",&egt);
|
||||||
|
ImGui::InputInt("algOrGlobalSus",&algOrGlobalSus);
|
||||||
|
ImGui::InputInt("instType",&instType);
|
||||||
|
ImGui::InputFloat("maxArDr",&maxArDr);
|
||||||
|
ImGui::InputFloat("maxTl",&maxTl);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
if (ImGui::TreeNode("User Interface")) {
|
if (ImGui::TreeNode("User Interface")) {
|
||||||
if (ImGui::Button("Inspect")) {
|
if (ImGui::Button("Inspect")) {
|
||||||
inspectorOpen=!inspectorOpen;
|
inspectorOpen=!inspectorOpen;
|
||||||
|
|
|
@ -99,20 +99,14 @@ void FurnaceGUI::doAction(int what) {
|
||||||
if (++curOctave>7) {
|
if (++curOctave>7) {
|
||||||
curOctave=7;
|
curOctave=7;
|
||||||
} else {
|
} else {
|
||||||
for (size_t i=0; i<activeNotes.size(); i++) {
|
e->autoNoteOffAll();
|
||||||
e->noteOff(activeNotes[i].chan);
|
|
||||||
}
|
|
||||||
activeNotes.clear();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_OCTAVE_DOWN:
|
case GUI_ACTION_OCTAVE_DOWN:
|
||||||
if (--curOctave<-5) {
|
if (--curOctave<-5) {
|
||||||
curOctave=-5;
|
curOctave=-5;
|
||||||
} else {
|
} else {
|
||||||
for (size_t i=0; i<activeNotes.size(); i++) {
|
e->autoNoteOffAll();
|
||||||
e->noteOff(activeNotes[i].chan);
|
|
||||||
}
|
|
||||||
activeNotes.clear();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_INS_UP:
|
case GUI_ACTION_INS_UP:
|
||||||
|
@ -565,12 +559,14 @@ void FurnaceGUI::doAction(int what) {
|
||||||
|
|
||||||
case GUI_ACTION_SAMPLE_LIST_ADD:
|
case GUI_ACTION_SAMPLE_LIST_ADD:
|
||||||
curSample=e->addSample();
|
curSample=e->addSample();
|
||||||
|
updateSampleTex=true;
|
||||||
MARK_MODIFIED;
|
MARK_MODIFIED;
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_SAMPLE_LIST_DUPLICATE:
|
case GUI_ACTION_SAMPLE_LIST_DUPLICATE:
|
||||||
if (curSample>=0 && curSample<(int)e->song.sample.size()) {
|
if (curSample>=0 && curSample<(int)e->song.sample.size()) {
|
||||||
DivSample* prevSample=e->getSample(curSample);
|
DivSample* prevSample=e->getSample(curSample);
|
||||||
curSample=e->addSample();
|
curSample=e->addSample();
|
||||||
|
updateSampleTex=true;
|
||||||
e->lockEngine([this,prevSample]() {
|
e->lockEngine([this,prevSample]() {
|
||||||
DivSample* sample=e->getSample(curSample);
|
DivSample* sample=e->getSample(curSample);
|
||||||
if (sample!=NULL) {
|
if (sample!=NULL) {
|
||||||
|
@ -597,16 +593,23 @@ void FurnaceGUI::doAction(int what) {
|
||||||
if (curSample>=0 && curSample<(int)e->song.sample.size()) openFileDialog(GUI_FILE_SAMPLE_SAVE);
|
if (curSample>=0 && curSample<(int)e->song.sample.size()) openFileDialog(GUI_FILE_SAMPLE_SAVE);
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_SAMPLE_LIST_MOVE_UP:
|
case GUI_ACTION_SAMPLE_LIST_MOVE_UP:
|
||||||
if (e->moveSampleUp(curSample)) curSample--;
|
if (e->moveSampleUp(curSample)) {
|
||||||
|
curSample--;
|
||||||
|
updateSampleTex=true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_SAMPLE_LIST_MOVE_DOWN:
|
case GUI_ACTION_SAMPLE_LIST_MOVE_DOWN:
|
||||||
if (e->moveSampleDown(curSample)) curSample++;
|
if (e->moveSampleDown(curSample)) {
|
||||||
|
curSample++;
|
||||||
|
updateSampleTex=true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_SAMPLE_LIST_DELETE:
|
case GUI_ACTION_SAMPLE_LIST_DELETE:
|
||||||
e->delSample(curSample);
|
e->delSample(curSample);
|
||||||
MARK_MODIFIED;
|
MARK_MODIFIED;
|
||||||
if (curSample>=(int)e->song.sample.size()) {
|
if (curSample>=(int)e->song.sample.size()) {
|
||||||
curSample--;
|
curSample--;
|
||||||
|
updateSampleTex=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_SAMPLE_LIST_EDIT:
|
case GUI_ACTION_SAMPLE_LIST_EDIT:
|
||||||
|
@ -614,9 +617,11 @@ void FurnaceGUI::doAction(int what) {
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_SAMPLE_LIST_UP:
|
case GUI_ACTION_SAMPLE_LIST_UP:
|
||||||
if (--curSample<0) curSample=0;
|
if (--curSample<0) curSample=0;
|
||||||
|
updateSampleTex=true;
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_SAMPLE_LIST_DOWN:
|
case GUI_ACTION_SAMPLE_LIST_DOWN:
|
||||||
if (++curSample>=(int)e->song.sample.size()) curSample=((int)e->song.sample.size())-1;
|
if (++curSample>=(int)e->song.sample.size()) curSample=((int)e->song.sample.size())-1;
|
||||||
|
updateSampleTex=true;
|
||||||
break;
|
break;
|
||||||
case GUI_ACTION_SAMPLE_LIST_PREVIEW:
|
case GUI_ACTION_SAMPLE_LIST_PREVIEW:
|
||||||
e->previewSample(curSample);
|
e->previewSample(curSample);
|
||||||
|
|
|
@ -35,10 +35,7 @@ void FurnaceGUI::drawEditControls() {
|
||||||
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
|
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
|
||||||
if (curOctave>7) curOctave=7;
|
if (curOctave>7) curOctave=7;
|
||||||
if (curOctave<-5) curOctave=-5;
|
if (curOctave<-5) curOctave=-5;
|
||||||
for (size_t i=0; i<activeNotes.size(); i++) {
|
e->autoNoteOffAll();
|
||||||
e->noteOff(activeNotes[i].chan);
|
|
||||||
}
|
|
||||||
activeNotes.clear();
|
|
||||||
|
|
||||||
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
|
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
|
||||||
nextWindow=GUI_WINDOW_PATTERN;
|
nextWindow=GUI_WINDOW_PATTERN;
|
||||||
|
@ -139,10 +136,7 @@ void FurnaceGUI::drawEditControls() {
|
||||||
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
|
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
|
||||||
if (curOctave>7) curOctave=7;
|
if (curOctave>7) curOctave=7;
|
||||||
if (curOctave<-5) curOctave=-5;
|
if (curOctave<-5) curOctave=-5;
|
||||||
for (size_t i=0; i<activeNotes.size(); i++) {
|
e->autoNoteOffAll();
|
||||||
e->noteOff(activeNotes[i].chan);
|
|
||||||
}
|
|
||||||
activeNotes.clear();
|
|
||||||
|
|
||||||
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
|
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
|
||||||
nextWindow=GUI_WINDOW_PATTERN;
|
nextWindow=GUI_WINDOW_PATTERN;
|
||||||
|
@ -213,10 +207,7 @@ void FurnaceGUI::drawEditControls() {
|
||||||
if (ImGui::InputInt("##Octave",&curOctave,0,0)) {
|
if (ImGui::InputInt("##Octave",&curOctave,0,0)) {
|
||||||
if (curOctave>7) curOctave=7;
|
if (curOctave>7) curOctave=7;
|
||||||
if (curOctave<-5) curOctave=-5;
|
if (curOctave<-5) curOctave=-5;
|
||||||
for (size_t i=0; i<activeNotes.size(); i++) {
|
e->autoNoteOffAll();
|
||||||
e->noteOff(activeNotes[i].chan);
|
|
||||||
}
|
|
||||||
activeNotes.clear();
|
|
||||||
|
|
||||||
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
|
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
|
||||||
nextWindow=GUI_WINDOW_PATTERN;
|
nextWindow=GUI_WINDOW_PATTERN;
|
||||||
|
@ -314,10 +305,7 @@ void FurnaceGUI::drawEditControls() {
|
||||||
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
|
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
|
||||||
if (curOctave>7) curOctave=7;
|
if (curOctave>7) curOctave=7;
|
||||||
if (curOctave<-5) curOctave=-5;
|
if (curOctave<-5) curOctave=-5;
|
||||||
for (size_t i=0; i<activeNotes.size(); i++) {
|
e->autoNoteOffAll();
|
||||||
e->noteOff(activeNotes[i].chan);
|
|
||||||
}
|
|
||||||
activeNotes.clear();
|
|
||||||
|
|
||||||
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
|
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
|
||||||
nextWindow=GUI_WINDOW_PATTERN;
|
nextWindow=GUI_WINDOW_PATTERN;
|
||||||
|
|
182
src/gui/gui.cpp
182
src/gui/gui.cpp
|
@ -1078,9 +1078,6 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
|
||||||
if (edit) {
|
if (edit) {
|
||||||
noteInput(num,key);
|
noteInput(num,key);
|
||||||
}
|
}
|
||||||
if (key!=100 && key!=101 && key!=102) {
|
|
||||||
previewNote(cursor.xCoarse,num);
|
|
||||||
}
|
|
||||||
} catch (std::out_of_range& e) {
|
} catch (std::out_of_range& e) {
|
||||||
}
|
}
|
||||||
} else if (edit) { // value
|
} else if (edit) { // value
|
||||||
|
@ -1182,75 +1179,10 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
|
||||||
}
|
}
|
||||||
} catch (std::out_of_range& e) {
|
} catch (std::out_of_range& e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PER-WINDOW PREVIEW KEYS
|
|
||||||
switch (curWindow) {
|
|
||||||
case GUI_WINDOW_INS_EDIT:
|
|
||||||
case GUI_WINDOW_INS_LIST:
|
|
||||||
case GUI_WINDOW_EDIT_CONTROLS:
|
|
||||||
case GUI_WINDOW_SONG_INFO:
|
|
||||||
if (!ev.key.repeat) {
|
|
||||||
try {
|
|
||||||
int key=noteKeys.at(ev.key.keysym.scancode);
|
|
||||||
int num=12*curOctave+key;
|
|
||||||
if (key!=100 && key!=101 && key!=102) {
|
|
||||||
previewNote(cursor.xCoarse,num);
|
|
||||||
}
|
|
||||||
} catch (std::out_of_range& e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GUI_WINDOW_SAMPLE_EDIT:
|
|
||||||
case GUI_WINDOW_SAMPLE_LIST:
|
|
||||||
if (!ev.key.repeat) {
|
|
||||||
try {
|
|
||||||
int key=noteKeys.at(ev.key.keysym.scancode);
|
|
||||||
int num=12*curOctave+key;
|
|
||||||
if (key!=100 && key!=101 && key!=102) {
|
|
||||||
e->previewSample(curSample,num);
|
|
||||||
samplePreviewOn=true;
|
|
||||||
samplePreviewKey=ev.key.keysym.scancode;
|
|
||||||
samplePreviewNote=num;
|
|
||||||
}
|
|
||||||
} catch (std::out_of_range& e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GUI_WINDOW_WAVE_LIST:
|
|
||||||
case GUI_WINDOW_WAVE_EDIT:
|
|
||||||
if (!ev.key.repeat) {
|
|
||||||
try {
|
|
||||||
int key=noteKeys.at(ev.key.keysym.scancode);
|
|
||||||
int num=12*curOctave+key;
|
|
||||||
if (key!=100 && key!=101 && key!=102) {
|
|
||||||
e->previewWave(curWave,num);
|
|
||||||
wavePreviewOn=true;
|
|
||||||
wavePreviewKey=ev.key.keysym.scancode;
|
|
||||||
wavePreviewNote=num;
|
|
||||||
}
|
|
||||||
} catch (std::out_of_range& e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FurnaceGUI::keyUp(SDL_Event& ev) {
|
void FurnaceGUI::keyUp(SDL_Event& ev) {
|
||||||
stopPreviewNote(ev.key.keysym.scancode,true);
|
// nothing for now
|
||||||
if (wavePreviewOn) {
|
|
||||||
if (ev.key.keysym.scancode==wavePreviewKey) {
|
|
||||||
wavePreviewOn=false;
|
|
||||||
e->stopWavePreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (samplePreviewOn) {
|
|
||||||
if (ev.key.keysym.scancode==samplePreviewKey) {
|
|
||||||
samplePreviewOn=false;
|
|
||||||
e->stopSamplePreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dirExists(String what) {
|
bool dirExists(String what) {
|
||||||
|
@ -2021,10 +1953,100 @@ void FurnaceGUI::editOptions(bool topMenu) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _processEvent(void* instance, SDL_Event* event) {
|
||||||
|
return ((FurnaceGUI*)instance)->processEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FurnaceGUI::processEvent(SDL_Event* ev) {
|
||||||
|
if (ev->type==SDL_KEYDOWN) {
|
||||||
|
if (!ev->key.repeat && !wantCaptureKeyboard && (ev->key.keysym.mod&(~(KMOD_NUM|KMOD_CAPS|KMOD_SCROLL)))==0) {
|
||||||
|
if (settings.notePreviewBehavior==0) return 1;
|
||||||
|
switch (curWindow) {
|
||||||
|
case GUI_WINDOW_SAMPLE_EDIT:
|
||||||
|
case GUI_WINDOW_SAMPLE_LIST:
|
||||||
|
try {
|
||||||
|
int key=noteKeys.at(ev->key.keysym.scancode);
|
||||||
|
int num=12*curOctave+key;
|
||||||
|
if (key!=100 && key!=101 && key!=102) {
|
||||||
|
e->previewSample(curSample,num);
|
||||||
|
samplePreviewOn=true;
|
||||||
|
samplePreviewKey=ev->key.keysym.scancode;
|
||||||
|
samplePreviewNote=num;
|
||||||
|
}
|
||||||
|
} catch (std::out_of_range& e) {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GUI_WINDOW_WAVE_LIST:
|
||||||
|
case GUI_WINDOW_WAVE_EDIT:
|
||||||
|
try {
|
||||||
|
int key=noteKeys.at(ev->key.keysym.scancode);
|
||||||
|
int num=12*curOctave+key;
|
||||||
|
if (key!=100 && key!=101 && key!=102) {
|
||||||
|
e->previewWave(curWave,num);
|
||||||
|
wavePreviewOn=true;
|
||||||
|
wavePreviewKey=ev->key.keysym.scancode;
|
||||||
|
wavePreviewNote=num;
|
||||||
|
}
|
||||||
|
} catch (std::out_of_range& e) {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GUI_WINDOW_ORDERS: // ignore here
|
||||||
|
break;
|
||||||
|
case GUI_WINDOW_PATTERN:
|
||||||
|
if (settings.notePreviewBehavior==1) {
|
||||||
|
if (cursor.xFine!=0) break;
|
||||||
|
} else if (settings.notePreviewBehavior==2) {
|
||||||
|
if (edit && cursor.xFine!=0) break;
|
||||||
|
}
|
||||||
|
// fall-through
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
int key=noteKeys.at(ev->key.keysym.scancode);
|
||||||
|
int num=12*curOctave+key;
|
||||||
|
|
||||||
|
if (num<-60) num=-60; // C-(-5)
|
||||||
|
if (num>119) num=119; // B-9
|
||||||
|
|
||||||
|
if (key!=100 && key!=101 && key!=102) {
|
||||||
|
previewNote(cursor.xCoarse,num);
|
||||||
|
}
|
||||||
|
} catch (std::out_of_range& e) {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ev->type==SDL_KEYUP) {
|
||||||
|
stopPreviewNote(ev->key.keysym.scancode,true);
|
||||||
|
if (wavePreviewOn) {
|
||||||
|
if (ev->key.keysym.scancode==wavePreviewKey) {
|
||||||
|
wavePreviewOn=false;
|
||||||
|
e->stopWavePreview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (samplePreviewOn) {
|
||||||
|
if (ev->key.keysym.scancode==samplePreviewKey) {
|
||||||
|
samplePreviewOn=false;
|
||||||
|
e->stopSamplePreview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
bool FurnaceGUI::loop() {
|
bool FurnaceGUI::loop() {
|
||||||
|
SDL_SetEventFilter(_processEvent,this);
|
||||||
|
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
SDL_Event ev;
|
SDL_Event ev;
|
||||||
|
if (e->isPlaying()) {
|
||||||
|
WAKE_UP;
|
||||||
|
}
|
||||||
|
if (--drawHalt<=0) {
|
||||||
|
drawHalt=0;
|
||||||
|
if (settings.powerSave) SDL_WaitEventTimeout(NULL,500);
|
||||||
|
}
|
||||||
while (SDL_PollEvent(&ev)) {
|
while (SDL_PollEvent(&ev)) {
|
||||||
|
WAKE_UP;
|
||||||
ImGui_ImplSDL2_ProcessEvent(&ev);
|
ImGui_ImplSDL2_ProcessEvent(&ev);
|
||||||
switch (ev.type) {
|
switch (ev.type) {
|
||||||
case SDL_MOUSEMOTION: {
|
case SDL_MOUSEMOTION: {
|
||||||
|
@ -2131,23 +2153,7 @@ bool FurnaceGUI::loop() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
if (!ImGui::GetIO().WantCaptureKeyboard) {
|
// for now
|
||||||
keyUp(ev);
|
|
||||||
} else {
|
|
||||||
stopPreviewNote(ev.key.keysym.scancode,true);
|
|
||||||
if (wavePreviewOn) {
|
|
||||||
if (ev.key.keysym.scancode==wavePreviewKey) {
|
|
||||||
wavePreviewOn=false;
|
|
||||||
e->stopWavePreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (samplePreviewOn) {
|
|
||||||
if (ev.key.keysym.scancode==samplePreviewKey) {
|
|
||||||
samplePreviewOn=false;
|
|
||||||
e->stopSamplePreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SDL_DROPFILE:
|
case SDL_DROPFILE:
|
||||||
if (ev.drop.file!=NULL) {
|
if (ev.drop.file!=NULL) {
|
||||||
|
@ -2173,6 +2179,8 @@ bool FurnaceGUI::loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wantCaptureKeyboard=ImGui::GetIO().WantCaptureKeyboard;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
midiLock.lock();
|
midiLock.lock();
|
||||||
if (midiQueue.empty()) {
|
if (midiQueue.empty()) {
|
||||||
|
@ -3422,8 +3430,10 @@ FurnaceGUI::FurnaceGUI():
|
||||||
displayError(false),
|
displayError(false),
|
||||||
displayExporting(false),
|
displayExporting(false),
|
||||||
vgmExportLoop(true),
|
vgmExportLoop(true),
|
||||||
|
wantCaptureKeyboard(false),
|
||||||
displayNew(false),
|
displayNew(false),
|
||||||
vgmExportVersion(0x171),
|
vgmExportVersion(0x171),
|
||||||
|
drawHalt(10),
|
||||||
curFileDialog(GUI_FILE_OPEN),
|
curFileDialog(GUI_FILE_OPEN),
|
||||||
warnAction(GUI_WARN_OPEN),
|
warnAction(GUI_WARN_OPEN),
|
||||||
postWarnAction(GUI_WARN_GENERIC),
|
postWarnAction(GUI_WARN_GENERIC),
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#define unimportant(x) if (x) {handleUnimportant}
|
#define unimportant(x) if (x) {handleUnimportant}
|
||||||
|
|
||||||
#define MARK_MODIFIED modified=true;
|
#define MARK_MODIFIED modified=true;
|
||||||
|
#define WAKE_UP drawHalt=16;
|
||||||
|
|
||||||
#define TOGGLE_COLOR(x) ((x)?uiColors[GUI_COLOR_TOGGLE_ON]:uiColors[GUI_COLOR_TOGGLE_OFF])
|
#define TOGGLE_COLOR(x) ((x)?uiColors[GUI_COLOR_TOGGLE_ON]:uiColors[GUI_COLOR_TOGGLE_OFF])
|
||||||
|
|
||||||
|
@ -711,10 +712,11 @@ class FurnaceGUI {
|
||||||
String mmlString[17];
|
String mmlString[17];
|
||||||
String mmlStringW;
|
String mmlStringW;
|
||||||
|
|
||||||
bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop;
|
bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard;
|
||||||
bool displayNew;
|
bool displayNew;
|
||||||
bool willExport[32];
|
bool willExport[32];
|
||||||
int vgmExportVersion;
|
int vgmExportVersion;
|
||||||
|
int drawHalt;
|
||||||
|
|
||||||
FurnaceGUIFileDialogs curFileDialog;
|
FurnaceGUIFileDialogs curFileDialog;
|
||||||
FurnaceGUIWarnings warnAction;
|
FurnaceGUIWarnings warnAction;
|
||||||
|
@ -819,6 +821,8 @@ class FurnaceGUI {
|
||||||
int oplStandardWaveNames;
|
int oplStandardWaveNames;
|
||||||
int cursorMoveNoScroll;
|
int cursorMoveNoScroll;
|
||||||
int lowLatency;
|
int lowLatency;
|
||||||
|
int notePreviewBehavior;
|
||||||
|
int powerSave;
|
||||||
unsigned int maxUndoSteps;
|
unsigned int maxUndoSteps;
|
||||||
String mainFontPath;
|
String mainFontPath;
|
||||||
String patFontPath;
|
String patFontPath;
|
||||||
|
@ -891,6 +895,8 @@ class FurnaceGUI {
|
||||||
oplStandardWaveNames(0),
|
oplStandardWaveNames(0),
|
||||||
cursorMoveNoScroll(0),
|
cursorMoveNoScroll(0),
|
||||||
lowLatency(0),
|
lowLatency(0),
|
||||||
|
notePreviewBehavior(1),
|
||||||
|
powerSave(1),
|
||||||
maxUndoSteps(100),
|
maxUndoSteps(100),
|
||||||
mainFontPath(""),
|
mainFontPath(""),
|
||||||
patFontPath(""),
|
patFontPath(""),
|
||||||
|
@ -1215,6 +1221,7 @@ class FurnaceGUI {
|
||||||
void addScroll(int amount);
|
void addScroll(int amount);
|
||||||
void setFileName(String name);
|
void setFileName(String name);
|
||||||
void runBackupThread();
|
void runBackupThread();
|
||||||
|
int processEvent(SDL_Event* ev);
|
||||||
bool loop();
|
bool loop();
|
||||||
bool finish();
|
bool finish();
|
||||||
bool init();
|
bool init();
|
||||||
|
|
|
@ -175,6 +175,10 @@ const char* n163UpdateBits[8]={
|
||||||
"now", "every waveform changed", NULL
|
"now", "every waveform changed", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* panBits[3]={
|
||||||
|
"left", "right", NULL
|
||||||
|
};
|
||||||
|
|
||||||
const char* oneBit[2]={
|
const char* oneBit[2]={
|
||||||
"on", NULL
|
"on", NULL
|
||||||
};
|
};
|
||||||
|
@ -2717,8 +2721,10 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
if (ins->type==DIV_INS_SAA1099) ex1Max=8;
|
if (ins->type==DIV_INS_SAA1099) ex1Max=8;
|
||||||
|
|
||||||
int panMax=0;
|
int panMax=0;
|
||||||
|
bool panSingle=false;
|
||||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_GB || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_VERA) {
|
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_GB || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_VERA) {
|
||||||
panMax=1;
|
panMax=1;
|
||||||
|
panSingle=true;
|
||||||
}
|
}
|
||||||
if (ins->type==DIV_INS_AMIGA) {
|
if (ins->type==DIV_INS_AMIGA) {
|
||||||
panMax=127;
|
panMax=127;
|
||||||
|
@ -2746,8 +2752,12 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false);
|
NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false);
|
||||||
}
|
}
|
||||||
if (panMax>0) {
|
if (panMax>0) {
|
||||||
NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",(31+panMax),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false);
|
if (panSingle) {
|
||||||
NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",(31+panMax),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false);
|
NORMAL_MACRO(ins->std.panLMacro,0,2,"panL","Panning",32,ins->std.panLMacro.open,true,panBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false);
|
||||||
|
} else {
|
||||||
|
NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",(31+panMax),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false);
|
||||||
|
NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",(31+panMax),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NORMAL_MACRO(ins->std.pitchMacro,pitchMacroScroll,pitchMacroScroll+160,"pitch","Pitch",160,ins->std.pitchMacro.open,false,NULL,true,&pitchMacroScroll,-2048,2047,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[15],-2048,2047,NULL,!ins->std.pitchMacro.mode);
|
NORMAL_MACRO(ins->std.pitchMacro,pitchMacroScroll,pitchMacroScroll+160,"pitch","Pitch",160,ins->std.pitchMacro.open,false,NULL,true,&pitchMacroScroll,-2048,2047,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[15],-2048,2047,NULL,!ins->std.pitchMacro.mode);
|
||||||
if (ins->type==DIV_INS_FM ||
|
if (ins->type==DIV_INS_FM ||
|
||||||
|
|
|
@ -49,12 +49,19 @@ void FurnaceGUI::readOsc() {
|
||||||
for (int i=0; i<512; i++) {
|
for (int i=0; i<512; i++) {
|
||||||
int pos=(readPos+(i*total/512))&0x7fff;
|
int pos=(readPos+(i*total/512))&0x7fff;
|
||||||
oscValues[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f;
|
oscValues[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f;
|
||||||
|
if (oscValues[i]>0.001f || oscValues[i]<-0.001f) {
|
||||||
|
WAKE_UP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime;
|
float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime;
|
||||||
for (int i=0; i<2; i++) {
|
for (int i=0; i<2; i++) {
|
||||||
peak[i]*=1.0-peakDecay;
|
peak[i]*=1.0-peakDecay;
|
||||||
if (peak[i]<0.0001) peak[i]=0.0;
|
if (peak[i]<0.0001) {
|
||||||
|
peak[i]=0.0;
|
||||||
|
} else {
|
||||||
|
WAKE_UP;
|
||||||
|
}
|
||||||
float newPeak=peak[i];
|
float newPeak=peak[i];
|
||||||
for (int j=0; j<total; j++) {
|
for (int j=0; j<total; j++) {
|
||||||
int pos=(readPos+j)&0x7fff;
|
int pos=(readPos+j)&0x7fff;
|
||||||
|
|
|
@ -890,6 +890,7 @@ void FurnaceGUI::drawPattern() {
|
||||||
|
|
||||||
// particle simulation
|
// particle simulation
|
||||||
ImDrawList* fdl=ImGui::GetForegroundDrawList();
|
ImDrawList* fdl=ImGui::GetForegroundDrawList();
|
||||||
|
if (!particles.empty()) WAKE_UP;
|
||||||
for (size_t i=0; i<particles.size(); i++) {
|
for (size_t i=0; i<particles.size(); i++) {
|
||||||
Particle& part=particles[i];
|
Particle& part=particles[i];
|
||||||
if (part.update(frameTime)) {
|
if (part.update(frameTime)) {
|
||||||
|
|
|
@ -31,6 +31,13 @@
|
||||||
|
|
||||||
#define DEFAULT_NOTE_KEYS "5:7;6:4;7:3;8:16;10:6;11:8;12:24;13:10;16:11;17:9;18:26;19:28;20:12;21:17;22:1;23:19;24:23;25:5;26:14;27:2;28:21;29:0;30:100;31:13;32:15;34:18;35:20;36:22;38:25;39:27;43:100;46:101;47:29;48:31;53:102;"
|
#define DEFAULT_NOTE_KEYS "5:7;6:4;7:3;8:16;10:6;11:8;12:24;13:10;16:11;17:9;18:26;19:28;20:12;21:17;22:1;23:19;24:23;25:5;26:14;27:2;28:21;29:0;30:100;31:13;32:15;34:18;35:20;36:22;38:25;39:27;43:100;46:101;47:29;48:31;53:102;"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__APPLE__)
|
||||||
|
#define POWER_SAVE_DEFAULT 1
|
||||||
|
#else
|
||||||
|
// currently off on Linux/other due to Mesa catch-up behavior.
|
||||||
|
#define POWER_SAVE_DEFAULT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
const char* mainFonts[]={
|
const char* mainFonts[]={
|
||||||
"IBM Plex Sans",
|
"IBM Plex Sans",
|
||||||
"Liberation Sans",
|
"Liberation Sans",
|
||||||
|
@ -301,6 +308,28 @@ void FurnaceGUI::drawSettings() {
|
||||||
settings.sysFileDialog=sysFileDialogB;
|
settings.sysFileDialog=sysFileDialogB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool powerSaveB=settings.powerSave;
|
||||||
|
if (ImGui::Checkbox("Power-saving mode",&powerSaveB)) {
|
||||||
|
settings.powerSave=powerSaveB;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("saves power by lowering the frame rate to 2fps when idle.\nmay cause issues under Mesa drivers!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text("Note preview behavior:");
|
||||||
|
if (ImGui::RadioButton("Never##npb0",settings.notePreviewBehavior==0)) {
|
||||||
|
settings.notePreviewBehavior=0;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton("When cursor is in Note column##npb1",settings.notePreviewBehavior==1)) {
|
||||||
|
settings.notePreviewBehavior=1;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton("When cursor is in Note column or not in edit mode##npb2",settings.notePreviewBehavior==2)) {
|
||||||
|
settings.notePreviewBehavior=2;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton("Always##npb3",settings.notePreviewBehavior==3)) {
|
||||||
|
settings.notePreviewBehavior=3;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Text("Wrap pattern cursor horizontally:");
|
ImGui::Text("Wrap pattern cursor horizontally:");
|
||||||
if (ImGui::RadioButton("No##wrapH0",settings.wrapHorizontal==0)) {
|
if (ImGui::RadioButton("No##wrapH0",settings.wrapHorizontal==0)) {
|
||||||
settings.wrapHorizontal=0;
|
settings.wrapHorizontal=0;
|
||||||
|
@ -1609,6 +1638,8 @@ void FurnaceGUI::syncSettings() {
|
||||||
settings.oplStandardWaveNames=e->getConfInt("oplStandardWaveNames",0);
|
settings.oplStandardWaveNames=e->getConfInt("oplStandardWaveNames",0);
|
||||||
settings.cursorMoveNoScroll=e->getConfInt("cursorMoveNoScroll",0);
|
settings.cursorMoveNoScroll=e->getConfInt("cursorMoveNoScroll",0);
|
||||||
settings.lowLatency=e->getConfInt("lowLatency",0);
|
settings.lowLatency=e->getConfInt("lowLatency",0);
|
||||||
|
settings.notePreviewBehavior=e->getConfInt("notePreviewBehavior",1);
|
||||||
|
settings.powerSave=e->getConfInt("powerSave",POWER_SAVE_DEFAULT);
|
||||||
|
|
||||||
clampSetting(settings.mainFontSize,2,96);
|
clampSetting(settings.mainFontSize,2,96);
|
||||||
clampSetting(settings.patFontSize,2,96);
|
clampSetting(settings.patFontSize,2,96);
|
||||||
|
@ -1670,6 +1701,8 @@ void FurnaceGUI::syncSettings() {
|
||||||
clampSetting(settings.oplStandardWaveNames,0,1);
|
clampSetting(settings.oplStandardWaveNames,0,1);
|
||||||
clampSetting(settings.cursorMoveNoScroll,0,1);
|
clampSetting(settings.cursorMoveNoScroll,0,1);
|
||||||
clampSetting(settings.lowLatency,0,1);
|
clampSetting(settings.lowLatency,0,1);
|
||||||
|
clampSetting(settings.notePreviewBehavior,0,3);
|
||||||
|
clampSetting(settings.powerSave,0,1);
|
||||||
|
|
||||||
// keybinds
|
// keybinds
|
||||||
for (int i=0; i<GUI_ACTION_MAX; i++) {
|
for (int i=0; i<GUI_ACTION_MAX; i++) {
|
||||||
|
@ -1758,6 +1791,8 @@ void FurnaceGUI::commitSettings() {
|
||||||
e->setConf("oplStandardWaveNames",settings.oplStandardWaveNames);
|
e->setConf("oplStandardWaveNames",settings.oplStandardWaveNames);
|
||||||
e->setConf("cursorMoveNoScroll",settings.cursorMoveNoScroll);
|
e->setConf("cursorMoveNoScroll",settings.cursorMoveNoScroll);
|
||||||
e->setConf("lowLatency",settings.lowLatency);
|
e->setConf("lowLatency",settings.lowLatency);
|
||||||
|
e->setConf("notePreviewBehavior",settings.notePreviewBehavior);
|
||||||
|
e->setConf("powerSave",settings.powerSave);
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||||
|
|
Loading…
Reference in New Issue