Add fixed octave for block+fnum systems

This isn't implemented in SAA1099, despite also being block+fnum system, as there are no benefits from it
This commit is contained in:
Natt Akuma 2024-09-18 14:48:10 +07:00
parent 6a58797669
commit cf3d08ca5a
25 changed files with 194 additions and 97 deletions

View file

@ -192,6 +192,7 @@ size | description
1 | |x| ALG |x| FB | 1 | |x| ALG |x| FB |
1 | |FMS2 |AMS| FMS | 1 | |FMS2 |AMS| FMS |
1 | |AM2|4| LLPatch | 1 | |AM2|4| LLPatch |
1 | |xxxxxxx| Block | (>=224)
-----|------------------------------------ -----|------------------------------------
| **operator data × opCount** | **operator data × opCount**
| /7 6 5 4 3 2 1 0| | /7 6 5 4 3 2 1 0|

View file

@ -948,7 +948,7 @@ class DivDispatch {
#define NOTE_FREQUENCY(x) parent->calcBaseFreq(chipClock,CHIP_FREQBASE,x,false) #define NOTE_FREQUENCY(x) parent->calcBaseFreq(chipClock,CHIP_FREQBASE,x,false)
// this is a special case definition. only use it for f-num/block-based chips. // this is a special case definition. only use it for f-num/block-based chips.
#define NOTE_FNUM_BLOCK(x,bits) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits) #define NOTE_FNUM_BLOCK(x,bits,ins) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits,parent->getIns(ins)->fm.block)
// this is for volume scaling calculation. // this is for volume scaling calculation.
#define VOL_SCALE_LINEAR(x,y,range) ((parent->song.ceilVolumeScaling)?((((x)*(y))+(range-1))/(range)):(((x)*(y))/(range))) #define VOL_SCALE_LINEAR(x,y,range) ((parent->song.ceilVolumeScaling)?((((x)*(y))+(range-1))/(range)):(((x)*(y))/(range)))

View file

@ -1797,15 +1797,27 @@ double DivEngine::calcBaseFreq(double clock, double divider, int note, bool peri
/* logV("f-num: %d block: %d",bf,block); */ \ /* logV("f-num: %d block: %d",bf,block); */ \
return bf|(block<<bits); return bf|(block<<bits);
int DivEngine::calcBaseFreqFNumBlock(double clock, double divider, int note, int bits) { #define CONVERT_FNUM_FIXEDBLOCK(bf,bits,block) \
bf>>=(block); \
if (bf<0) bf=0; \
if (bf>((1<<(bits))-1)) { \
bf=(1<<(bits))-1; \
} \
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==2) { // full linear
return (note<<7); return (note<<7);
} }
int bf=calcBaseFreq(clock,divider,note,false); int bf=calcBaseFreq(clock,divider,note,false);
CONVERT_FNUM_BLOCK(bf,bits,note) if (fixedBlock>0) {
CONVERT_FNUM_FIXEDBLOCK(bf,bits,fixedBlock-1);
} else {
CONVERT_FNUM_BLOCK(bf,bits,note);
}
} }
int DivEngine::calcFreq(int base, int pitch, int arp, bool arpFixed, bool period, int octave, int pitch2, double clock, double divider, int blockBits) { 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) { if (song.linearPitch==2) {
// do frequency calculation here // do frequency calculation here
int nbase=base+pitch+pitch2; int nbase=base+pitch+pitch2;
@ -1821,7 +1833,11 @@ int DivEngine::calcFreq(int base, int pitch, int arp, bool arpFixed, bool period
round((clock/fbase)/divider): round((clock/fbase)/divider):
round(fbase*(divider/clock)); round(fbase*(divider/clock));
if (blockBits>0) { if (blockBits>0) {
CONVERT_FNUM_BLOCK(bf,blockBits,nbase>>7) if (fixedBlock>0) {
CONVERT_FNUM_FIXEDBLOCK(bf,blockBits,fixedBlock-1);
} else {
CONVERT_FNUM_BLOCK(bf,blockBits,nbase>>7);
}
} else { } else {
return bf; return bf;
} }

View file

@ -54,8 +54,8 @@ class DivWorkPool;
#define DIV_UNSTABLE #define DIV_UNSTABLE
#define DIV_VERSION "dev223" #define DIV_VERSION "dev224"
#define DIV_ENGINE_VERSION 223 #define DIV_ENGINE_VERSION 224
// for imports // for imports
#define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02 #define DIV_VERSION_FC 0xff02
@ -805,10 +805,10 @@ class DivEngine {
double calcBaseFreq(double clock, double divider, int note, bool period); double calcBaseFreq(double clock, double divider, int note, bool period);
// calculate base frequency in f-num/block format // calculate base frequency in f-num/block format
int calcBaseFreqFNumBlock(double clock, double divider, int note, int bits); int calcBaseFreqFNumBlock(double clock, double divider, int note, int bits, int fixedBlock);
// calculate frequency/period // calculate frequency/period
int calcFreq(int base, int pitch, int arp, bool arpFixed, bool period=false, int octave=0, int pitch2=0, double clock=1.0, double divider=1.0, int blockBits=0); int calcFreq(int base, int pitch, int arp, bool arpFixed, bool period=false, int octave=0, int pitch2=0, double clock=1.0, double divider=1.0, int blockBits=0, int fixedBlock=0);
// calculate arpeggio // calculate arpeggio
int calcArp(int note, int arp, int offset=0); int calcArp(int note, int arp, int offset=0);

View file

@ -409,6 +409,7 @@ void DivInstrument::writeFeatureFM(SafeWriter* w, bool fui) {
w->writeC(((fm.alg&7)<<4)|(fm.fb&7)); w->writeC(((fm.alg&7)<<4)|(fm.fb&7));
w->writeC(((fm.fms2&7)<<5)|((fm.ams&3)<<3)|(fm.fms&7)); w->writeC(((fm.fms2&7)<<5)|((fm.ams&3)<<3)|(fm.fms&7));
w->writeC(((fm.ams2&3)<<6)|((fm.ops==4)?32:0)|(fm.opllPreset&31)); w->writeC(((fm.ams2&3)<<6)|((fm.ops==4)?32:0)|(fm.opllPreset&31));
w->writeC(fm.block&15);
// operator data // operator data
for (int i=0; i<opCount; i++) { for (int i=0; i<opCount; i++) {
@ -1741,6 +1742,11 @@ void DivInstrument::readFeatureFM(SafeReader& reader, short version) {
fm.ops=(next&32)?4:2; fm.ops=(next&32)?4:2;
fm.opllPreset=next&31; fm.opllPreset=next&31;
if (version>=224) {
next=reader.readC();
fm.block=next&15;
}
// read operators // read operators
for (int i=0; i<opCount; i++) { for (int i=0; i<opCount; i++) {
DivInstrumentFM::Operator& op=fm.op[i]; DivInstrumentFM::Operator& op=fm.op[i];

View file

@ -165,7 +165,7 @@ enum DivMacroTypeOp: unsigned char {
// - WS, DVB = MULT (FINE), DAM = REV, KSL = EGShift, EGT = Fixed // - WS, DVB = MULT (FINE), DAM = REV, KSL = EGShift, EGT = Fixed
struct DivInstrumentFM { struct DivInstrumentFM {
unsigned char alg, fb, fms, ams, fms2, ams2, ops, opllPreset; unsigned char alg, fb, fms, ams, fms2, ams2, ops, opllPreset, block;
bool fixedDrums; bool fixedDrums;
unsigned short kickFreq, snareHatFreq, tomTopFreq; unsigned short kickFreq, snareHatFreq, tomTopFreq;
@ -216,6 +216,7 @@ struct DivInstrumentFM {
ams2(0), ams2(0),
ops(2), ops(2),
opllPreset(0), opllPreset(0),
block(0),
fixedDrums(false), fixedDrums(false),
kickFreq(0x520), kickFreq(0x520),
snareHatFreq(0x550), snareHatFreq(0x550),

View file

@ -292,7 +292,12 @@ void DivPlatformESFM::tick(bool sysTick) {
for (int i=0; i<18; i++) { for (int i=0; i<18; i++) {
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,octave(chan[i].baseFreq)*2,chan[i].pitch2,chipClock,CHIP_FREQBASE); int mul=2;
int fixedBlock=parent->getIns(chan[i].ins)->fm.block;
if (parent->song.linearPitch!=2) {
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);
if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>131071) chan[i].freq=131071; if (chan[i].freq>131071) chan[i].freq=131071;
@ -315,10 +320,10 @@ void DivPlatformESFM::tick(bool sysTick) {
if(chan[i].opsState[o].hasOpPitch) { if(chan[i].opsState[o].hasOpPitch) {
pitch2=chan[i].opsState[o].pitch2+dt; pitch2=chan[i].opsState[o].pitch2+dt;
} }
int opFreq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,arp,fixedArp,false,octave(chan[i].baseFreq)*2,pitch2,chipClock,CHIP_FREQBASE); int opFreq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,arp,fixedArp,false,mul,pitch2,chipClock,CHIP_FREQBASE);
if (opFreq<0) opFreq=0; if (opFreq<0) opFreq=0;
if (opFreq>131071) opFreq=131071; if (opFreq>131071) opFreq=131071;
int freqt=toFreq(opFreq); int freqt=toFreq(opFreq,fixedBlock);
chan[i].freqL[o]=freqt&0xff; chan[i].freqL[o]=freqt&0xff;
chan[i].freqH[o]=freqt>>8; chan[i].freqH[o]=freqt>>8;
} }
@ -366,16 +371,23 @@ void DivPlatformESFM::tick(bool sysTick) {
} }
} }
int DivPlatformESFM::octave(int freq) { int DivPlatformESFM::octave(int freq, int fixedBlock) {
if (fixedBlock>0) {
return 1<<(fixedBlock-1);
}
if (freq>0x3ff) { if (freq>0x3ff) {
return 1<<(bsr32(freq)-10); return 1<<(bsr32(freq)-10);
} }
return 1; return 1;
} }
int DivPlatformESFM::toFreq(int freq) { int DivPlatformESFM::toFreq(int freq, int fixedBlock) {
int block=0; int block=0;
if (freq>0x3ff) { if (fixedBlock>0) {
block=fixedBlock-1;
freq>>=block;
if (freq>0x3ff) freq=0x3ff;
} else if (freq>0x3ff) {
block=bsr32(freq)-10; block=bsr32(freq)-10;
freq>>=block; freq>>=block;
} }
@ -512,21 +524,27 @@ int DivPlatformESFM::dispatch(DivCommand c) {
int destFreq=NOTE_FREQUENCY(c.value2); int destFreq=NOTE_FREQUENCY(c.value2);
int newFreq; int newFreq;
bool return2=false; bool return2=false;
int mul=1;
int fixedBlock=0;
if (parent->song.linearPitch!=2) {
fixedBlock=parent->getIns(chan[c.chan].ins)->fm.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}
if (destFreq>chan[c.chan].baseFreq) { if (destFreq>chan[c.chan].baseFreq) {
newFreq=chan[c.chan].baseFreq+c.value*((parent->song.linearPitch==2)?1:octave(chan[c.chan].baseFreq)); newFreq=chan[c.chan].baseFreq+c.value*mul;
if (newFreq>=destFreq) { if (newFreq>=destFreq) {
newFreq=destFreq; newFreq=destFreq;
return2=true; return2=true;
} }
} else { } else {
newFreq=chan[c.chan].baseFreq-c.value*((parent->song.linearPitch==2)?1:octave(chan[c.chan].baseFreq)); newFreq=chan[c.chan].baseFreq-c.value*mul;
if (newFreq<=destFreq) { if (newFreq<=destFreq) {
newFreq=destFreq; newFreq=destFreq;
return2=true; return2=true;
} }
} }
if (!chan[c.chan].portaPause && parent->song.linearPitch!=2) { if (!chan[c.chan].portaPause && parent->song.linearPitch!=2) {
if (octave(chan[c.chan].baseFreq)!=octave(newFreq)) { if (mul!=octave(newFreq,fixedBlock)) {
chan[c.chan].portaPause=true; chan[c.chan].portaPause=true;
break; break;
} }

View file

@ -126,8 +126,8 @@ class DivPlatformESFM: public DivDispatch {
short oldWrites[ESFM_REG_POOL_SIZE]; short oldWrites[ESFM_REG_POOL_SIZE];
short pendingWrites[ESFM_REG_POOL_SIZE]; short pendingWrites[ESFM_REG_POOL_SIZE];
int octave(int freq); int octave(int freq, int fixedBlock);
int toFreq(int freq); int toFreq(int freq, int fixedBlock);
void commitState(int ch, DivInstrument* ins); void commitState(int ch, DivInstrument* ins);
friend void putDispatchChip(void*,int); friend void putDispatchChip(void*,int);

View file

@ -27,7 +27,7 @@
#define PLEASE_HELP_ME(_targetChan) \ #define PLEASE_HELP_ME(_targetChan) \
int boundaryBottom=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,0,false); \ int boundaryBottom=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,0,false); \
int boundaryTop=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,12,false); \ int boundaryTop=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,12,false); \
int destFreq=NOTE_FNUM_BLOCK(c.value2,11); \ int destFreq=NOTE_FNUM_BLOCK(c.value2,11,_targetChan.ins); \
int newFreq; \ int newFreq; \
bool return2=false; \ bool return2=false; \
if (_targetChan.portaPause) { \ if (_targetChan.portaPause) { \

View file

@ -657,7 +657,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
chan[i].handleArp(); chan[i].handleArp();
} else if (chan[i].std.arp.had) { } else if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11,chan[i].ins);
} }
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -838,7 +838,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
if (i==2 && extMode) continue; if (i==2 && extMode) continue;
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==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,2,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(chan[i].baseFreq&0xf800)>>11; int block=(chan[i].baseFreq&0xf800)>>11;
@ -1084,7 +1084,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11,chan[c.chan].ins);
chan[c.chan].portaPause=false; chan[c.chan].portaPause=false;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
@ -1274,7 +1274,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
commitState(c.chan,ins); commitState(c.chan,ins);
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
} }
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11,chan[c.chan].ins);
} }
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;

View file

@ -96,7 +96,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].portaPause=false; opChan[ch].portaPause=false;
opChan[ch].note=c.value; opChan[ch].note=c.value;
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
@ -216,7 +216,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
commitStateExt(ch,ins); commitStateExt(ch,ins);
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
} }
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
break; break;
} }
@ -517,7 +517,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
if (opChan[i].std.arp.had) { if (opChan[i].std.arp.had) {
if (!opChan[i].inPorta) { if (!opChan[i].inPorta) {
opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11); opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11,opChan[i].ins);
} }
opChan[i].freqChanged=true; opChan[i].freqChanged=true;
} }
@ -638,7 +638,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
if (extMode) for (int i=0; i<4; i++) { if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) { if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==2) {
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); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(opChan[i].baseFreq&0xf800)>>11; int block=(opChan[i].baseFreq&0xf800)>>11;

View file

@ -1433,11 +1433,16 @@ void DivPlatformOPL::tick(bool sysTick) {
} }
} else { } else {
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,octave(chan[i].baseFreq)*2,chan[i].pitch2,chipClock,CHIP_FREQBASE); int mul=2;
int fixedBlock=parent->getIns(chan[i].ins)->fm.block;
if (parent->song.linearPitch!=2) {
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);
if (chan[i].fixedFreq>0) chan[i].freq=chan[i].fixedFreq; if (chan[i].fixedFreq>0) chan[i].freq=chan[i].fixedFreq;
if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>131071) chan[i].freq=131071; if (chan[i].freq>131071) chan[i].freq=131071;
int freqt=toFreq(chan[i].freq); int freqt=toFreq(chan[i].freq,fixedBlock);
chan[i].freqH=freqt>>8; chan[i].freqH=freqt>>8;
chan[i].freqL=freqt&0xff; chan[i].freqL=freqt&0xff;
immWrite(chanMap[i]+ADDR_FREQ,chan[i].freqL); immWrite(chanMap[i]+ADDR_FREQ,chan[i].freqL);
@ -1501,16 +1506,26 @@ void DivPlatformOPL::tick(bool sysTick) {
#define OPLL_C_NUM 686 #define OPLL_C_NUM 686
int DivPlatformOPL::octave(int freq) { int DivPlatformOPL::octave(int freq, int fixedBlock) {
if (fixedBlock>0) {
return 1<<(fixedBlock-1);
}
freq/=OPLL_C_NUM; freq/=OPLL_C_NUM;
if (freq==0) return 1; if (freq==0) return 1;
return 1<<bsr(freq); return 1<<bsr(freq);
} }
int DivPlatformOPL::toFreq(int freq) { int DivPlatformOPL::toFreq(int freq, int fixedBlock) {
int block=freq/OPLL_C_NUM; int block=0;
if (fixedBlock>0) {
block=fixedBlock-1;
} else {
block=freq/OPLL_C_NUM;
if (block>0) block=bsr(block); if (block>0) block=bsr(block);
return (block<<10)|((freq>>block)&0x3ff); }
freq>>=block;
if (freq>0x3ff) freq=0x3ff;
return (block<<10)|freq;
} }
void DivPlatformOPL::muteChannel(int ch, bool mute) { void DivPlatformOPL::muteChannel(int ch, bool mute) {
@ -2020,21 +2035,27 @@ int DivPlatformOPL::dispatch(DivCommand c) {
int destFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value2)):(NOTE_FREQUENCY(c.value2)); int destFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value2)):(NOTE_FREQUENCY(c.value2));
int newFreq; int newFreq;
bool return2=false; bool return2=false;
int mul=1;
int fixedBlock=0;
if (parent->song.linearPitch!=2) {
fixedBlock=parent->getIns(chan[c.chan].ins)->fm.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}
if (destFreq>chan[c.chan].baseFreq) { if (destFreq>chan[c.chan].baseFreq) {
newFreq=chan[c.chan].baseFreq+c.value*((parent->song.linearPitch==2)?1:octave(chan[c.chan].baseFreq)); newFreq=chan[c.chan].baseFreq+c.value*mul;
if (newFreq>=destFreq) { if (newFreq>=destFreq) {
newFreq=destFreq; newFreq=destFreq;
return2=true; return2=true;
} }
} else { } else {
newFreq=chan[c.chan].baseFreq-c.value*((parent->song.linearPitch==2)?1:octave(chan[c.chan].baseFreq)); newFreq=chan[c.chan].baseFreq-c.value*mul;
if (newFreq<=destFreq) { if (newFreq<=destFreq) {
newFreq=destFreq; newFreq=destFreq;
return2=true; return2=true;
} }
} }
if (!chan[c.chan].portaPause && parent->song.linearPitch!=2) { if (!chan[c.chan].portaPause && parent->song.linearPitch!=2) {
if (octave(chan[c.chan].baseFreq)!=octave(newFreq)) { if (mul!=octave(newFreq,fixedBlock)) {
chan[c.chan].portaPause=true; chan[c.chan].portaPause=true;
break; break;
} }

View file

@ -169,8 +169,8 @@ class DivPlatformOPL: public DivDispatch {
DivMemoryComposition memCompo; DivMemoryComposition memCompo;
int octave(int freq); int octave(int freq, int fixedBlock);
int toFreq(int freq); int toFreq(int freq, int fixedBlock);
double NOTE_ADPCMB(int note); double NOTE_ADPCMB(int note);
void commitState(int ch, DivInstrument* ins); void commitState(int ch, DivInstrument* ins);

View file

@ -295,11 +295,16 @@ void DivPlatformOPLL::tick(bool sysTick) {
for (int i=0; i<11; i++) { for (int i=0; i<11; i++) {
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,octave(chan[i].baseFreq)*2,chan[i].pitch2,chipClock,CHIP_FREQBASE); int mul=2;
int fixedBlock=parent->getIns(chan[i].ins)->fm.block;
if (parent->song.linearPitch!=2) {
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);
if (chan[i].fixedFreq>0 && properDrums) chan[i].freq=chan[i].fixedFreq; if (chan[i].fixedFreq>0 && properDrums) chan[i].freq=chan[i].fixedFreq;
if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>65535) chan[i].freq=65535; if (chan[i].freq>65535) chan[i].freq=65535;
int freqt=toFreq(chan[i].freq); int freqt=toFreq(chan[i].freq,fixedBlock);
if (freqt>4095) freqt=4095; if (freqt>4095) freqt=4095;
chan[i].freqL=freqt&0xff; chan[i].freqL=freqt&0xff;
if (i>=6 && properDrums && (i<9 || !noTopHatFreq)) { if (i>=6 && properDrums && (i<9 || !noTopHatFreq)) {
@ -352,16 +357,26 @@ void DivPlatformOPLL::tick(bool sysTick) {
#define OPLL_C_NUM 343 #define OPLL_C_NUM 343
int DivPlatformOPLL::octave(int freq) { int DivPlatformOPLL::octave(int freq, int fixedBlock) {
if (fixedBlock>0) {
return 1<<(fixedBlock-1);
}
freq/=OPLL_C_NUM; freq/=OPLL_C_NUM;
if (freq==0) return 1; if (freq==0) return 1;
return 1<<bsr(freq); return 1<<bsr(freq);
} }
int DivPlatformOPLL::toFreq(int freq) { int DivPlatformOPLL::toFreq(int freq, int fixedBlock) {
int block=freq/OPLL_C_NUM; int block=0;
if (fixedBlock>0) {
block=fixedBlock-1;
} else {
block=freq/OPLL_C_NUM;
if (block>0) block=bsr(block); if (block>0) block=bsr(block);
return (block<<9)|((freq>>block)&0x1ff); }
freq>>=block;
if (freq>0x1ff) freq=0x1ff;
return (block<<9)|freq;
} }
void DivPlatformOPLL::muteChannel(int ch, bool mute) { void DivPlatformOPLL::muteChannel(int ch, bool mute) {
@ -622,21 +637,27 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
int destFreq=NOTE_FREQUENCY(c.value2); int destFreq=NOTE_FREQUENCY(c.value2);
int newFreq; int newFreq;
bool return2=false; bool return2=false;
int mul=1;
int fixedBlock=0;
if (parent->song.linearPitch!=2) {
fixedBlock=parent->getIns(chan[c.chan].ins)->fm.block;
mul=octave(chan[c.chan].baseFreq,fixedBlock);
}
if (destFreq>chan[c.chan].baseFreq) { if (destFreq>chan[c.chan].baseFreq) {
newFreq=chan[c.chan].baseFreq+c.value*((parent->song.linearPitch==2)?1:octave(chan[c.chan].baseFreq)); newFreq=chan[c.chan].baseFreq+c.value*mul;
if (newFreq>=destFreq) { if (newFreq>=destFreq) {
newFreq=destFreq; newFreq=destFreq;
return2=true; return2=true;
} }
} else { } else {
newFreq=chan[c.chan].baseFreq-c.value*((parent->song.linearPitch==2)?1:octave(chan[c.chan].baseFreq)); newFreq=chan[c.chan].baseFreq-c.value*mul;
if (newFreq<=destFreq) { if (newFreq<=destFreq) {
newFreq=destFreq; newFreq=destFreq;
return2=true; return2=true;
} }
} }
/*if (!chan[c.chan].portaPause) { /*if (!chan[c.chan].portaPause) {
if (octave(chan[c.chan].baseFreq)!=octave(newFreq)) { if (mul!=octave(newFreq,fixedBlock)) {
chan[c.chan].portaPause=true; chan[c.chan].portaPause=true;
break; break;
} }

View file

@ -80,8 +80,8 @@ class DivPlatformOPLL: public DivDispatch {
short oldWrites[256]; short oldWrites[256];
short pendingWrites[256]; short pendingWrites[256];
int octave(int freq); int octave(int freq, int fixedBlock);
int toFreq(int freq); int toFreq(int freq, int fixedBlock);
void commitState(int ch, DivInstrument* ins); void commitState(int ch, DivInstrument* ins);
void switchMode(bool mode); void switchMode(bool mode);

View file

@ -503,7 +503,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
chan[i].handleArp(); chan[i].handleArp();
} else if (chan[i].std.arp.had) { } else if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11,chan[i].ins);
} }
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -638,7 +638,7 @@ void DivPlatformYM2203::tick(bool sysTick) {
if (i==2 && extMode) continue; if (i==2 && extMode) continue;
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==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,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(chan[i].baseFreq&0xf800)>>11; int block=(chan[i].baseFreq&0xf800)>>11;
@ -760,7 +760,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11,chan[c.chan].ins);
chan[c.chan].portaPause=false; chan[c.chan].portaPause=false;
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
@ -844,7 +844,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
break; break;
} }
if (c.chan>(psgChanOffs-1) || parent->song.linearPitch==2) { // PSG if (c.chan>(psgChanOffs-1) || parent->song.linearPitch==2) { // PSG
int destFreq=NOTE_FNUM_BLOCK(c.value2,11); int destFreq=NOTE_FNUM_BLOCK(c.value2,11,chan[c.chan].ins);
bool return2=false; bool return2=false;
if (destFreq>chan[c.chan].baseFreq) { if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value; chan[c.chan].baseFreq+=c.value;
@ -878,7 +878,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
commitState(c.chan,ins); commitState(c.chan,ins);
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
} }
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11,chan[c.chan].ins);
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
break; break;
} }

View file

@ -89,7 +89,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].portaPause=false; opChan[ch].portaPause=false;
opChan[ch].note=c.value; opChan[ch].note=c.value;
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
@ -177,7 +177,7 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
commitStateExt(ch,ins); commitStateExt(ch,ins);
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
} }
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
break; break;
} }
@ -444,7 +444,7 @@ void DivPlatformYM2203Ext::tick(bool sysTick) {
if (opChan[i].std.arp.had) { if (opChan[i].std.arp.had) {
if (!opChan[i].inPorta) { if (!opChan[i].inPorta) {
opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11); opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11,opChan[i].ins);
} }
opChan[i].freqChanged=true; opChan[i].freqChanged=true;
} }
@ -543,7 +543,7 @@ void DivPlatformYM2203Ext::tick(bool sysTick) {
if (extMode) for (int i=0; i<4; i++) { if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) { if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==2) {
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); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(opChan[i].baseFreq&0xf800)>>11; int block=(opChan[i].baseFreq&0xf800)>>11;

View file

@ -284,7 +284,7 @@ double DivPlatformYM2608::NOTE_OPNB(int ch, int note) {
return NOTE_PERIODIC(note); return NOTE_PERIODIC(note);
} }
// FM // FM
return NOTE_FNUM_BLOCK(note,11); return NOTE_FNUM_BLOCK(note,11,chan[ch].ins);
} }
double DivPlatformYM2608::NOTE_ADPCMB(int note) { double DivPlatformYM2608::NOTE_ADPCMB(int note) {
@ -719,7 +719,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
chan[i].handleArp(); chan[i].handleArp();
} else if (chan[i].std.arp.had) { } else if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11,chan[i].ins);
} }
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -871,7 +871,7 @@ void DivPlatformYM2608::tick(bool sysTick) {
if (i==2 && extMode) continue; if (i==2 && extMode) continue;
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==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,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(chan[i].baseFreq&0xf800)>>11; int block=(chan[i].baseFreq&0xf800)>>11;
@ -1233,7 +1233,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11,chan[c.chan].ins);
chan[c.chan].portaPause=false; chan[c.chan].portaPause=false;
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;

View file

@ -93,7 +93,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].portaPause=false; opChan[ch].portaPause=false;
opChan[ch].note=c.value; opChan[ch].note=c.value;
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
@ -197,7 +197,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
commitStateExt(ch,ins); commitStateExt(ch,ins);
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
} }
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
break; break;
} }
@ -472,7 +472,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
if (opChan[i].std.arp.had) { if (opChan[i].std.arp.had) {
if (!opChan[i].inPorta) { if (!opChan[i].inPorta) {
opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11); opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11,opChan[i].ins);
} }
opChan[i].freqChanged=true; opChan[i].freqChanged=true;
} }
@ -594,7 +594,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
if (extMode) for (int i=0; i<4; i++) { if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) { if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==2) {
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); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(opChan[i].baseFreq&0xf800)>>11; int block=(opChan[i].baseFreq&0xf800)>>11;

View file

@ -647,7 +647,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
chan[i].handleArp(); chan[i].handleArp();
} else if (chan[i].std.arp.had) { } else if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11,chan[i].ins);
} }
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -799,7 +799,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
if (i==1 && extMode) continue; if (i==1 && extMode) continue;
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==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,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(chan[i].baseFreq&0xf800)>>11; int block=(chan[i].baseFreq&0xf800)>>11;
@ -1200,7 +1200,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11,chan[c.chan].ins);
chan[c.chan].portaPause=false; chan[c.chan].portaPause=false;
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;

View file

@ -715,7 +715,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
chan[i].handleArp(); chan[i].handleArp();
} else if (chan[i].std.arp.had) { } else if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11,chan[i].ins);
} }
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -867,7 +867,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
if (i==2 && extMode) continue; if (i==2 && extMode) continue;
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==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,4,chan[i].pitch2,chipClock,CHIP_FREQBASE,11); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(chan[i].baseFreq&0xf800)>>11; int block=(chan[i].baseFreq&0xf800)>>11;
@ -1268,7 +1268,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11,chan[c.chan].ins);
chan[c.chan].portaPause=false; chan[c.chan].portaPause=false;
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;

View file

@ -89,7 +89,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].portaPause=false; opChan[ch].portaPause=false;
opChan[ch].note=c.value; opChan[ch].note=c.value;
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
@ -193,7 +193,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
commitStateExt(ch,ins); commitStateExt(ch,ins);
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
} }
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
break; break;
} }
@ -465,7 +465,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
if (opChan[i].std.arp.had) { if (opChan[i].std.arp.had) {
if (!opChan[i].inPorta) { if (!opChan[i].inPorta) {
opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11); opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11,opChan[i].ins);
} }
opChan[i].freqChanged=true; opChan[i].freqChanged=true;
} }
@ -586,7 +586,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
if (extMode) for (int i=0; i<4; i++) { if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) { if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==2) {
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); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(opChan[i].baseFreq&0xf800)>>11; int block=(opChan[i].baseFreq&0xf800)>>11;

View file

@ -89,7 +89,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].portaPause=false; opChan[ch].portaPause=false;
opChan[ch].note=c.value; opChan[ch].note=c.value;
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
@ -193,7 +193,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
commitStateExt(ch,ins); commitStateExt(ch,ins);
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
} }
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11,opChan[ch].ins);
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
break; break;
} }
@ -465,7 +465,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
if (opChan[i].std.arp.had) { if (opChan[i].std.arp.had) {
if (!opChan[i].inPorta) { if (!opChan[i].inPorta) {
opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11); opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11,opChan[i].ins);
} }
opChan[i].freqChanged=true; opChan[i].freqChanged=true;
} }
@ -586,7 +586,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
if (extMode) for (int i=0; i<4; i++) { if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) { if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) { if (parent->song.linearPitch==2) {
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); 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,parent->getIns(chan[i].ins)->fm.block);
} else { } 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); 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);
int block=(opChan[i].baseFreq&0xf800)>>11; int block=(opChan[i].baseFreq&0xf800)>>11;

View file

@ -97,7 +97,7 @@ class DivPlatformYM2610Base: public DivPlatformOPN {
return NOTE_PERIODIC(note); return NOTE_PERIODIC(note);
} }
// FM // FM
return NOTE_FNUM_BLOCK(note,11); return NOTE_FNUM_BLOCK(note,11,chan[ch].ins);
} }
double NOTE_ADPCMB(int note) { double NOTE_ADPCMB(int note) {
if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].sample<parent->song.sampleLen) { if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].sample<parent->song.sampleLen) {

View file

@ -49,8 +49,8 @@ const char* ssgEnvTypes[8]={
_N("Up DOWN") _N("Up DOWN")
}; };
const char* fmParamNames[3][32]={ const char* fmParamNames[3][33]={
{_N("Algorithm"), _N("Feedback"), _N("LFO > Freq"), _N("LFO > Amp"), _N("Attack"), _N("Decay"), _N("Decay 2"), _N("Release"), _N("Sustain"), _N("Level"), _N("EnvScale"), _N("Multiplier"), _N("Detune"), _N("Detune 2"), _N("SSG-EG"), _N("AM"), _N("AM Depth"), _N("Vibrato Depth"), _N("Sustained"), _N("Sustained"), _N("Level Scaling"), _N("Sustain"), _N("Vibrato"), _N("Waveform"), _N("Scale Rate"), _N("OP2 Half Sine"), _N("OP1 Half Sine"), _N("EnvShift"), _N("Reverb"), _N("Fine"), _N("LFO2 > Freq"), _N("LFO2 > Amp")}, {_N("Algorithm"), _N("Feedback"), _N("LFO > Freq"), _N("LFO > Amp"), _N("Attack"), _N("Decay"), _N("Decay 2"), _N("Release"), _N("Sustain"), _N("Level"), _N("EnvScale"), _N("Multiplier"), _N("Detune"), _N("Detune 2"), _N("SSG-EG"), _N("AM"), _N("AM Depth"), _N("Vibrato Depth"), _N("Sustained"), _N("Sustained"), _N("Level Scaling"), _N("Sustain"), _N("Vibrato"), _N("Waveform"), _N("Scale Rate"), _N("OP2 Half Sine"), _N("OP1 Half Sine"), _N("EnvShift"), _N("Reverb"), _N("Fine"), _N("LFO2 > Freq"), _N("LFO2 > Amp"), _N("Block")},
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"}, {"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"},
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"} {"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"}
}; };
@ -388,7 +388,8 @@ enum FMParams {
FM_REV=28, FM_REV=28,
FM_FINE=29, FM_FINE=29,
FM_FMS2=30, FM_FMS2=30,
FM_AMS2=31 FM_AMS2=31,
FM_BLOCK=32
}; };
enum ESFMParams { enum ESFMParams {
@ -3909,8 +3910,13 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
} }
if (ImGui::BeginTable("fmDetails",3,(ins->type==DIV_INS_ESFM)?ImGuiTableFlags_SizingStretchProp:ImGuiTableFlags_SizingStretchSame)) { if (ImGui::BeginTable("fmDetails",3,(ins->type==DIV_INS_ESFM)?ImGuiTableFlags_SizingStretchProp:ImGuiTableFlags_SizingStretchSame)) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.50f:0.0f)); String blockTxt=_("Any");
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.15f:0.0f)); if (ins->fm.block>=1) {
blockTxt=fmt::sprintf("%d",ins->fm.block-1);
}
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.40f:0.0f));
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.25f:0.0f));
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.35f:0.0f)); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,((ins->type==DIV_INS_ESFM)?0.35f:0.0f));
ImGui::TableNextRow(); ImGui::TableNextRow();
@ -3920,6 +3926,9 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable
P(CWSliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN)); rightClickable
if (ins->type==DIV_INS_FM) {
P(CWSliderScalar(FM_NAME(FM_BLOCK),ImGuiDataType_U8,&ins->fm.block,&_ZERO,&_EIGHT,blockTxt.c_str())); rightClickable
}
ImGui::TableNextColumn(); ImGui::TableNextColumn();
P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN)); rightClickable
P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable
@ -3981,6 +3990,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
P(CWSliderScalar(FM_NAME(FM_BLOCK),ImGuiDataType_U8,&ins->fm.block,&_ZERO,&_EIGHT,blockTxt.c_str())); rightClickable
ImGui::TableNextColumn(); ImGui::TableNextColumn();
P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&algMax)); rightClickable P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&algMax)); rightClickable
if (ins->type==DIV_INS_OPL) { if (ins->type==DIV_INS_OPL) {
@ -4012,6 +4022,10 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
fmOrigin.fms=dc; fmOrigin.fms=dc;
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
if (ins->fm.opllPreset!=0) {
ins->fm.op[1].tl&=15;
P(CWSliderScalar(_("Volume##TL"),ImGuiDataType_U8,&ins->fm.op[1].tl,&_FIFTEEN,&_ZERO)); rightClickable
}
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (ImGui::Checkbox(FM_NAME(FM_SUS),&sus)) { PARAMETER if (ImGui::Checkbox(FM_NAME(FM_SUS),&sus)) { PARAMETER
ins->fm.alg=sus; ins->fm.alg=sus;
@ -4021,6 +4035,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
fmOrigin.ams=dm; fmOrigin.ams=dm;
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
P(CWSliderScalar(FM_NAME(FM_BLOCK),ImGuiDataType_U8,&ins->fm.block,&_ZERO,&_EIGHT,blockTxt.c_str())); rightClickable
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (fmPreviewOn) { if (fmPreviewOn) {
drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale));
@ -4074,6 +4089,7 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
P(CWSliderScalar(ESFM_LONG_NAME(ESFM_NOISE),ImGuiDataType_U8,&ins->esfm.noise,&_ZERO,&_THREE,_(esfmNoiseModeNames[ins->esfm.noise&3]))); rightClickable P(CWSliderScalar(ESFM_LONG_NAME(ESFM_NOISE),ImGuiDataType_U8,&ins->esfm.noise,&_ZERO,&_THREE,_(esfmNoiseModeNames[ins->esfm.noise&3]))); rightClickable
ImGui::TextUnformatted(_(esfmNoiseModeDescriptions[ins->esfm.noise&3])); ImGui::TextUnformatted(_(esfmNoiseModeDescriptions[ins->esfm.noise&3]));
ImGui::TableNextColumn(); ImGui::TableNextColumn();
P(CWSliderScalar(FM_NAME(FM_BLOCK),ImGuiDataType_U8,&ins->fm.block,&_ZERO,&_EIGHT,blockTxt.c_str())); rightClickable
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (fmPreviewOn) { if (fmPreviewOn) {
drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
@ -4091,6 +4107,9 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
} }
ImGui::EndTable(); ImGui::EndTable();
} }
if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset==16) {
ImGui::Text(_("this volume slider only works in compatibility (non-drums) system."));
}
if (((ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL) && ins->fm.opllPreset==16) || ins->type==DIV_INS_OPL_DRUMS) { if (((ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL) && ins->fm.opllPreset==16) || ins->type==DIV_INS_OPL_DRUMS) {
ins->fm.ops=2; ins->fm.ops=2;
@ -4121,12 +4140,6 @@ void FurnaceGUI::insTabFM(DivInstrument* ins) {
bool willDisplayOps=true; bool willDisplayOps=true;
if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset!=0) willDisplayOps=false; if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset!=0) willDisplayOps=false;
if (!willDisplayOps && ins->type==DIV_INS_OPLL) { if (!willDisplayOps && ins->type==DIV_INS_OPLL) {
ins->fm.op[1].tl&=15;
P(CWSliderScalar(_("Volume##TL"),ImGuiDataType_U8,&ins->fm.op[1].tl,&_FIFTEEN,&_ZERO)); rightClickable
if (ins->fm.opllPreset==16) {
ImGui::Text(_("this volume slider only works in compatibility (non-drums) system."));
}
// update OPLL preset preview // update OPLL preset preview
if (ins->fm.opllPreset>0 && ins->fm.opllPreset<16) { if (ins->fm.opllPreset>0 && ins->fm.opllPreset<16) {
const opll_patch_t* patchROM=NULL; const opll_patch_t* patchROM=NULL;