Lynx: Add a chip config for constant tone frequency
This commit is contained in:
parent
ec10046964
commit
463c9a89bb
|
@ -34,7 +34,6 @@
|
|||
#define WRITE_ATTEN(ch,v) rWrite((0x40+ch),(v))
|
||||
#define WRITE_STEREO(v) rWrite(0x50,(v))
|
||||
|
||||
#define CHIP_DIVIDER 64
|
||||
#define CHIP_FREQBASE 16000000
|
||||
|
||||
static int32_t clamp(int32_t v, int32_t lo, int32_t hi)
|
||||
|
@ -42,6 +41,41 @@ static int32_t clamp(int32_t v, int32_t lo, int32_t hi)
|
|||
return v<lo?lo:(v>hi?hi:v);
|
||||
}
|
||||
|
||||
const int DUTY_DIVIDERS[]={
|
||||
1, 2, 4, 3, 6, 7, 7, 4, 8, 15, 6, 14, 15, 12, 14, 5,
|
||||
10, 21, 31, 28, 31, 30, 12, 31, 21, 8, 30, 31, 28, 31, 31, 6,
|
||||
12, 63, 14, 62, 9, 28, 62, 15, 14, 42, 8, 21, 62, 63, 15, 60,
|
||||
63, 20, 42, 63, 28, 12, 63, 62, 62, 63, 21, 24, 15, 62, 60, 7,
|
||||
16, 63, 30, 254, 217, 84, 186, 217, 12, 254, 28, 15, 254, 51, 255, 84,
|
||||
217, 120, 210, 63, 60, 255, 255, 254, 254, 217, 63, 252, 17, 42, 124, 85,
|
||||
30, 254, 24, 217, 210, 21, 255, 252, 28, 217, 10, 186, 63, 124, 254, 255,
|
||||
186, 255, 255, 56, 255, 70, 36, 30, 255, 60, 254, 85, 124, 85, 21, 254,
|
||||
22,1533,2047, 868,1953,2046, 420, 651,1533,2044,2046,2047,1016,1785, 105, 126,
|
||||
595, 630, 204,1533,1302,2047,2047,2044,2044, 119, 372,1778,1953, 120, 682,1905,
|
||||
595, 868, 510,2047,2044, 762, 279, 682, 210,1953, 595,1524,1533, 210, 248, 635,
|
||||
60,2047,2047, 62,1905,2044,2046, 42,2047, 510, 252,1905,1778,2047,1533,1016,
|
||||
1953,1860,1778, 219, 48,1905,2047,1778, 682,2047, 465,1020,1785, 126,2044, 434,
|
||||
2044, 63,2047,2046,2047, 280, 30,1953, 210, 682, 868, 89,2046,2047,2047,1524,
|
||||
1302,1785,2047,1860,2047,2046,1016, 372,2047, 84, 630, 70, 252,2047,1533, 682,
|
||||
1905,2046, 372,1905, 90,1533, 217, 168, 340,2047,2047,1302,1533, 28, 186,2047,
|
||||
24,3255, 126,1190, 45,4092, 178, 315, 28, 438, 124, 315,3570, 255,1023,2044,
|
||||
819,1016, 930,3937,1260,1302, 511,4094,3810, 819, 195,2604,1023,4094, 84,1365,
|
||||
18,3810, 56,1023, 42,3937, 819,4092, 124,4095, 30,4094, 85,1524,3906, 63,
|
||||
3906,1023,3255, 120,4095,3570,1020,3937,2667,3556,4094, 195,2044,4095,4095, 762,
|
||||
28,1302, 84,4095,3906,1023, 255, 292, 16,1085, 42,3066, 315,3556,4094,4095,
|
||||
3066,4095,3937, 372, 511,4094, 620,1302, 273, 504,1190, 819,4092,4095,1023, 210,
|
||||
124,1023, 126,3570,3937, 252, 438,4095, 30,4094, 120,4095,4094, 255, 63,1020,
|
||||
4095,1364, 558,2667, 420,4095, 105,1270,1190,3255, 93,1016, 91, 372,4092,3937,
|
||||
3255, 44,3066,1365,1736, 510, 91,4094,1302, 511,3937, 420, 105,3906,4092, 819,
|
||||
252, 585, 255, 210,3937,1016,3570,1023, 455,3066,2044,1365,4094, 126,2667,4092,
|
||||
3810, 93, 63,1364,1365,3906, 120, 28,1023,2044, 238,4095,3556, 255,4095, 372,
|
||||
511,1190,1260,1023,3066, 255, 819, 408,2044, 255,1302,4094, 455,2604,4094, 585,
|
||||
438, 511, 455, 292, 455, 434,1364, 102,1085, 204,3570, 255, 240,4095, 93,4094,
|
||||
3937,4094, 84, 63,4094, 315, 819, 140,1260,3937,4095,3066,2667, 680,4094, 511,
|
||||
4095,2044, 178,1023,1020, 819, 21,3810,4094, 20,1023,3556,3937, 210,2040, 273,
|
||||
252,2667,4095,3906, 63, 124, 930, 455, 510,4094,4092, 511,3570,4095, 30, 744
|
||||
};
|
||||
|
||||
const char* regCheatSheetLynx[]={
|
||||
"AUDIO0_VOLCNTRL", "20",
|
||||
"AUDIO0_FEEDBACK", "21",
|
||||
|
@ -134,6 +168,7 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
chan[i].handleArp();
|
||||
} else if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
double CHIP_DIVIDER=tuned?DUTY_DIVIDERS[chan[i].duty.val&0x1ff]*8:64;
|
||||
chan[i].actualNote=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].actualNote);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].actualNote);
|
||||
|
@ -194,28 +229,35 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
WRITE_OTHER(i, ((chan[i].lfsr&0xf00)>>4));
|
||||
chan[i].lfsr=-1;
|
||||
}
|
||||
chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
if (!chan[i].pcm) {
|
||||
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
||||
}
|
||||
}
|
||||
double divider=tuned?DUTY_DIVIDERS[chan[i].duty.val&0x1ff]*8:64;
|
||||
chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,divider);
|
||||
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
||||
WRITE_BACKUP( i, chan[i].fd.backup );
|
||||
}
|
||||
chan[i].freqChanged=false;
|
||||
} else if (chan[i].std.duty.had) {
|
||||
chan[i].duty = chan[i].std.duty.val;
|
||||
chan[i].duty=chan[i].std.duty.val;
|
||||
if (!chan[i].pcm) {
|
||||
if (tuned) {
|
||||
double divider=DUTY_DIVIDERS[chan[i].duty.val&0x1ff]*8;
|
||||
chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,divider);
|
||||
}
|
||||
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
||||
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
||||
if (tuned) WRITE_BACKUP( i, chan[i].fd.backup );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformLynx::dispatch(DivCommand c) {
|
||||
double CHIP_DIVIDER=tuned?DUTY_DIVIDERS[chan[c.chan].duty.val&0x1ff]*8:64;
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
bool prevPCM=chan[c.chan].pcm;
|
||||
|
@ -455,6 +497,16 @@ bool DivPlatformLynx::getLegacyAlwaysSetVolume() {
|
|||
// return 12;
|
||||
//}
|
||||
|
||||
void DivPlatformLynx::setFlags(const DivConfig& flags) {
|
||||
tuned=flags.getBool("tuned",false);
|
||||
chipClock=16000000;
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/128;
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformLynx::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
|
@ -478,14 +530,7 @@ int DivPlatformLynx::init(DivEngine* p, int channels, int sugRate, const DivConf
|
|||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
|
||||
chipClock = 16000000;
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate = chipClock/128;
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
setFlags(flags);
|
||||
|
||||
reset();
|
||||
return 4;
|
||||
|
@ -533,6 +578,7 @@ DivPlatformLynx::MikeyDuty::MikeyDuty(int duty) {
|
|||
//1: f1
|
||||
//0: f0
|
||||
|
||||
val=duty;
|
||||
//f7 moved to bit 7 and int moved to bit 5
|
||||
int_feedback7=((duty&0x40)<<1)|((duty&0x200)>>4);
|
||||
//f11 and f10 moved to bits 7 & 6
|
||||
|
|
|
@ -35,6 +35,7 @@ class DivPlatformLynx: public DivDispatch {
|
|||
struct MikeyDuty {
|
||||
unsigned char int_feedback7;
|
||||
unsigned char feedback;
|
||||
int val;
|
||||
|
||||
MikeyDuty(int duty);
|
||||
};
|
||||
|
@ -64,6 +65,7 @@ class DivPlatformLynx: public DivDispatch {
|
|||
Channel chan[4];
|
||||
DivDispatchOscBuffer* oscBuf[4];
|
||||
bool isMuted[4];
|
||||
bool tuned;
|
||||
std::unique_ptr<Lynx::Mikey> mikey;
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
@ -86,6 +88,7 @@ class DivPlatformLynx: public DivDispatch {
|
|||
bool keyOffAffectsPorta(int ch);
|
||||
bool getLegacyAlwaysSetVolume();
|
||||
//int getPortaFloor(int ch);
|
||||
void setFlags(const DivConfig& flags);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
|
|
|
@ -1596,6 +1596,19 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_LYNX: {
|
||||
bool tuned=flags.getBool("tuned",false);
|
||||
if (ImGui::Checkbox("Consistent frequency across all duties",&tuned)) {
|
||||
altered=true;
|
||||
e->lockSave([&]() {
|
||||
flags.set("tuned",tuned);
|
||||
});
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("note: only works for an initial LFSR value of 0!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_OPL:
|
||||
case DIV_SYSTEM_OPL_DRUMS:
|
||||
case DIV_SYSTEM_OPL2:
|
||||
|
|
Loading…
Reference in a new issue