Merge branch 'master' of https://github.com/tildearrow/furnace into nmk112
This commit is contained in:
commit
3922770e8f
166 changed files with 4829 additions and 2054 deletions
|
|
@ -370,20 +370,10 @@ void DivPlatformAmiga::tick(bool sysTick) {
|
|||
chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol.val))>>6;
|
||||
chan[i].writeVol=true;
|
||||
}
|
||||
double off=1.0;
|
||||
if (!chan[i].useWave && chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
if (s->centerRate<1) {
|
||||
off=1.0;
|
||||
} else {
|
||||
off=8363.0/(double)s->centerRate;
|
||||
}
|
||||
}
|
||||
if (NEW_ARP_STRAT) {
|
||||
chan[i].handleArp();
|
||||
} else if (chan[i].std.arp.had) {
|
||||
// TODO: why the off mult? this may be a bug!
|
||||
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(parent->calcArp(chan[i].note,chan[i].std.arp.val)));
|
||||
chan[i].baseFreq=round(NOTE_PERIODIC_NOROUND(parent->calcArp(chan[i].note,chan[i].std.arp.val)));
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].useWave && chan[i].std.wave.had) {
|
||||
|
|
@ -577,10 +567,14 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
|
|||
chan[c.chan].updateWave=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
} else {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
chan[c.chan].useWave=false;
|
||||
}
|
||||
|
|
@ -657,9 +651,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
|
|||
chan[c.chan].updateWave=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value2);
|
||||
int destFreq=round(NOTE_PERIODIC_NOROUND(c.value2));
|
||||
int destFreq=round(NOTE_PERIODIC_NOROUND(c.value2+chan[c.chan].sampleNoteDelta));
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -682,7 +674,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=round(NOTE_PERIODIC_NOROUND(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))));
|
||||
chan[c.chan].baseFreq=round(NOTE_PERIODIC_NOROUND(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -405,7 +405,12 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dac.sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dac.sample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dac.sample=-1;
|
||||
|
|
@ -457,6 +462,8 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
|
|
@ -526,7 +533,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -549,7 +556,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -406,7 +406,12 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dac.sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dac.sample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dac.sample=-1;
|
||||
|
|
@ -458,6 +463,8 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
|
|
@ -520,7 +527,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -543,7 +550,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,7 +320,9 @@ int DivPlatformC140::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroPanMul=ins->type==DIV_INS_AMIGA?127:255;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
|
|
@ -393,7 +395,7 @@ int DivPlatformC140::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -416,7 +418,7 @@ int DivPlatformC140::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -719,27 +719,51 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
// man this code
|
||||
// part of the reason why it's so messy is because the chip is
|
||||
// overly complex and because when this pull request was made,
|
||||
// Furnace still was in an early state with no support for sample
|
||||
// maps or whatever...
|
||||
// one day I'll come back and clean this up
|
||||
int DivPlatformES5506::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_ES5506);
|
||||
bool sampleValid=false;
|
||||
if (((ins->amiga.useNoteMap) && (c.value>=0 && c.value<120)) ||
|
||||
((!ins->amiga.useNoteMap) && (ins->amiga.initSample>=0 && ins->amiga.initSample<parent->song.sampleLen))) {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
int sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
if (sample>=0 && sample<parent->song.sampleLen) {
|
||||
sampleValid=true;
|
||||
chan[c.chan].volMacroMax=ins->type==DIV_INS_AMIGA?64:0xfff;
|
||||
chan[c.chan].panMacroMax=ins->type==DIV_INS_AMIGA?127:0xfff;
|
||||
chan[c.chan].pcm.next=ins->amiga.useNoteMap?c.value:sample;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
chan[c.chan].pcm.note=c.value;
|
||||
chan[c.chan].filter=ins->es5506.filter;
|
||||
chan[c.chan].envelope=ins->es5506.envelope;
|
||||
} else {
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
} else {
|
||||
int sample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
if (sample>=0 && sample<parent->song.sampleLen) {
|
||||
sampleValid=true;
|
||||
chan[c.chan].volMacroMax=ins->type==DIV_INS_AMIGA?64:0xfff;
|
||||
chan[c.chan].panMacroMax=ins->type==DIV_INS_AMIGA?127:0xfff;
|
||||
chan[c.chan].pcm.next=ins->amiga.useNoteMap?chan[c.chan].sampleNote:sample;
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
chan[c.chan].pcm.note=c.value;
|
||||
chan[c.chan].filter=ins->es5506.filter;
|
||||
chan[c.chan].envelope=ins->es5506.envelope;
|
||||
} else {
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
}
|
||||
if (!sampleValid) {
|
||||
chan[c.chan].pcm.index=chan[c.chan].pcm.next=-1;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
chan[c.chan].filter=DivInstrumentES5506::Filter();
|
||||
chan[c.chan].envelope=DivInstrumentES5506::Envelope();
|
||||
}
|
||||
|
|
@ -962,7 +986,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int nextFreq=chan[c.chan].baseFreq;
|
||||
const int destFreq=NOTE_ES5506(c.chan,c.value2);
|
||||
const int destFreq=NOTE_ES5506(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>nextFreq) {
|
||||
nextFreq+=c.value;
|
||||
|
|
@ -987,7 +1011,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].nextNote=chan[c.chan].note+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0));
|
||||
chan[c.chan].nextNote=chan[c.chan].note+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0));
|
||||
chan[c.chan].noteChanged.note=1;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,7 +207,9 @@ int DivPlatformGA20::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
|
|
@ -263,7 +265,7 @@ int DivPlatformGA20::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
const int destFreq=NOTE_PERIODIC(c.value2);
|
||||
const int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -286,7 +288,7 @@ int DivPlatformGA20::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -704,8 +704,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
} else if (chan[c.chan].furnaceDac) {
|
||||
chan[c.chan].dacMode=0;
|
||||
rWrite(0x2b,0<<7);
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
} else if (!chan[c.chan].dacMode) {
|
||||
rWrite(0x2b,0<<7);
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
}
|
||||
if (c.chan>=5 && chan[c.chan].dacMode) {
|
||||
|
|
@ -713,7 +717,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
if (ins->type==DIV_INS_AMIGA) { // Furnace mode
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
|
|
@ -752,6 +761,8 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
chan[c.chan].dacSample=12*chan[c.chan].sampleBank+chan[c.chan].note%12;
|
||||
if (chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
|
|
@ -863,7 +874,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
if (parent->song.linearPitch==2) {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -909,7 +920,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||
int destFreq=parent->calcBaseFreq(1,1,c.value2,false);
|
||||
int destFreq=parent->calcBaseFreq(1,1,c.value2+chan[c.chan].sampleNoteDelta,false);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value*16;
|
||||
|
|
@ -963,7 +974,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
if (c.chan==csmChan) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
} else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+chan[c.chan].sampleNoteDelta,false);
|
||||
} else {
|
||||
if (chan[c.chan].insChanged) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
|
|
|
|||
|
|
@ -281,7 +281,9 @@ int DivPlatformK007232::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:15;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
|
|
@ -347,7 +349,7 @@ int DivPlatformK007232::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
const int destFreq=NOTE_PERIODIC(c.value2);
|
||||
const int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -370,7 +372,7 @@ int DivPlatformK007232::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -230,7 +230,9 @@ int DivPlatformK053260::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:127;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
|
|
@ -291,7 +293,7 @@ int DivPlatformK053260::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -314,7 +316,7 @@ int DivPlatformK053260::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -228,19 +228,28 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
WRITE_CONTROL(c.chan,0x18);
|
||||
WRITE_BACKUP(c.chan,0);
|
||||
} else {
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
WRITE_FEEDBACK(c.chan,chan[c.chan].duty.feedback);
|
||||
WRITE_CONTROL(c.chan,(chan[c.chan].fd.clockDivider|0x18|chan[c.chan].duty.int_feedback7));
|
||||
WRITE_BACKUP(c.chan,chan[c.chan].fd.backup);
|
||||
}
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
if (chan[c.chan].pcm) {
|
||||
if (chan[c.chan].pcm) {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
chan[c.chan].sampleBaseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].sampleAccum=0;
|
||||
chan[c.chan].samplePos=0;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
chan[c.chan].sampleAccum=0;
|
||||
chan[c.chan].samplePos=0;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
|
|
@ -301,7 +310,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -327,7 +336,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
int whatAMess=c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0));
|
||||
int whatAMess=c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0));
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(whatAMess);
|
||||
if (chan[c.chan].pcm) {
|
||||
chan[c.chan].sampleBaseFreq=NOTE_FREQUENCY(whatAMess);
|
||||
|
|
|
|||
|
|
@ -178,7 +178,12 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
|
|||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
dacSample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
dacSample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
dacSample=-1;
|
||||
|
|
@ -189,8 +194,8 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
|
|||
}
|
||||
dacPos=0;
|
||||
dacPeriod=0;
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
|
|
@ -270,7 +275,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=(c.chan==2)?(parent->calcBaseFreq(1,1,c.value2,false)):(NOTE_PERIODIC(c.value2));
|
||||
int destFreq=(c.chan==2)?(parent->calcBaseFreq(1,1,c.value2+chan[c.chan].sampleNoteDelta,false)):(NOTE_PERIODIC(c.value2));
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -304,7 +309,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_LEGATO:
|
||||
if (c.chan==2) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)),false);
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)),false);
|
||||
} else {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -407,7 +407,14 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
if (c.value!=DIV_NOTE_NULL) {
|
||||
dacSample=ins->amiga.getSample(c.value);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
dacSample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
}
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
|
|
@ -535,7 +542,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=(c.chan==4)?(parent->calcBaseFreq(1,1,c.value2,false)):(NOTE_PERIODIC(c.value2));
|
||||
int destFreq=(c.chan==4)?(parent->calcBaseFreq(1,1,c.value2+chan[c.chan].sampleNoteDelta,false)):(NOTE_PERIODIC(c.value2));
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -636,7 +643,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
case DIV_CMD_LEGATO:
|
||||
if (c.chan==3) break;
|
||||
if (c.chan==4) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)),false);
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)),false);
|
||||
} else {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -515,6 +515,18 @@ static const int cycleMapDrums[18]={
|
|||
0, 1, 2, 3, 4, 5, 3, 4, 5,
|
||||
};
|
||||
|
||||
static const int cycleMap3[36]={
|
||||
14, 12, 13, 14, 0, 2, 4, 0, 2,
|
||||
4, 1, 3, 5, 1, 3, 5, 15, 16,
|
||||
17, 15, 16, 17, 6, 8, 10, 6, 8, 10, 7, 9, 11, 7, 9, 11, 12, 13
|
||||
};
|
||||
|
||||
static const int cycleMap3Drums[36]={
|
||||
14, 12, 13, 14, 0, 2, 4, 0, 2,
|
||||
4, 1, 3, 5, 1, 3, 5, 15, 19,
|
||||
17, 15, 16, 18, 6, 8, 10, 6, 8, 10, 7, 9, 11, 7, 9, 11, 12, 13
|
||||
};
|
||||
|
||||
void DivPlatformOPL::acquire_nukedLLE2(short** buf, size_t len) {
|
||||
int chOut[11];
|
||||
thread_local ymfm::ymfm_output<2> aOut;
|
||||
|
|
@ -662,10 +674,11 @@ void DivPlatformOPL::acquire_nukedLLE2(short** buf, size_t len) {
|
|||
|
||||
void DivPlatformOPL::acquire_nukedLLE3(short** buf, size_t len) {
|
||||
int chOut[20];
|
||||
int ch=0;
|
||||
|
||||
for (size_t h=0; h<len; h++) {
|
||||
//int curCycle=0;
|
||||
//unsigned char subCycle=0;
|
||||
int curCycle=0;
|
||||
unsigned char subCycle=0;
|
||||
|
||||
for (int i=0; i<20; i++) {
|
||||
chOut[i]=0;
|
||||
|
|
@ -721,10 +734,24 @@ void DivPlatformOPL::acquire_nukedLLE3(short** buf, size_t len) {
|
|||
if (--delay<0) waitingBusy=false;
|
||||
}
|
||||
|
||||
/*if (!(++subCycle&3)) {
|
||||
// TODO: chan osc
|
||||
if (!(++subCycle&1)) {
|
||||
if (properDrums) {
|
||||
ch=cycleMap3Drums[curCycle];
|
||||
} else {
|
||||
ch=cycleMap3[curCycle];
|
||||
}
|
||||
|
||||
if (ch<12 && !(ch&1) && chan[ch&(~1)].state.alg>0) ch|=1;
|
||||
|
||||
if (ch>=12 || (ch&1) || !chan[ch&(~1)].fourOp) {
|
||||
if (fm_lle3.op_value_debug&0x1000) {
|
||||
chOut[ch]+=(fm_lle3.op_value_debug|0xfffff000)<<1;
|
||||
} else {
|
||||
chOut[ch]+=(fm_lle3.op_value_debug)<<1;
|
||||
}
|
||||
}
|
||||
curCycle++;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (fm_lle3.o_sy && !lastSY) {
|
||||
dacVal>>=1;
|
||||
|
|
@ -746,11 +773,11 @@ void DivPlatformOPL::acquire_nukedLLE3(short** buf, size_t len) {
|
|||
}
|
||||
|
||||
for (int i=0; i<20; i++) {
|
||||
if (i>=15 && properDrums) {
|
||||
/*if (i>=15 && properDrums) {
|
||||
chOut[i]<<=1;
|
||||
} else {
|
||||
chOut[i]<<=2;
|
||||
}
|
||||
}*/
|
||||
if (chOut[i]<-32768) chOut[i]=-32768;
|
||||
if (chOut[i]>32767) chOut[i]=32767;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=chOut[i];
|
||||
|
|
|
|||
|
|
@ -278,6 +278,8 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
chan[c.chan].pcm=true;
|
||||
} else if (chan[c.chan].furnaceDac) {
|
||||
chan[c.chan].pcm=false;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
if (chan[c.chan].pcm) {
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
|
|
@ -285,7 +287,12 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
if (skipRegisterWrites) break;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
|
|
@ -312,6 +319,8 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
//chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
chan[c.chan].furnaceDac=false;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
if (skipRegisterWrites) break;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
|
|
@ -334,6 +343,8 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
|
@ -413,7 +424,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
updateLFO=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -454,7 +465,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -314,6 +314,8 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[0].ins,DIV_INS_AMIGA);
|
||||
if (ins->amiga.useWave) {
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
chan[0].useWave=true;
|
||||
chan[0].audLen=ins->amiga.waveLen+1;
|
||||
if (chan[0].insChanged) {
|
||||
|
|
@ -326,7 +328,12 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
|||
} else {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[0].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
chan[0].useWave=false;
|
||||
}
|
||||
|
|
@ -335,6 +342,8 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
|||
}
|
||||
if (chan[0].useWave || chan[0].sample<0 || chan[0].sample>=parent->song.sampleLen) {
|
||||
chan[0].sample=-1;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
if (chan[0].setPos) {
|
||||
chan[0].setPos=false;
|
||||
|
|
@ -402,9 +411,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
|||
chan[0].ws.changeWave1(chan[0].wave);
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
DivInstrument* ins=parent->getIns(chan[0].ins,DIV_INS_AMIGA);
|
||||
chan[0].sample=ins->amiga.getSample(c.value2);
|
||||
int destFreq=round(NOTE_FREQUENCY(c.value2));
|
||||
int destFreq=round(NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta));
|
||||
bool return2=false;
|
||||
if (destFreq>chan[0].baseFreq) {
|
||||
chan[0].baseFreq+=c.value;
|
||||
|
|
@ -427,7 +434,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[0].baseFreq=round(NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[0].std.arp.val):(0))));
|
||||
chan[0].baseFreq=round(NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[0].std.arp.val):(0))));
|
||||
chan[0].freqChanged=true;
|
||||
chan[0].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
541
src/engine/platform/powernoise.cpp
Normal file
541
src/engine/platform/powernoise.cpp
Normal file
|
|
@ -0,0 +1,541 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2024 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "powernoise.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include "furIcons.h"
|
||||
#include <math.h>
|
||||
#include "../bsr.h"
|
||||
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {regPool[a]=(v); pwrnoise_write(&pn,(unsigned char)(a),(unsigned char)(v)); if (dumpWrites) {addWrite(a,v);}}
|
||||
#define chWrite(c,a,v) rWrite((c<<3)|((a)+1),(v))
|
||||
#define noiseCtl(enable,am,tapB) (((enable)?0x80:0x00)|((am)?0x02:0x00)|((tapB)?0x01:0x00))
|
||||
#define slopeCtl(enable,rst,a,b) (((enable)?0x80:0x00)| \
|
||||
(rst?0x40:0x00)| \
|
||||
(a.clip?0x20:0x00)| \
|
||||
(b.clip?0x10:0x00)| \
|
||||
(a.reset?0x08:0x00)| \
|
||||
(b.reset?0x04:0x00)| \
|
||||
(a.dir?0x02:0x00)| \
|
||||
(b.dir?0x01:0x00))
|
||||
#define volPan(v,p) (((v*(p>>4)/15)<<4)|((v*(p&0xf)/15)&0xf))
|
||||
// TODO: optimize!
|
||||
#define mapAmp(a) ((((a)*65535/63-32768)*(pn.flags&0x7)/7)>>1)
|
||||
|
||||
const char* regCheatSheetPowerNoise[]={
|
||||
"ACTL", "00",
|
||||
"N1CTL", "01",
|
||||
"N1FL", "02",
|
||||
"N1FH", "03",
|
||||
"N1SRL", "04",
|
||||
"N1SRH", "05",
|
||||
"N1TAP", "06",
|
||||
"N1V", "07",
|
||||
"IOA", "08",
|
||||
"N2CTL", "09",
|
||||
"N2FL", "0A",
|
||||
"N2FH", "0B",
|
||||
"N2SRL", "0C",
|
||||
"N2SRH", "0D",
|
||||
"N2TAP", "0E",
|
||||
"N2V", "0F",
|
||||
"IOB", "10",
|
||||
"N3CTL", "11",
|
||||
"N3FL", "12",
|
||||
"N3FH", "13",
|
||||
"N3SRL", "14",
|
||||
"N3SRH", "15",
|
||||
"N3TAP", "16",
|
||||
"N3V", "17",
|
||||
"SLACC", "18",
|
||||
"SLCTL", "19",
|
||||
"SLFL", "1A",
|
||||
"SLFH", "1B",
|
||||
"SLPA", "1C",
|
||||
"SLPB", "1D",
|
||||
"SLPO", "1E",
|
||||
"SLV", "1F",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformPowerNoise::getRegisterSheet() {
|
||||
return regCheatSheetPowerNoise;
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::acquire(short** buf, size_t len) {
|
||||
short left, right;
|
||||
|
||||
for (size_t h=0; h<len; h++) {
|
||||
pwrnoise_step(&pn,32,&left,&right);
|
||||
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=mapAmp((pn.n1.out_latch&0xf)+(pn.n1.out_latch>>4));
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=mapAmp((pn.n2.out_latch&0xf)+(pn.n2.out_latch>>4));
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=mapAmp((pn.n3.out_latch&0xf)+(pn.n3.out_latch>>4));
|
||||
oscBuf[3]->data[oscBuf[3]->needle++]=mapAmp((pn.s.out_latch&0xf)+(pn.s.out_latch>>4));
|
||||
|
||||
buf[0][h]=left;
|
||||
buf[1][h]=right;
|
||||
}
|
||||
}
|
||||
|
||||
/* macros:
|
||||
* EX1 - control (0-63)
|
||||
* EX2 - portion A length (0-255) - slope only
|
||||
* EX3 - portion B length (0-255) - slope only
|
||||
* EX4 - tap A location (0-15) - noise only
|
||||
* EX5 - tap B location (0-15) - noise only
|
||||
* EX6 - portion A offset (0-15) - slope only
|
||||
* EX7 - portion B offset (0-15) - slope only
|
||||
* EX8 - load LFSR (0-65535) - noise only
|
||||
*/
|
||||
|
||||
void DivPlatformPowerNoise::tick(bool sysTick) {
|
||||
for (int i=0; i<4; i++) {
|
||||
int CHIP_DIVIDER=2;
|
||||
if (i==3) CHIP_DIVIDER=128;
|
||||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.ex1.had) {
|
||||
int val=chan[i].std.ex1.val;
|
||||
|
||||
if (chan[i].slope) {
|
||||
chan[i].slopeA.clip=(val&0x20);
|
||||
chan[i].slopeB.clip=(val&0x10);
|
||||
chan[i].slopeA.reset=(val&0x08);
|
||||
chan[i].slopeB.reset=(val&0x04);
|
||||
chan[i].slopeA.dir=(val&0x02);
|
||||
chan[i].slopeB.dir=(val&0x01);
|
||||
chWrite(i,0x00,slopeCtl(chan[i].active,false,chan[i].slopeA,chan[i].slopeB));
|
||||
} else {
|
||||
chan[i].am=(val&0x02);
|
||||
chan[i].tapBEnable=(val&0x01);
|
||||
chWrite(i,0x00,noiseCtl(chan[i].active, chan[i].am, chan[i].tapBEnable));
|
||||
}
|
||||
}
|
||||
if (chan[i].slope) {
|
||||
if (chan[i].std.ex2.had) {
|
||||
chan[i].slopeA.len=chan[i].std.ex2.val;
|
||||
chWrite(i,0x03,chan[i].std.ex2.val);
|
||||
}
|
||||
if (chan[i].std.ex3.had) {
|
||||
chan[i].slopeB.len=chan[i].std.ex3.val;
|
||||
chWrite(i,0x04,chan[i].std.ex3.val);
|
||||
}
|
||||
if (chan[i].std.ex6.had) {
|
||||
chan[i].slopeA.offset=chan[i].std.ex6.val;
|
||||
}
|
||||
if (chan[i].std.ex7.had) {
|
||||
chan[i].slopeB.offset=chan[i].std.ex7.val;
|
||||
}
|
||||
if (chan[i].std.ex6.had || chan[i].std.ex7.had) {
|
||||
chWrite(i,0x05,(chan[i].slopeA.offset<<4)|chan[i].slopeB.offset);
|
||||
}
|
||||
} else {
|
||||
if (chan[i].std.ex4.had) {
|
||||
chan[i].tapA=chan[i].std.ex4.val;
|
||||
}
|
||||
if (chan[i].std.ex5.had) {
|
||||
chan[i].tapB=chan[i].std.ex5.val;
|
||||
}
|
||||
if (chan[i].std.ex4.had || chan[i].std.ex5.had) {
|
||||
chWrite(i,0x05,(chan[i].tapA<<4)|chan[i].tapB);
|
||||
}
|
||||
if (chan[i].std.ex8.had) {
|
||||
if (chan[i].initLFSR!=(chan[i].std.ex8.val&0xffff)) {
|
||||
chan[i].initLFSR=chan[i].std.ex8.val&0xffff;
|
||||
chWrite(i,0x03,chan[i].std.ex8.val&0xff);
|
||||
chWrite(i,0x04,chan[i].std.ex8.val>>8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=VOL_SCALE_LINEAR(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
}
|
||||
if (NEW_ARP_STRAT) {
|
||||
chan[i].handleArp();
|
||||
} else if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan&=0x0f;
|
||||
chan[i].pan|=(chan[i].std.panL.val&15)<<4;
|
||||
}
|
||||
if (chan[i].std.panR.had) {
|
||||
chan[i].pan&=0xf0;
|
||||
chan[i].pan|=chan[i].std.panR.val&15;
|
||||
}
|
||||
|
||||
if (chan[i].std.vol.had || chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||
chWrite(i,0x06,isMuted[i]?0:volPan(chan[i].outVol,chan[i].pan));
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
chan[i].pitch2+=chan[i].std.pitch.val;
|
||||
CLAMP_VAR(chan[i].pitch2,-32768,32767);
|
||||
} else {
|
||||
chan[i].pitch2=chan[i].std.pitch.val;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) {
|
||||
if (chan[i].slope) {
|
||||
chWrite(i,0x00,slopeCtl(chan[i].active,true,chan[i].slopeA,chan[i].slopeB));
|
||||
chan[i].keyOn=true;
|
||||
} else {
|
||||
chWrite(i,0x03,chan[i].initLFSR&0xff);
|
||||
chWrite(i,0x04,chan[i].initLFSR>>8);
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=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);
|
||||
chan[i].freq>>=chan[i].octaveOff;
|
||||
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].freq>0x7ffffff) chan[i].freq=0x7ffffff;
|
||||
int bsr32Val=bsr32(chan[i].freq);
|
||||
chan[i].octave=MAX(bsr32Val-12,0);
|
||||
if (chan[i].octave>15) chan[i].octave=15;
|
||||
chan[i].fNum=0x1000-(chan[i].freq>>chan[i].octave);
|
||||
if (chan[i].fNum<0) chan[i].fNum=0;
|
||||
if (chan[i].fNum>4095) chan[i].fNum=4095;
|
||||
|
||||
chWrite(i,0x01,chan[i].fNum&0xff);
|
||||
chWrite(i,0x02,(chan[i].fNum>>8)|(chan[i].octave<<4));
|
||||
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].slope) {
|
||||
chWrite(i,0x00,slopeCtl(true,false,chan[i].slopeA,chan[i].slopeB));
|
||||
} else {
|
||||
chWrite(i,0x00,noiseCtl(true,chan[i].am,chan[i].tapBEnable));
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
if (chan[i].slope) {
|
||||
chWrite(i,0x00,slopeCtl(false,false,chan[i].slopeA,chan[i].slopeB));
|
||||
} else {
|
||||
chWrite(i,0x00,noiseCtl(false,chan[i].am,chan[i].tapBEnable));
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
|
||||
if (chan[i].slope) {
|
||||
unsigned char counter=pn.s.accum;
|
||||
regPool[0x18]=counter;
|
||||
} else {
|
||||
unsigned short lfsr;
|
||||
if (i==0) {
|
||||
lfsr=pn.n1.lfsr;
|
||||
} else if (i==1) {
|
||||
lfsr=pn.n2.lfsr;
|
||||
} else {
|
||||
lfsr=pn.n3.lfsr;
|
||||
}
|
||||
regPool[(i<<3)+0x4]=lfsr&0xff;
|
||||
regPool[(i<<3)+0x5]=lfsr>>8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformPowerNoise::dispatch(DivCommand c) {
|
||||
int CHIP_DIVIDER=2;
|
||||
if (c.chan==3) CHIP_DIVIDER=128;
|
||||
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_POWERNOISE);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].octaveOff=ins->powernoise.octave;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].insChanged=false;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (chan[c.chan].ins!=c.value || c.value2==1) {
|
||||
chan[c.chan].ins=c.value;
|
||||
chan[c.chan].insChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_VOLUME:
|
||||
if (chan[c.chan].vol!=c.value) {
|
||||
chan[c.chan].vol=c.value;
|
||||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_GET_VOLUME:
|
||||
if (chan[c.chan].std.vol.has) {
|
||||
return chan[c.chan].vol;
|
||||
}
|
||||
return chan[c.chan].outVol;
|
||||
break;
|
||||
case DIV_CMD_PITCH:
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
if (chan[c.chan].baseFreq>0x7ffffff) {
|
||||
chan[c.chan].baseFreq=0x7ffffff;
|
||||
}
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq-=c.value;
|
||||
if (chan[c.chan].baseFreq<0) {
|
||||
chan[c.chan].baseFreq=0;
|
||||
}
|
||||
if (chan[c.chan].baseFreq<=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PANNING:
|
||||
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
int whatAMess=c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0));
|
||||
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(whatAMess);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PRE_PORTA: {
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_POWERNOISE));
|
||||
}
|
||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
}
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 15;
|
||||
break;
|
||||
case DIV_CMD_POWERNOISE_COUNTER_LOAD: {
|
||||
if (chan[c.chan].slope && c.value==0) {
|
||||
rWrite(0x18,c.value2&0x7f);
|
||||
} else if (!chan[c.chan].slope) {
|
||||
chWrite(c.chan,0x03+c.value,c.value2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_POWERNOISE_IO_WRITE:
|
||||
rWrite(0x08+(c.value<<3),c.value2);
|
||||
break;
|
||||
case DIV_CMD_MACRO_OFF:
|
||||
chan[c.chan].std.mask(c.value,true);
|
||||
break;
|
||||
case DIV_CMD_MACRO_ON:
|
||||
chan[c.chan].std.mask(c.value,false);
|
||||
break;
|
||||
case DIV_CMD_MACRO_RESTART:
|
||||
chan[c.chan].std.restart(c.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
chWrite(ch,0x06,isMuted[ch]?0:volPan(chan[ch].outVol,chan[ch].pan));
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::forceIns() {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].insChanged=true;
|
||||
chan[i].freqChanged=true;
|
||||
if (i<3) {
|
||||
chWrite(i,0x03,chan[i].initLFSR&0xff);
|
||||
chWrite(i,0x04,chan[i].initLFSR>>8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* DivPlatformPowerNoise::getChanState(int ch) {
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformPowerNoise::getChanMacroInt(int ch) {
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
unsigned short DivPlatformPowerNoise::getPan(int ch) {
|
||||
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
|
||||
}
|
||||
|
||||
DivChannelModeHints DivPlatformPowerNoise::getModeHints(int ch) {
|
||||
DivChannelModeHints ret;
|
||||
ret.count=0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DivPlatformPowerNoise::getDCOffRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformPowerNoise::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformPowerNoise::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
||||
int DivPlatformPowerNoise::getRegisterPoolSize() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::reset() {
|
||||
memset(regPool,0,32);
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i]=DivPlatformPowerNoise::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
chan[i].slope=(i==3);
|
||||
}
|
||||
|
||||
pwrnoise_reset(&pn);
|
||||
|
||||
// set master volume to full
|
||||
rWrite(0,0x87);
|
||||
// set per-channel panning
|
||||
for (int i=0; i<4; i++) {
|
||||
chWrite(i,0x06,volPan(chan[i].outVol,chan[i].pan));
|
||||
}
|
||||
// set default params so we have sound
|
||||
// noise
|
||||
for (int i=0; i<3; i++) {
|
||||
chWrite(i,0x03,chan[i].initLFSR&0xff);
|
||||
chWrite(i,0x04,chan[i].initLFSR>>8);
|
||||
chWrite(i,0x05,(chan[i].tapA<<4)|chan[i].tapB);
|
||||
}
|
||||
// slope
|
||||
chWrite(3,0x03,chan[3].slopeA.len);
|
||||
chWrite(3,0x04,chan[3].slopeB.len);
|
||||
chWrite(3,0x05,(chan[3].slopeA.offset<<4)|chan[3].slopeB.offset);
|
||||
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
|
||||
int DivPlatformPowerNoise::getOutputCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool DivPlatformPowerNoise::keyOffAffectsArp(int ch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::notifyWaveChange(int wave) {
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::setFlags(const DivConfig& flags) {
|
||||
chipClock=16000000;
|
||||
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/32;
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::poke(unsigned int addr, unsigned short val) {
|
||||
rWrite(addr,val);
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::poke(std::vector<DivRegWrite>& wlist) {
|
||||
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
int DivPlatformPowerNoise::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
isMuted[i]=false;
|
||||
}
|
||||
setFlags(flags);
|
||||
reset();
|
||||
return 4;
|
||||
}
|
||||
|
||||
void DivPlatformPowerNoise::quit() {
|
||||
for (int i=0; i<4; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformPowerNoise::~DivPlatformPowerNoise() {
|
||||
}
|
||||
108
src/engine/platform/powernoise.h
Normal file
108
src/engine/platform/powernoise.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2024 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _POWERNOISE_H
|
||||
#define _POWERNOISE_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include "../../../extern/pwrnoise/pwrnoise.h"
|
||||
|
||||
class DivPlatformPowerNoise: public DivDispatch {
|
||||
struct SlopePortion {
|
||||
unsigned char len, offset;
|
||||
bool clip, reset, dir;
|
||||
|
||||
SlopePortion(unsigned char l, unsigned char o, bool c, bool r, bool d):
|
||||
len(l),
|
||||
offset(o),
|
||||
clip(c),
|
||||
reset(r),
|
||||
dir(d) {}
|
||||
|
||||
SlopePortion():
|
||||
len(0),
|
||||
offset(0),
|
||||
clip(false),
|
||||
reset(false),
|
||||
dir(false) {}
|
||||
};
|
||||
|
||||
struct Channel: public SharedChannel<signed char> {
|
||||
int fNum;
|
||||
unsigned short initLFSR;
|
||||
unsigned char octave, pan, tapA, tapB, octaveOff;
|
||||
bool slope, am, tapBEnable, keyOn, keyOff;
|
||||
SlopePortion slopeA, slopeB;
|
||||
|
||||
Channel():
|
||||
SharedChannel<signed char>(15),
|
||||
fNum(0),
|
||||
initLFSR(0x5555),
|
||||
octave(0),
|
||||
pan(255),
|
||||
tapA(1),
|
||||
tapB(2),
|
||||
octaveOff(0),
|
||||
slope(false),
|
||||
am(false),
|
||||
tapBEnable(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
slopeA(255,1,false,false,false),
|
||||
slopeB() {}
|
||||
};
|
||||
|
||||
Channel chan[4];
|
||||
DivDispatchOscBuffer* oscBuf[4];
|
||||
bool isMuted[4];
|
||||
unsigned char regPool[32];
|
||||
|
||||
power_noise_t pn;
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
void acquire(short** buf, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
unsigned short getPan(int chan);
|
||||
DivChannelModeHints getModeHints(int chan);
|
||||
bool getDCOffRequired();
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
int getOutputCount();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void setFlags(const DivConfig& flags);
|
||||
void notifyWaveChange(int wave);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
~DivPlatformPowerNoise();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -451,7 +451,9 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
chan[c.chan].isNewQSound=(ins->type==DIV_INS_QSOUND);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(c.value);
|
||||
|
|
@ -543,7 +545,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=QS_NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=QS_NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -566,7 +568,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -184,7 +184,9 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
|
|
@ -243,7 +245,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -266,7 +268,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -189,7 +189,9 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].pcm.sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].pcm.sample=-1;
|
||||
|
|
@ -297,7 +299,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=(c.value2<<7);
|
||||
int destFreq=((c.value2+chan[c.chan].sampleNoteDelta)<<7);
|
||||
int newFreq;
|
||||
int mul=(oldSlides || parent->song.linearPitch!=2)?8:1;
|
||||
bool return2=false;
|
||||
|
|
@ -323,7 +325,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=(c.value<<7);
|
||||
chan[c.chan].baseFreq=((c.value+chan[c.chan].sampleNoteDelta)<<7);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,6 +333,8 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
|||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SNES);
|
||||
if (ins->amiga.useWave) {
|
||||
chan[c.chan].useWave=true;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
chan[c.chan].wtLen=ins->amiga.waveLen+1;
|
||||
if (chan[c.chan].insChanged) {
|
||||
if (chan[c.chan].wave<0) {
|
||||
|
|
@ -345,7 +347,9 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
|||
} else {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
chan[c.chan].useWave=false;
|
||||
}
|
||||
|
|
@ -424,7 +428,7 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
|||
chan[c.chan].ws.changeWave1(chan[c.chan].wave);
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=round(NOTE_FREQUENCY(c.value2));
|
||||
int destFreq=round(NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta));
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -447,7 +451,7 @@ int DivPlatformSNES::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))));
|
||||
chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ protected:
|
|||
uint8_t m_clock_prescale; // prescale factor (2/3/6)
|
||||
uint8_t m_irq_mask; // mask of which bits signal IRQs
|
||||
uint8_t m_irq_state; // current IRQ state
|
||||
uint8_t m_timer_running[2]; // current timer running state
|
||||
uint8_t m_timer_running[4]; // current timer running state
|
||||
uint8_t m_total_clocks; // low 8 bits of the total number of clocks processed
|
||||
uint32_t m_active_channels; // mask of active channels (computed by prepare)
|
||||
uint32_t m_modified_channels; // mask of channels that have been modified
|
||||
|
|
|
|||
|
|
@ -1198,7 +1198,7 @@ fm_engine_base<RegisterType>::fm_engine_base(ymfm_interface &intf) :
|
|||
m_clock_prescale(RegisterType::DEFAULT_PRESCALE),
|
||||
m_irq_mask(STATUS_TIMERA | STATUS_TIMERB),
|
||||
m_irq_state(0),
|
||||
m_timer_running{0,0},
|
||||
m_timer_running{0,0,0,0},
|
||||
m_total_clocks(0),
|
||||
m_active_channels(ALL_CHANNELS),
|
||||
m_modified_channels(ALL_CHANNELS),
|
||||
|
|
|
|||
|
|
@ -282,8 +282,13 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
if (chan[c.chan].pcm) {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_SU(c.chan,c.value);
|
||||
|
|
@ -450,7 +455,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_SU(c.chan,c.value2);
|
||||
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)));
|
||||
|
|
@ -482,7 +487,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOn=true;
|
||||
break;
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_SU(c.chan,c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_SU(c.chan,c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -257,6 +257,8 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
pcm=true;
|
||||
} else if (furnaceDac) {
|
||||
pcm=false;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
if (pcm) {
|
||||
if (skipRegisterWrites) break;
|
||||
|
|
@ -265,7 +267,12 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
dacSample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
dacSample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
dacSample=-1;
|
||||
|
|
@ -332,6 +339,8 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
dacSample=-1;
|
||||
if (dumpWrites) postWrite(0xffff0002,0);
|
||||
pcm=false;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
|
|
@ -383,7 +392,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -412,7 +421,13 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_MODE:
|
||||
if (c.chan==1) pcm=c.value;
|
||||
if (c.chan==1) {
|
||||
pcm=c.value;
|
||||
if (!pcm) {
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
|
|
@ -426,7 +441,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -299,10 +299,15 @@ int DivPlatformVERA::dispatch(DivCommand c) {
|
|||
if (c.chan<16) {
|
||||
rWriteLo(c.chan,2,chan[c.chan].vol);
|
||||
} else {
|
||||
DivInstrument* ins=parent->getIns(chan[16].ins,DIV_INS_VERA);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
DivInstrument* ins=parent->getIns(chan[16].ins,DIV_INS_VERA);
|
||||
chan[16].pcm.sample=ins->amiga.getSample(c.value);
|
||||
chan[16].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[16].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[16].pcm.sample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (chan[16].pcm.sample<0 || chan[16].pcm.sample>=parent->song.sampleLen) {
|
||||
chan[16].pcm.sample=-1;
|
||||
|
|
@ -371,7 +376,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=calcNoteFreq(c.chan,c.value2);
|
||||
int destFreq=calcNoteFreq(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -394,7 +399,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=calcNoteFreq(c.chan,c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=calcNoteFreq(c.chan,c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -236,13 +236,20 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
chan[c.chan].pcm=true;
|
||||
} else if (chan[c.chan].furnaceDac) {
|
||||
chan[c.chan].pcm=false;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
if (chan[c.chan].pcm) {
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
|
|
@ -270,6 +277,8 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
//chan[c.chan].keyOn=true;
|
||||
chan[c.chan].furnaceDac=true;
|
||||
} else {
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
|
|
@ -314,6 +323,8 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
|
||||
chan[c.chan].pcm=false;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
|
|
@ -352,7 +363,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_PERIODIC(c.value2);
|
||||
int destFreq=NOTE_PERIODIC(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -382,6 +393,10 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
case DIV_CMD_SAMPLE_MODE:
|
||||
if (c.chan!=2) { // pulse
|
||||
chan[c.chan].pcm=c.value;
|
||||
if (!chan[c.chan].pcm) {
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
|
|
@ -391,7 +406,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -536,6 +536,8 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
}
|
||||
if (skipRegisterWrites) break;
|
||||
if (chan[c.chan].furnacePCM) {
|
||||
|
|
@ -543,7 +545,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroInit(ins);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
|
|
@ -608,6 +612,8 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
}
|
||||
} else if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].sampleNote=DIV_NOTE_NULL;
|
||||
chan[c.chan].sampleNoteDelta=0;
|
||||
chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note);
|
||||
chan[c.chan].fixedFreq=0;
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
|
@ -684,7 +690,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NoteX1_010(c.chan,c.value2);
|
||||
int destFreq=NoteX1_010(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -732,7 +738,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
|
|
|
|||
|
|
@ -919,7 +919,9 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
|
|
@ -1109,7 +1111,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
if (c.chan>5 || parent->song.linearPitch==2) { // PSG, ADPCM-B
|
||||
int destFreq=NOTE_OPNB(c.chan,c.value2);
|
||||
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -1150,7 +1152,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
}
|
||||
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value+chan[c.chan].sampleNoteDelta);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -850,7 +850,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
|
|
@ -1081,7 +1083,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B
|
||||
int destFreq=NOTE_OPNB(c.chan,c.value2);
|
||||
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -1122,7 +1124,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
}
|
||||
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value+chan[c.chan].sampleNoteDelta);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -917,7 +917,9 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
|
|
@ -1148,7 +1150,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B
|
||||
int destFreq=NOTE_OPNB(c.chan,c.value2);
|
||||
int destFreq=NOTE_OPNB(c.chan,c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -1189,7 +1191,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
}
|
||||
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value+chan[c.chan].sampleNoteDelta);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,9 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
|
|
@ -272,7 +274,7 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
int multiplier=(parent->song.linearPitch==2)?1:256;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
|
|
@ -296,7 +298,7 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -30,13 +30,14 @@ const char** DivPlatformZXBeeperQuadTone::getRegisterSheet() {
|
|||
}
|
||||
|
||||
void DivPlatformZXBeeperQuadTone::acquire(short** buf, size_t len) {
|
||||
bool o=false;
|
||||
for (size_t h=0; h<len; h++) {
|
||||
if (curSample>=0 && curSample<parent->song.sampleLen && !isMuted[4]) {
|
||||
bool sampleActive=false;
|
||||
if (curSample>=0 && curSample<parent->song.sampleLen) {
|
||||
sampleActive=!isMuted[4];
|
||||
while (curSamplePeriod>=chan[4].freq) {
|
||||
DivSample* s=parent->getSample(curSample);
|
||||
if (s->samples>0) {
|
||||
if (!isMuted[4]) o=(s->data8[curSamplePos++]>0);
|
||||
chan[4].out=(s->data8[curSamplePos++]>0);
|
||||
if (curSamplePos>=s->samples) curSample=-1;
|
||||
// (theoretical) 32KiB limit
|
||||
if (curSamplePos>=32768*8) curSample=-1;
|
||||
|
|
@ -46,46 +47,47 @@ void DivPlatformZXBeeperQuadTone::acquire(short** buf, size_t len) {
|
|||
curSamplePeriod-=chan[4].freq;
|
||||
}
|
||||
curSamplePeriod+=40;
|
||||
if ((outputClock&3)==0) {
|
||||
}
|
||||
if (sampleActive) {
|
||||
buf[0][h]=chan[4].out?32767:0;
|
||||
if (outputClock==0) {
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=0;
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=0;
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=0;
|
||||
oscBuf[3]->data[oscBuf[3]->needle++]=0;
|
||||
oscBuf[4]->data[oscBuf[4]->needle++]=o?32767:0;
|
||||
}
|
||||
oscBuf[4]->data[oscBuf[4]->needle++]=buf[0][h];
|
||||
} else {
|
||||
int ch=outputClock/2;
|
||||
int b=ch*4;
|
||||
bool o=false;
|
||||
if ((outputClock&1)==0) {
|
||||
short oscOut;
|
||||
chan[ch].sPosition+=(regPool[1+b]<<8)|regPool[0+b];
|
||||
chan[ch].out=regPool[3+b]+((((chan[ch].sPosition>>8)&0xff)<regPool[2+b])?1:0);
|
||||
if (isMuted[ch]) chan[ch].out=0;
|
||||
}
|
||||
if ((outputClock&3)==0) {
|
||||
oscBuf[4]->data[oscBuf[4]->needle++]=0;
|
||||
}
|
||||
o=chan[ch].out&0x10;
|
||||
oscBuf[ch]->data[oscBuf[ch]->needle++]=o?32767:0;
|
||||
chan[ch].out<<=1;
|
||||
|
||||
// if muted, ztill run sample
|
||||
if (curSample>=0 && curSample<parent->song.sampleLen && isMuted[4]) {
|
||||
while (curSamplePeriod>=chan[4].freq) {
|
||||
DivSample* s=parent->getSample(curSample);
|
||||
if (s->samples>0) {
|
||||
if (curSamplePos>=s->samples) curSample=-1;
|
||||
// (theoretical) 32KiB limit
|
||||
if (curSamplePos>=32768*8) curSample=-1;
|
||||
} else {
|
||||
curSample=-1;
|
||||
}
|
||||
curSamplePeriod-=chan[4].freq;
|
||||
if (isMuted[ch] || ((chan[ch].out&0x18)==0)) {
|
||||
oscOut=0;
|
||||
} else if ((chan[ch].out&0x18)==0x18) {
|
||||
oscOut=32767;
|
||||
} else {
|
||||
oscOut=16383;
|
||||
}
|
||||
curSamplePeriod+=40;
|
||||
oscBuf[ch]->data[oscBuf[ch]->needle++]=oscOut;
|
||||
}
|
||||
if (!isMuted[ch]) o=chan[ch].out&0x10;
|
||||
if (noHiss) {
|
||||
deHisser[outputClock]=o;
|
||||
buf[0][h]=-1;
|
||||
for (int i=0; i<8; i++) {
|
||||
buf[0][h]+=deHisser[i]?4096:0;
|
||||
}
|
||||
} else {
|
||||
buf[0][h]=o?32767:0;
|
||||
}
|
||||
chan[ch].out<<=1;
|
||||
oscBuf[4]->data[oscBuf[4]->needle++]=0;
|
||||
}
|
||||
outputClock=(outputClock+1)&7;
|
||||
buf[0][h]=o?32767:0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -157,6 +159,7 @@ void DivPlatformZXBeeperQuadTone::tick(bool sysTick) {
|
|||
chan[4].freq=parent->calcFreq(chan[4].baseFreq,chan[4].pitch,chan[4].fixedArp?chan[4].baseNoteOverride:chan[4].arpOff,chan[4].fixedArp,true,2,chan[4].pitch2,chipClock,off);
|
||||
if (chan[4].freq>258) chan[4].freq=258;
|
||||
if (chan[4].freq<3) chan[4].freq=3;
|
||||
rWrite(16,(chan[4].freq-2)&255);
|
||||
chan[4].freq*=13;
|
||||
}
|
||||
if (chan[4].keyOn) chan[4].keyOn=false;
|
||||
|
|
@ -187,13 +190,21 @@ int DivPlatformZXBeeperQuadTone::dispatch(DivCommand c) {
|
|||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
curSample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
// TODO support offset commands
|
||||
curSamplePos=0;
|
||||
curSamplePeriod=0;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
curSample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
// TODO support offset commands
|
||||
curSamplePos=0;
|
||||
curSamplePeriod=0;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
|
|
@ -241,7 +252,7 @@ int DivPlatformZXBeeperQuadTone::dispatch(DivCommand c) {
|
|||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int destFreq=NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
|
|
@ -268,7 +279,7 @@ int DivPlatformZXBeeperQuadTone::dispatch(DivCommand c) {
|
|||
if (c.chan<4) rWrite(2+c.chan*4,chan[c.chan].duty^0xff);
|
||||
break;
|
||||
case DIV_CMD_LEGATO:
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
break;
|
||||
|
|
@ -332,11 +343,12 @@ unsigned char* DivPlatformZXBeeperQuadTone::getRegisterPool() {
|
|||
}
|
||||
|
||||
int DivPlatformZXBeeperQuadTone::getRegisterPoolSize() {
|
||||
return 16;
|
||||
return 17;
|
||||
}
|
||||
|
||||
void DivPlatformZXBeeperQuadTone::reset() {
|
||||
memset(regPool,0,16);
|
||||
memset(regPool,0,17);
|
||||
memset(deHisser,0,8);
|
||||
for (int i=0; i<5; i++) {
|
||||
chan[i]=DivPlatformZXBeeperQuadTone::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
|
|
@ -345,7 +357,6 @@ void DivPlatformZXBeeperQuadTone::reset() {
|
|||
cycles=0;
|
||||
curChan=0;
|
||||
sOffTimer=0;
|
||||
ulaOut=0;
|
||||
curSample=-1;
|
||||
curSamplePos=0;
|
||||
curSamplePeriod=0;
|
||||
|
|
@ -373,9 +384,11 @@ void DivPlatformZXBeeperQuadTone::setFlags(const DivConfig& flags) {
|
|||
}
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/40;
|
||||
noHiss=flags.getBool("noHiss",false);
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->rate=rate/4;
|
||||
oscBuf[i]->rate=rate/8;
|
||||
}
|
||||
oscBuf[4]->rate=rate;
|
||||
}
|
||||
|
||||
void DivPlatformZXBeeperQuadTone::poke(unsigned int addr, unsigned short val) {
|
||||
|
|
|
|||
|
|
@ -36,12 +36,13 @@ class DivPlatformZXBeeperQuadTone: public DivDispatch {
|
|||
Channel chan[5];
|
||||
DivDispatchOscBuffer* oscBuf[5];
|
||||
bool isMuted[5];
|
||||
unsigned char ulaOut;
|
||||
bool noHiss;
|
||||
bool deHisser[8];
|
||||
|
||||
int cycles, curChan, sOffTimer, delay, curSample, curSamplePeriod;
|
||||
unsigned int curSamplePos;
|
||||
unsigned int outputClock;
|
||||
unsigned char regPool[16];
|
||||
unsigned char regPool[17];
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue