mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-15 17:25:06 +00:00
Merge branch 'newpitch'
This commit is contained in:
commit
bb4bc01778
12 changed files with 118 additions and 107 deletions
|
@ -49,12 +49,27 @@ the coding style is described here:
|
|||
- `size_t` are 32-bit or 64-bit, depending on architecture.
|
||||
- in float/double operations, always use decimal and `f` if single-precision.
|
||||
- e.g. `1.0f` or `1.0` instead of `1`.
|
||||
- prefer `NULL` over `nullptr` or any other proprietary null.
|
||||
- don't use `auto` unless needed.
|
||||
- use `String` for `std::string` (this is typedef'd in ta-utils.h).
|
||||
- prefer using operator for String (std::string) comparisons (a=="").
|
||||
|
||||
some files (particularly the ones in `src/engine/platform/sound` and `extern/`) don't follow this style.
|
||||
|
||||
you don't have to follow this style. I will fix it after I accept your contribution.
|
||||
|
||||
additional guidelines:
|
||||
|
||||
- in general **strongly** avoid breaking compatibility.
|
||||
- do not touch loadFur/saveFur unless you know what you're doing!
|
||||
- new fields must be at the end of each block to ensure forward compatibility
|
||||
- likewise, the instrument read/write functions in DivInstrument have to be handled carefully
|
||||
- any change to the format requires a version bump (see `src/engine/engine.h`).
|
||||
- do not bump the version number under any circumstances!
|
||||
- if you are making major changes to the playback routine, make sure to test with older songs to ensure nothing breaks.
|
||||
- I will run a test suite to make sure this is the case.
|
||||
- if something breaks, you might want to add a compatibility flag (this requires changing the format though).
|
||||
|
||||
## Demo Songs
|
||||
|
||||
just put your demo song in `demos/`!
|
||||
|
|
|
@ -29,6 +29,8 @@ furthermore, an `or reserved` indicates this field is always present, but is res
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 85: Furnace dev85
|
||||
- 84: Furnace dev84
|
||||
- 83: Furnace dev83
|
||||
- 82: Furnace dev82
|
||||
- 81: Furnace dev81
|
||||
|
@ -269,7 +271,9 @@ size | description
|
|||
1 | ExtCh channel state is shared (>=78) or reserved
|
||||
1 | ignore DAC mode change outside of intended channel (>=83) or reserved
|
||||
1 | E1xx and E2xx also take priority over Slide00 (>=83) or reserved
|
||||
23 | reserved
|
||||
1 | new Sega PCM (with macros and proper vol/pan) (>=84) or reserved
|
||||
1 | weird f-num/block-based chip pitch slides (>=85) or reserved
|
||||
21 | reserved
|
||||
```
|
||||
|
||||
# instrument
|
||||
|
|
|
@ -426,6 +426,7 @@ class DivDispatch {
|
|||
#define NOTE_PERIODIC(x) round(parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true))
|
||||
#define NOTE_PERIODIC_NOROUND(x) parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true)
|
||||
#define NOTE_FREQUENCY(x) parent->calcBaseFreq(chipClock,CHIP_FREQBASE,x,false)
|
||||
#define NOTE_FNUM_BLOCK(x,bits) ((((int)parent->calcBaseFreq(chipClock,CHIP_FREQBASE,(x)%12,false))&((1<<bits)-1))|((MAX(x,0)/12)<<bits))
|
||||
|
||||
#define COLOR_NTSC (315000000.0/88.0)
|
||||
#define COLOR_PAL (283.75*15625.0+25.0)
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev84"
|
||||
#define DIV_ENGINE_VERSION 84
|
||||
#define DIV_VERSION "dev85"
|
||||
#define DIV_ENGINE_VERSION 85
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
|
|
@ -162,6 +162,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.gbInsAffectsEnvelope=true;
|
||||
ds.ignoreDACModeOutsideIntendedChannel=false;
|
||||
ds.e1e2AlsoTakePriority=true;
|
||||
ds.fbPortaPause=true;
|
||||
|
||||
// 1.1 compat flags
|
||||
if (ds.version>24) {
|
||||
|
@ -993,6 +994,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version<84) {
|
||||
ds.newSegaPCM=false;
|
||||
}
|
||||
if (ds.version<85) {
|
||||
ds.fbPortaPause=true;
|
||||
}
|
||||
ds.isDMF=false;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
@ -1342,7 +1346,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<22; i++) {
|
||||
if (ds.version>=85) {
|
||||
ds.fbPortaPause=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<21; i++) {
|
||||
reader.readC();
|
||||
}
|
||||
}
|
||||
|
@ -2283,7 +2292,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(song.ignoreDACModeOutsideIntendedChannel);
|
||||
w->writeC(song.e1e2AlsoTakePriority);
|
||||
w->writeC(song.newSegaPCM);
|
||||
for (int i=0; i<22; i++) {
|
||||
w->writeC(song.fbPortaPause);
|
||||
for (int i=0; i<21; i++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -245,15 +245,15 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11);
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val);
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11);
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11);
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
|
@ -394,9 +394,9 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
for (int i=0; i<6; i++) {
|
||||
if (i==2 && extMode) continue;
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq));
|
||||
if (chan[i].freq>262143) chan[i].freq=262143;
|
||||
int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val;
|
||||
chan[i].freq=((chan[i].baseFreq&0xf800)|parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4))+chan[i].std.pitch.val;
|
||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||
int freqt=chan[i].freq;
|
||||
immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8);
|
||||
immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff);
|
||||
if (chan[i].furnaceDac && dacMode) {
|
||||
|
@ -422,47 +422,6 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
int DivPlatformGenesis::octave(int freq) {
|
||||
if (freq>=82432) {
|
||||
return 128;
|
||||
} else if (freq>=41216) {
|
||||
return 64;
|
||||
} else if (freq>=20608) {
|
||||
return 32;
|
||||
} else if (freq>=10304) {
|
||||
return 16;
|
||||
} else if (freq>=5152) {
|
||||
return 8;
|
||||
} else if (freq>=2576) {
|
||||
return 4;
|
||||
} else if (freq>=1288) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DivPlatformGenesis::toFreq(int freq) {
|
||||
if (freq>=82432) {
|
||||
return 0x3800|((freq>>7)&0x7ff);
|
||||
} else if (freq>=41216) {
|
||||
return 0x3000|((freq>>6)&0x7ff);
|
||||
} else if (freq>=20608) {
|
||||
return 0x2800|((freq>>5)&0x7ff);
|
||||
} else if (freq>=10304) {
|
||||
return 0x2000|((freq>>4)&0x7ff);
|
||||
} else if (freq>=5152) {
|
||||
return 0x1800|((freq>>3)&0x7ff);
|
||||
} else if (freq>=2576) {
|
||||
return 0x1000|((freq>>2)&0x7ff);
|
||||
} else if (freq>=1288) {
|
||||
return 0x800|((freq>>1)&0x7ff);
|
||||
} else {
|
||||
return freq&0x7ff;
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
for (int j=0; j<4; j++) {
|
||||
|
@ -509,7 +468,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
dacPos=0;
|
||||
dacPeriod=0;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
chan[c.chan].furnaceDac=true;
|
||||
|
@ -576,7 +535,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
chan[c.chan].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
chan[c.chan].portaPause=false;
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -656,31 +615,42 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=NOTE_FNUM_BLOCK(c.value2,11);
|
||||
int newFreq;
|
||||
bool return2=false;
|
||||
if (chan[c.chan].portaPause) {
|
||||
chan[c.chan].baseFreq=chan[c.chan].portaPauseFreq;
|
||||
}
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
newFreq=chan[c.chan].baseFreq+c.value*octave(chan[c.chan].baseFreq);
|
||||
newFreq=chan[c.chan].baseFreq+c.value;
|
||||
if (newFreq>=destFreq) {
|
||||
newFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
newFreq=chan[c.chan].baseFreq-c.value*octave(chan[c.chan].baseFreq);
|
||||
newFreq=chan[c.chan].baseFreq-c.value;
|
||||
if (newFreq<=destFreq) {
|
||||
newFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
// check for octave boundary
|
||||
// what the heck!
|
||||
if (!chan[c.chan].portaPause) {
|
||||
if (octave(chan[c.chan].baseFreq)!=octave(newFreq)) {
|
||||
if ((newFreq&0x7ff)>1288) {
|
||||
chan[c.chan].portaPauseFreq=(644)|((newFreq+0x800)&0xf800);
|
||||
chan[c.chan].portaPause=true;
|
||||
break;
|
||||
}
|
||||
if ((newFreq&0x7ff)<644) {
|
||||
chan[c.chan].portaPauseFreq=newFreq=(1287)|((newFreq-0x800)&0xf800);
|
||||
chan[c.chan].portaPause=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
chan[c.chan].baseFreq=newFreq;
|
||||
chan[c.chan].portaPause=false;
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].baseFreq=newFreq;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
|
@ -699,7 +669,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
|
|
|
@ -36,7 +36,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
DivInstrumentFM state;
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, note;
|
||||
int freq, baseFreq, pitch, portaPauseFreq, note;
|
||||
unsigned char ins;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset;
|
||||
int vol, outVol;
|
||||
|
@ -47,6 +47,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
portaPauseFreq(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
active(false),
|
||||
|
@ -93,9 +94,6 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
||||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||
|
|
|
@ -72,7 +72,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
opChan[ch].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
opChan[ch].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
opChan[ch].portaPause=false;
|
||||
opChan[ch].freqChanged=true;
|
||||
}
|
||||
|
@ -127,31 +127,49 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=NOTE_FNUM_BLOCK(c.value2,11);
|
||||
int newFreq;
|
||||
bool return2=false;
|
||||
if (opChan[ch].portaPause) {
|
||||
opChan[ch].baseFreq=opChan[ch].portaPauseFreq;
|
||||
}
|
||||
if (destFreq>opChan[ch].baseFreq) {
|
||||
newFreq=opChan[ch].baseFreq+c.value*octave(opChan[ch].baseFreq);
|
||||
newFreq=opChan[ch].baseFreq+c.value;
|
||||
if (newFreq>=destFreq) {
|
||||
newFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
newFreq=opChan[ch].baseFreq-c.value*octave(opChan[ch].baseFreq);
|
||||
newFreq=opChan[ch].baseFreq-c.value;
|
||||
if (newFreq<=destFreq) {
|
||||
newFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
// what the heck!
|
||||
if (!opChan[ch].portaPause) {
|
||||
if (octave(opChan[ch].baseFreq)!=octave(newFreq)) {
|
||||
if ((newFreq&0x7ff)>1288) {
|
||||
if (parent->song.fbPortaPause) {
|
||||
opChan[ch].portaPauseFreq=(644)|((newFreq+0x800)&0xf800);
|
||||
opChan[ch].portaPause=true;
|
||||
break;
|
||||
} else {
|
||||
newFreq=(newFreq>>1)|((newFreq+0x800)&0xf800);
|
||||
}
|
||||
}
|
||||
if ((newFreq&0x7ff)<644) {
|
||||
if (parent->song.fbPortaPause) {
|
||||
opChan[ch].portaPauseFreq=newFreq=(1287)|((newFreq-0x800)&0xf800);
|
||||
opChan[ch].portaPause=true;
|
||||
break;
|
||||
} else {
|
||||
newFreq=(newFreq<<1)|((newFreq-0x800)&0xf800);
|
||||
}
|
||||
}
|
||||
}
|
||||
opChan[ch].baseFreq=newFreq;
|
||||
opChan[ch].portaPause=false;
|
||||
opChan[ch].freqChanged=true;
|
||||
opChan[ch].baseFreq=newFreq;
|
||||
if (return2) return 2;
|
||||
break;
|
||||
}
|
||||
|
@ -172,7 +190,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
opChan[ch].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
opChan[ch].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
|
@ -289,35 +307,10 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
unsigned char writeMask=2;
|
||||
if (extMode) for (int i=0; i<4; i++) {
|
||||
if (opChan[i].freqChanged) {
|
||||
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch);
|
||||
if (opChan[i].freq>262143) opChan[i].freq=262143;
|
||||
if (opChan[i].freq>=82432) {
|
||||
opChan[i].freqH=((opChan[i].freq>>15)&7)|0x38;
|
||||
opChan[i].freqL=(opChan[i].freq>>7)&0xff;
|
||||
} else if (opChan[i].freq>=41216) {
|
||||
opChan[i].freqH=((opChan[i].freq>>14)&7)|0x30;
|
||||
opChan[i].freqL=(opChan[i].freq>>6)&0xff;
|
||||
} else if (opChan[i].freq>=20608) {
|
||||
opChan[i].freqH=((opChan[i].freq>>13)&7)|0x28;
|
||||
opChan[i].freqL=(opChan[i].freq>>5)&0xff;
|
||||
} else if (opChan[i].freq>=10304) {
|
||||
opChan[i].freqH=((opChan[i].freq>>12)&7)|0x20;
|
||||
opChan[i].freqL=(opChan[i].freq>>4)&0xff;
|
||||
} else if (opChan[i].freq>=5152) {
|
||||
opChan[i].freqH=((opChan[i].freq>>11)&7)|0x18;
|
||||
opChan[i].freqL=(opChan[i].freq>>3)&0xff;
|
||||
} else if (opChan[i].freq>=2576) {
|
||||
opChan[i].freqH=((opChan[i].freq>>10)&7)|0x10;
|
||||
opChan[i].freqL=(opChan[i].freq>>2)&0xff;
|
||||
} else if (opChan[i].freq>=1288) {
|
||||
opChan[i].freqH=((opChan[i].freq>>9)&7)|0x08;
|
||||
opChan[i].freqL=(opChan[i].freq>>1)&0xff;
|
||||
} else {
|
||||
opChan[i].freqH=(opChan[i].freq>>8)&7;
|
||||
opChan[i].freqL=opChan[i].freq&0xff;
|
||||
}
|
||||
immWrite(opChanOffsH[i],opChan[i].freqH);
|
||||
immWrite(opChanOffsL[i],opChan[i].freqL);
|
||||
opChan[i].freq=(opChan[i].baseFreq&0xf800)|parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,false,4);
|
||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||
immWrite(opChanOffsH[i],opChan[i].freq>>8);
|
||||
immWrite(opChanOffsL[i],opChan[i].freq&0xff);
|
||||
}
|
||||
writeMask|=opChan[i].active<<(4+i);
|
||||
if (opChan[i].keyOn) {
|
||||
|
|
|
@ -25,13 +25,28 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
struct OpChannel {
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch;
|
||||
int freq, baseFreq, pitch, portaPauseFreq;
|
||||
unsigned char ins;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
|
||||
int vol;
|
||||
unsigned char pan;
|
||||
OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {}
|
||||
OpChannel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
portaPauseFreq(0),
|
||||
ins(-1),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
portaPause(false),
|
||||
vol(0),
|
||||
pan(3) {}
|
||||
};
|
||||
OpChannel opChan[4];
|
||||
bool isOpMuted[4];
|
||||
|
|
|
@ -324,6 +324,7 @@ struct DivSong {
|
|||
bool ignoreDACModeOutsideIntendedChannel;
|
||||
bool e1e2AlsoTakePriority;
|
||||
bool newSegaPCM;
|
||||
bool fbPortaPause;
|
||||
|
||||
DivOrders orders;
|
||||
std::vector<DivInstrument*> ins;
|
||||
|
@ -406,7 +407,8 @@ struct DivSong {
|
|||
sharedExtStat(true),
|
||||
ignoreDACModeOutsideIntendedChannel(false),
|
||||
e1e2AlsoTakePriority(false),
|
||||
newSegaPCM(true) {
|
||||
newSegaPCM(true),
|
||||
fbPortaPause(false) {
|
||||
for (int i=0; i<32; i++) {
|
||||
system[i]=DIV_SYSTEM_NULL;
|
||||
systemVol[i]=64;
|
||||
|
|
|
@ -101,6 +101,10 @@ void FurnaceGUI::drawCompatFlags() {
|
|||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("simulates a bug in where portamento does not work after sliding.");
|
||||
}
|
||||
ImGui::Checkbox("FM pitch slide octave boundary odd behavior",&e->song.fbPortaPause);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("if this is on, a pitch slide that crosses the octave boundary will stop for one tick and then continue from the nearest octave boundary.\nfor .dmf compatibility.");
|
||||
}
|
||||
ImGui::Checkbox("Apply Game Boy envelope on note-less instrument change",&e->song.gbInsAffectsEnvelope);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("if this is on, an instrument change will also affect the envelope.");
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <SDL_keycode.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "gui.h"
|
||||
#include "util.h"
|
||||
|
|
Loading…
Reference in a new issue