dev237 - Merge branch 'partial'

This commit is contained in:
tildearrow 2025-10-22 14:20:56 -05:00
commit 4d56e72278
82 changed files with 90 additions and 125 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -290,8 +290,9 @@ size | description
1 | limit slides (>=36) or reserved
1 | linear pitch (>=36) or reserved
| - 0: non-linear
| - 1: only pitch change (04xy/E5xx) linear
| - 2: full linear (>=94)
| - 1: only pitch change (04xy/E5xx) linear (<237) - full linear (>=237)
| - partial pitch linearity removed in 237
| - 2: full linear (>=94, <237)
1 | loop modality (>=36) or reserved
1 | proper noise layout (>=42) or reserved
1 | wave duty is volume (>=42) or reserved

View file

@ -586,7 +586,7 @@ bool DivCSPlayer::tick() {
}
if (chan[i].portaSpeed) {
e->dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(e->song.linearPitch==2?e->song.pitchSlideSpeed:1),chan[i].portaTarget));
e->dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(e->song.linearPitch?e->song.pitchSlideSpeed:1),chan[i].portaTarget));
}
if (chan[i].arp && !chan[i].portaSpeed) {
if (chan[i].arpTicks==0) {

View file

@ -1098,7 +1098,7 @@ class DivDispatch {
if ((x)<(xMin)) (x)=(xMin); \
if ((x)>(xMax)) (x)=(xMax);
#define NEW_ARP_STRAT (parent->song.linearPitch==2 && !parent->song.oldArpStrategy)
#define NEW_ARP_STRAT (parent->song.linearPitch && !parent->song.oldArpStrategy)
#define HACKY_LEGATO_MESS chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode && !NEW_ARP_STRAT
#endif

View file

@ -1780,7 +1780,7 @@ int DivEngine::calcBaseFreq(double clock, double divider, int note, bool period)
}*/
double DivEngine::calcBaseFreq(double clock, double divider, int note, bool period) {
if (song.linearPitch==2) { // full linear
if (song.linearPitch) { // linear
return (note<<7);
}
double base=(period?(song.tuning*0.0625):song.tuning)*pow(2.0,(float)(note+3)/12.0);
@ -1830,7 +1830,7 @@ double DivEngine::calcBaseFreq(double clock, double divider, int note, bool peri
return bf|((block)<<(bits));
int DivEngine::calcBaseFreqFNumBlock(double clock, double divider, int note, int bits, int fixedBlock) {
if (song.linearPitch==2) { // full linear
if (song.linearPitch) { // linear
return (note<<7);
}
int bf=calcBaseFreq(clock,divider,note,false);
@ -1842,7 +1842,8 @@ int DivEngine::calcBaseFreqFNumBlock(double clock, double divider, int note, int
}
int DivEngine::calcFreq(int base, int pitch, int arp, bool arpFixed, bool period, int octave, int pitch2, double clock, double divider, int blockBits, int fixedBlock) {
if (song.linearPitch==2) {
// linear pitch
if (song.linearPitch) {
// do frequency calculation here
int nbase=base+pitch+pitch2;
if (!song.oldArpStrategy) {
@ -1866,24 +1867,7 @@ int DivEngine::calcFreq(int base, int pitch, int arp, bool arpFixed, bool period
return bf;
}
}
if (song.linearPitch==1) {
// global pitch multiplier
int whatTheFuck=(1024+(globalPitch<<6)-(globalPitch<0?globalPitch-6:0));
if (whatTheFuck<1) whatTheFuck=1; // avoids division by zero but please kill me
if (song.pitchMacroIsLinear) {
pitch+=pitch2;
}
pitch+=2048;
if (pitch<0) pitch=0;
if (pitch>4095) pitch=4095;
int ret=period?
((base*(reversePitchTable[pitch]))/whatTheFuck):
(((base*(pitchTable[pitch]))>>10)*whatTheFuck)/1024;
if (!song.pitchMacroIsLinear) {
ret+=period?(-pitch2):pitch2;
}
return ret;
}
// non-linear pitch
return period?
base-pitch-pitch2:
base+((pitch*octave)>>1)+pitch2;
@ -2175,7 +2159,7 @@ void DivEngine::reset() {
chan[i]=DivChannelState();
if (i<chans) chan[i].volMax=(disCont[dispatchOfChan[i]].dispatch->dispatch(DivCommand(DIV_CMD_GET_VOLMAX,dispatchChanOfChan[i]))<<8)|0xff;
chan[i].volume=chan[i].volMax;
if (song.linearPitch==0) chan[i].vibratoFine=4;
if (!song.linearPitch) chan[i].vibratoFine=4;
}
extValue=0;
extValuePresent=0;
@ -4243,10 +4227,6 @@ bool DivEngine::init() {
for (int i=0; i<128; i++) {
tremTable[i]=255*0.5*(1.0-cos(((double)i/128.0)*(2*M_PI)));
}
for (int i=0; i<4096; i++) {
reversePitchTable[i]=round(1024.0*pow(2.0,(2048.0-(double)i)/(12.0*128.0)));
pitchTable[i]=round(1024.0*pow(2.0,((double)i-2048.0)/(12.0*128.0)));
}
for (int i=0; i<DIV_MAX_CHANS; i++) {
isMuted[i]=0;

View file

@ -54,8 +54,8 @@ class DivWorkPool;
#define DIV_UNSTABLE
#define DIV_VERSION "dev236"
#define DIV_ENGINE_VERSION 236
#define DIV_VERSION "dev237"
#define DIV_ENGINE_VERSION 237
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
@ -548,8 +548,6 @@ class DivEngine {
short vibTable[64];
short tremTable[128];
int reversePitchTable[4096];
int pitchTable[4096];
short effectSlotMap[4096];
int midiBaseChan;
bool midiPoly;
@ -1539,8 +1537,6 @@ class DivEngine {
memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(vibTable,0,64*sizeof(short));
memset(tremTable,0,128*sizeof(short));
memset(reversePitchTable,0,4096*sizeof(int));
memset(pitchTable,0,4096*sizeof(int));
memset(effectSlotMap,-1,4096*sizeof(short));
memset(sysDefs,0,DIV_MAX_CHIP_DEFS*sizeof(void*));
memset(romExportDefs,0,DIV_ROM_MAX*sizeof(void*));

View file

@ -2371,7 +2371,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
CHECK_BLOCK_VERSION(3);
unsigned int linear_pitch = reader.readI();
ds.linearPitch = linear_pitch == 0 ? 0 : 2;
ds.linearPitch = linear_pitch == 0 ? 0 : 1;
if (blockVersion >= 2) {
int fineTuneCents = reader.readC() * 100;

View file

@ -2175,8 +2175,10 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
}
// warn on partial pitch linearity
if (ds.linearPitch==1) {
addWarning("this song uses partial pitch linearity, which will be removed soon. please migrate to full or none by going to Compatibility Flags and then adjusting your song afterwards.");
if (ds.linearPitch>1) {
ds.linearPitch=1;
} else if (ds.version<237 && ds.linearPitch!=0) {
addWarning("this song used partial pitch linearity, which has been removed from Furnace. you may have to adjust your song.");
}
if (active) quitDispatch();

View file

@ -277,7 +277,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
}
if (flags&8) {
ds.linearPitch=2;
ds.linearPitch=1;
} else {
ds.linearPitch=0;
}
@ -1667,7 +1667,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
for (int i=0; i<(maxChan+32)>>5; i++) {
ds.system[i]=DIV_SYSTEM_ES5506;
ds.systemFlags[i].set("amigaVol",true);
if (ds.linearPitch!=2) {
if (!ds.linearPitch) {
ds.systemFlags[i].set("amigaPitch",true);
}
}

View file

@ -251,7 +251,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
unsigned short totalChans=reader.readS();
unsigned short patCount=reader.readS();
ds.insLen=(unsigned short)reader.readS();
ds.linearPitch=(reader.readS()&1)?2:0;
ds.linearPitch=(reader.readS()&1)?1:0;
ds.subsong[0]->speeds.val[0]=reader.readS();
ds.subsong[0]->speeds.len=1;
double bpm=(unsigned short)reader.readS();

View file

@ -23,7 +23,7 @@
#include <math.h>
#define PITCH_OFFSET ((double)(16*2048*(chanMax+1)))
#define NOTE_ES5506(c,note) ((amigaPitch && parent->song.linearPitch!=2)?parent->calcBaseFreq(COLOR_NTSC*16,chan[c].pcm.freqOffs,note,true):parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false))
#define NOTE_ES5506(c,note) ((amigaPitch && !parent->song.linearPitch)?parent->calcBaseFreq(COLOR_NTSC*16,chan[c].pcm.freqOffs,note,true):parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false))
#define rWrite(a,...) {if(!skipRegisterWrites) {hostIntf32.push_back(QueuedHostIntf(4,(a),__VA_ARGS__)); }}
#define immWrite(a,...) {hostIntf32.push_back(QueuedHostIntf(4,(a),__VA_ARGS__));}
@ -603,7 +603,7 @@ void DivPlatformES5506::tick(bool sysTick) {
const unsigned int length=s->samples-1;
const unsigned int end=start+(length<<11);
const unsigned int nextBank=(offES5506>>22)&3;
const double nextFreqOffs=((amigaPitch && parent->song.linearPitch!=2)?16:PITCH_OFFSET)*off;
const double nextFreqOffs=((amigaPitch && !parent->song.linearPitch)?16:PITCH_OFFSET)*off;
chan[i].pcm.loopMode=loopMode;
chan[i].pcm.bank=nextBank;
chan[i].pcm.start=start;
@ -746,7 +746,7 @@ void DivPlatformES5506::tick(bool sysTick) {
chan[i].pcm.nextPos=0;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
if (amigaPitch && parent->song.linearPitch!=2) {
if (amigaPitch && !parent->song.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch*16,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,2,chan[i].pitch2*16,16*COLOR_NTSC,chan[i].pcm.freqOffs);
chan[i].freq=PITCH_OFFSET*(COLOR_NTSC/chan[i].freq)/(chipClock/16.0);
chan[i].freq=CLAMP(chan[i].freq,0,0x1ffff);
@ -767,7 +767,7 @@ void DivPlatformES5506::tick(bool sysTick) {
}
chan[i].pcm.loopStart=(chan[i].pcm.start+(s->loopStart<<11))&0xfffff800;
chan[i].pcm.loopEnd=(chan[i].pcm.start+((s->loopEnd)<<11))&0xffffff80;
chan[i].pcm.freqOffs=((amigaPitch && parent->song.linearPitch!=2)?16:PITCH_OFFSET)*off;
chan[i].pcm.freqOffs=((amigaPitch && !parent->song.linearPitch)?16:PITCH_OFFSET)*off;
unsigned int startPos=chan[i].pcm.direction?chan[i].pcm.end:chan[i].pcm.start;
if (chan[i].pcm.nextPos) {
const unsigned int start=chan[i].pcm.start;
@ -1212,7 +1212,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
int nextFreq=chan[c.chan].baseFreq;
int destFreq=NOTE_ES5506(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (amigaPitch && parent->song.linearPitch!=2) {
if (amigaPitch && !parent->song.linearPitch) {
c.value*=16;
}
if (destFreq>nextFreq) {

View file

@ -337,7 +337,7 @@ void DivPlatformESFM::tick(bool sysTick) {
if (chan[i].freqChanged) {
int mul=2;
int fixedBlock=chan[i].state.fm.block;
if (parent->song.linearPitch!=2) {
if (!parent->song.linearPitch) {
mul=octave(chan[i].baseFreq,fixedBlock)*2;
}
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,mul,chan[i].pitch2,chipClock,CHIP_FREQBASE);
@ -569,7 +569,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
bool return2=false;
int mul=1;
int fixedBlock=0;
if (parent->song.linearPitch!=2) {
if (!parent->song.linearPitch) {
fixedBlock=chan[c.chan].state.fm.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}
@ -586,7 +586,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
return2=true;
}
}
if (!chan[c.chan].portaPause && parent->song.linearPitch!=2) {
if (!chan[c.chan].portaPause && !parent->song.linearPitch) {
if (mul!=octave(newFreq,fixedBlock)) {
chan[c.chan].portaPause=true;
break;

View file

@ -894,7 +894,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
for (int i=0; i<csmChan; i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE,11);
@ -1223,7 +1223,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {

View file

@ -169,7 +169,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -656,7 +656,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,2,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,2,opChan[i].pitch2);

View file

@ -429,7 +429,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
}
}
chan[c.chan].freqChanged=true;
if (chan[c.chan].pcm && parent->song.linearPitch==2) {
if (chan[c.chan].pcm && parent->song.linearPitch) {
chan[c.chan].sampleBaseFreq=chan[c.chan].baseFreq;
}
if (return2) {

View file

@ -386,13 +386,13 @@ int DivPlatformN163::dispatch(DivCommand c) {
int destFreq=destFreqD;
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:16);
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:16);
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch==2)?1:16);
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:16);
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;

View file

@ -406,13 +406,13 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:8);
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:8);
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch==2)?1:8);
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:8);
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;

View file

@ -1510,7 +1510,7 @@ void DivPlatformOPL::tick(bool sysTick) {
if (chan[i].freqChanged) {
int mul=2;
int fixedBlock=chan[i].state.block;
if (parent->song.linearPitch!=2) {
if (!parent->song.linearPitch) {
mul=octave(chan[i].baseFreq,fixedBlock)*2;
}
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,mul,chan[i].pitch2,chipClock,CHIP_FREQBASE);
@ -2116,7 +2116,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
bool return2=false;
int mul=1;
int fixedBlock=0;
if (parent->song.linearPitch!=2) {
if (!parent->song.linearPitch) {
fixedBlock=chan[c.chan].state.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}
@ -2133,7 +2133,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
return2=true;
}
}
if (!chan[c.chan].portaPause && parent->song.linearPitch!=2) {
if (!chan[c.chan].portaPause && !parent->song.linearPitch) {
if (mul!=octave(newFreq,fixedBlock)) {
chan[c.chan].portaPause=true;
break;

View file

@ -341,7 +341,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
if (chan[i].freqChanged) {
int mul=2;
int fixedBlock=chan[i].state.block;
if (parent->song.linearPitch!=2) {
if (!parent->song.linearPitch) {
mul=octave(chan[i].baseFreq,fixedBlock)*2;
}
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,mul,chan[i].pitch2,chipClock,CHIP_FREQBASE);
@ -684,7 +684,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
bool return2=false;
int mul=1;
int fixedBlock=0;
if (parent->song.linearPitch!=2) {
if (!parent->song.linearPitch) {
fixedBlock=chan[c.chan].state.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}

View file

@ -223,7 +223,7 @@ void DivPlatformPOKEY::tick(bool sysTick) {
}
// non-linear pitch
if (parent->song.linearPitch==0) {
if (!parent->song.linearPitch) {
chan[i].freq-=chan[i].pitch;
}

View file

@ -261,13 +261,13 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
int destFreq=NOTE_PERIODIC(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:(8-chan[c.chan].freqH));
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:(8-chan[c.chan].freqH));
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch==2)?1:(8-chan[c.chan].freqH));
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:(8-chan[c.chan].freqH));
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;

View file

@ -315,7 +315,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
case DIV_CMD_NOTE_PORTA: {
int destFreq=((c.value2+chan[c.chan].sampleNoteDelta)<<7);
int newFreq;
int mul=(oldSlides || parent->song.linearPitch!=2)?8:1;
int mul=(oldSlides || !parent->song.linearPitch)?8:1;
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
newFreq=chan[c.chan].baseFreq+c.value*mul;

View file

@ -267,13 +267,13 @@ int DivPlatformSM8521::dispatch(DivCommand c) {
int destFreq=NOTE_PERIODIC(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:8);
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:8);
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch==2)?1:8);
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:8);
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;

View file

@ -189,7 +189,7 @@ void DivPlatformSMS::acquireDirect(blip_buffer_t** bb, size_t len) {
double DivPlatformSMS::NOTE_SN(int ch, int note) {
double CHIP_DIVIDER=toneDivider;
if (ch==3) CHIP_DIVIDER=noiseDivider;
if (parent->song.linearPitch==2 || !easyNoise) {
if (parent->song.linearPitch || !easyNoise) {
return NOTE_PERIODIC(note);
}
int easyStartingPeriod=16;
@ -209,7 +209,7 @@ int DivPlatformSMS::snCalcFreq(int ch) {
if (chan[ch].fixedArp) {
curFreq=chan[ch].baseNoteOverride<<7;
}
if (parent->song.linearPitch==2 && easyNoise && curFreq>easyThreshold) {
if (parent->song.linearPitch && easyNoise && curFreq>easyThreshold) {
int ret=(((easyStartingPeriod<<7))-(curFreq-(easyThreshold)))>>7;
if (ret<0) ret=0;
return ret;

View file

@ -484,13 +484,13 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
int destFreq=NOTE_SU(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch==2)?1:(1+(chan[c.chan].baseFreq>>9)));
chan[c.chan].baseFreq+=c.value*((parent->song.linearPitch)?1:(1+(chan[c.chan].baseFreq>>9)));
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch==2)?1:(1+(chan[c.chan].baseFreq>>9)));
chan[c.chan].baseFreq-=c.value*((parent->song.linearPitch)?1:(1+(chan[c.chan].baseFreq>>9)));
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;

View file

@ -95,7 +95,7 @@ void DivPlatformT6W28::writeOutVol(int ch) {
double DivPlatformT6W28::NOTE_SN(int ch, int note) {
double CHIP_DIVIDER=16;
if (ch==3) CHIP_DIVIDER=15;
if (parent->song.linearPitch==2 || !easyNoise) {
if (parent->song.linearPitch || !easyNoise) {
return NOTE_PERIODIC(note);
}
if (note>107) {
@ -105,7 +105,7 @@ double DivPlatformT6W28::NOTE_SN(int ch, int note) {
}
int DivPlatformT6W28::snCalcFreq(int ch) {
if (parent->song.linearPitch==2 && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(107<<7)) {
if (parent->song.linearPitch && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(107<<7)) {
int ret=(((13<<7)+0x40)-(chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2-(107<<7)))>>7;
if (ret<0) ret=0;
return ret;

View file

@ -321,7 +321,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
}
// fixed pitch
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
bool freqChangeOp=false;
if (op.egt) {

View file

@ -661,7 +661,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
for (int i=0; i<3; i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2);
@ -867,7 +867,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
}
break;
}
if (c.chan>(psgChanOffs-1) || parent->song.linearPitch==2) { // PSG
if (c.chan>(psgChanOffs-1) || parent->song.linearPitch) { // PSG
int destFreq=NOTE_FNUM_BLOCK(c.value2,11,chan[c.chan].state.block);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {

View file

@ -146,7 +146,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -551,7 +551,7 @@ void DivPlatformYM2203Ext::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2);

View file

@ -916,7 +916,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
for (int i=0; i<6; i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2);
@ -1395,7 +1395,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
}
break;
}
if (c.chan>(5+isCSM) || parent->song.linearPitch==2) { // PSG, ADPCM-B
if (c.chan>(5+isCSM) || parent->song.linearPitch) { // PSG, ADPCM-B
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {

View file

@ -166,7 +166,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -612,7 +612,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2);

View file

@ -836,7 +836,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
for (int i=0; i<(psgChanOffs-isCSM); i++) {
if (i==1 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11);
@ -1354,7 +1354,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
}
break;
}
if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B
if (c.chan>=psgChanOffs || parent->song.linearPitch) { // PSG, ADPCM-B
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {

View file

@ -905,7 +905,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
for (int i=0; i<(psgChanOffs-isCSM); i++) {
if (i==2 && extMode) continue;
if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[i].state.block);
} else {
int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,4,chan[i].pitch2);
@ -1423,7 +1423,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
}
break;
}
if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B
if (c.chan>=psgChanOffs || parent->song.linearPitch) { // PSG, ADPCM-B
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {

View file

@ -162,7 +162,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -604,7 +604,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2);

View file

@ -162,7 +162,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
@ -604,7 +604,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
unsigned char hardResetMask=0;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) {
if (parent->song.linearPitch) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11,chan[extChanOffs].state.block);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,4,opChan[i].pitch2);

View file

@ -287,7 +287,7 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
case DIV_CMD_NOTE_PORTA: {
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
bool return2=false;
int multiplier=(parent->song.linearPitch==2)?1:256;
int multiplier=(parent->song.linearPitch)?1:256;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value*multiplier;
if (chan[c.chan].baseFreq>=destFreq) {

View file

@ -1699,7 +1699,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].inPorta=false;
// COMPAT FLAG: arpeggio inhibits non-porta slides
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,0));
dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.linearPitch==2?song.pitchSlideSpeed:1),chan[i].portaNote));
dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.linearPitch?song.pitchSlideSpeed:1),chan[i].portaNote));
chan[i].portaNote=-1;
chan[i].portaSpeed=-1;
chan[i].inPorta=false;
@ -2420,11 +2420,10 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
// it returns whether the portamento is complete and has reached the target note.
// COMPAT FLAG: pitch linearity
// - 0: none (pitch control and slides non-linear)
// - 1: partial (pitch control linear; pitch slides non-linear)
// - 2: full (pitch slides linear... we multiply the portamento speed by a user-defined multiplier)
// - 1: full (pitch slides linear... we multiply the portamento speed by a user-defined multiplier)
// COMPAT FLAG: reset pitch slide/portamento upon reaching target (inverted in the GUI)
// - when disabled, portamento remains active after it has finished
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.linearPitch==2?song.pitchSlideSpeed:1),chan[i].portaNote))==2 && chan[i].portaStop && song.targetResetsSlides) {
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed*(song.linearPitch?song.pitchSlideSpeed:1),chan[i].portaNote))==2 && chan[i].portaStop && song.targetResetsSlides) {
// if we are here, it means we reached the target and shall stop
chan[i].portaSpeed=0;
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
@ -3356,6 +3355,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
float decay=2.f*size/got.rate;
for (int i=0; i<song.systemLen; i++) {
DivDispatch* disp=disCont[i].dispatch;
if (disp==NULL) continue;
for (int j=0; j<disp->getOutputCount(); j++) {
chipPeak[i][j]*=1.0-decay;
float peak=chipPeak[i][j];

View file

@ -281,9 +281,6 @@ struct DivSong {
// compatibility flags
bool limitSlides;
// linear pitch
// 0: not linear
// 1: only pitch changes (04xy/E5xx) linear
// 2: full linear
unsigned char linearPitch;
unsigned char pitchSlideSpeed;
// loop behavior
@ -428,7 +425,7 @@ struct DivSong {
masterVol(1.0f),
tuning(440.0f),
limitSlides(false),
linearPitch(2),
linearPitch(1),
pitchSlideSpeed(4),
loopModality(2),
delayBehavior(2),

View file

@ -302,26 +302,15 @@ void FurnaceGUI::drawCompatFlags() {
if (ImGui::BeginTabItem(_("Pitch/Playback"))) {
ImGui::Text(_("Pitch linearity:"));
ImGui::Indent();
if (ImGui::RadioButton(_("None"),e->song.linearPitch==0)) {
if (ImGui::RadioButton(_("None"),!e->song.linearPitch)) {
e->song.linearPitch=0;
MARK_MODIFIED;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(_("like ProTracker/FamiTracker"));
}
if (e->song.linearPitch==1) {
pushWarningColor(true);
if (ImGui::RadioButton(_("Partial (only 04xy/E5xx)"),e->song.linearPitch==1)) {
e->song.linearPitch=1;
MARK_MODIFIED;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(_("like DefleMask\n\nthis pitch linearity mode is deprecated due to:\n- excessive complexity\n- lack of possible optimization\n\nit is recommended to change it now because I will remove this option in the future!"));
}
popWarningColor();
}
if (ImGui::RadioButton(_("Full"),e->song.linearPitch==2)) {
e->song.linearPitch=2;
if (ImGui::RadioButton(_("Full"),e->song.linearPitch)) {
e->song.linearPitch=1;
MARK_MODIFIED;
}
if (ImGui::IsItemHovered()) {

View file

@ -540,7 +540,7 @@ void FurnaceGUI::drawExport() {
ImGui::CloseCurrentPopup();
}
if (ImGui::Button(_("Set pitch linearity to Partial"))) {
e->song.linearPitch=1;
showError(_("No!"));
ImGui::CloseCurrentPopup();
}
if (ImGui::Button(_("Set fat to max"))) {

View file

@ -4694,7 +4694,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
op.egt=egtOn;
}
if (egtOn) {
pushWarningColor(susOn && e->song.linearPitch!=2);
pushWarningColor(susOn && !e->song.linearPitch);
if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER
op.sus=susOn;
// HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly
@ -4703,7 +4703,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
}
popWarningColor();
if (ImGui::IsItemHovered()) {
if (susOn && e->song.linearPitch!=2) {
if (susOn && !e->song.linearPitch) {
ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full."));
} else {
ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros"));
@ -5470,7 +5470,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
P(CWSliderScalar("##FINE",ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN,tempID)); rightClickable
} else {
bool susOn=op.sus;
pushWarningColor(susOn && e->song.linearPitch!=2);
pushWarningColor(susOn && !e->song.linearPitch);
if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER
op.sus=susOn;
// HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly
@ -5479,7 +5479,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
}
popWarningColor();
if (ImGui::IsItemHovered()) {
if (susOn && e->song.linearPitch!=2) {
if (susOn && !e->song.linearPitch) {
ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full."));
} else {
ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros"));
@ -5793,7 +5793,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
bool susOn=op.sus;
if (fixedOn) {
ImGui::SameLine();
pushWarningColor(susOn && e->song.linearPitch!=2);
pushWarningColor(susOn && !e->song.linearPitch);
if (ImGui::Checkbox(_("Pitch control"),&susOn)) { PARAMETER
op.sus=susOn;
// HACK: reset zoom and scroll in fixed pitch macros so that they draw correctly
@ -5802,7 +5802,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
}
popWarningColor();
if (ImGui::IsItemHovered()) {
if (susOn && e->song.linearPitch!=2) {
if (susOn && !e->song.linearPitch) {
ImGui::SetTooltip(_("only works on linear pitch! go to Compatibility Flags > Pitch/Playback and set Pitch linearity to Full."));
} else {
ImGui::SetTooltip(_("use op's arpeggio and pitch macros control instead of block/f-num macros"));

View file

@ -1321,11 +1321,11 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
if (ImGui::Checkbox(_("Amiga channel volumes (64)"),&amigaVol)) {
altered=true;
}
pushWarningColor(amigaPitch && e->song.linearPitch==2);
pushWarningColor(amigaPitch && e->song.linearPitch);
if (ImGui::Checkbox(_("Amiga-like pitch (non-linear pitch only)"),&amigaPitch)) {
altered=true;
}
if (amigaPitch && e->song.linearPitch==2) {
if (amigaPitch && e->song.linearPitch) {
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("pitch linearity is set to linear. this won't do anything!");
}