mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-24 05:25:12 +00:00
Prepare for split sample chip instrument
(MSM6258, MSM6295, QSound, Sega PCM, ADPCM-A, ADPCM-B, YMZ280B, RF5C68) Instrument color and icons are placeholder. different volume range, hard panned/soft panned and/or independent volume per output, chip-dependent features (global volume, echo, etc) Allow use sample in instrument tab for chip with sample support Prepare to support X1-010 Seta 2 style bankswitch behavior Prepare to support AY89x0 PCM DAC Support volume for PCE sample (DAC) Fix Lynx, Y8950 sample pitch matches to sample preview Support PCM DAC with backward and pingpong loop mode Reduce some codes Add Sega PCM, AY89x0, QSound, PCM DAC, Lynx per-channel debug support
This commit is contained in:
parent
86baa8c014
commit
4cc79fb49d
53 changed files with 2928 additions and 1301 deletions
|
@ -165,6 +165,7 @@ enum DivDispatchCmds {
|
|||
DIV_CMD_X1_010_ENVELOPE_PERIOD,
|
||||
DIV_CMD_X1_010_ENVELOPE_SLIDE,
|
||||
DIV_CMD_X1_010_AUTO_ENVELOPE,
|
||||
DIV_CMD_X1_010_SAMPLE_BANK_SLOT,
|
||||
|
||||
DIV_CMD_WS_SWEEP_TIME,
|
||||
DIV_CMD_WS_SWEEP_AMOUNT,
|
||||
|
@ -189,6 +190,8 @@ enum DivDispatchCmds {
|
|||
DIV_CMD_SU_SYNC_PERIOD_LOW,
|
||||
DIV_CMD_SU_SYNC_PERIOD_HIGH,
|
||||
|
||||
DIV_CMD_ADPCMA_GLOBAL_VOLUME,
|
||||
|
||||
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
||||
|
||||
DIV_CMD_MAX
|
||||
|
|
|
@ -529,7 +529,7 @@ void DivInstrument::putInsData(SafeWriter* w) {
|
|||
}
|
||||
|
||||
// Sound Unit
|
||||
w->writeC(su.useSample);
|
||||
w->writeC(amiga.useSample);
|
||||
w->writeC(su.switchRoles);
|
||||
|
||||
// GB hardware sequence
|
||||
|
@ -1092,7 +1092,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
|
||||
// Sound Unit
|
||||
if (version>=104) {
|
||||
su.useSample=reader.readC();
|
||||
amiga.useSample=reader.readC();
|
||||
su.switchRoles=reader.readC();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,14 @@ enum DivInstrumentType: unsigned short {
|
|||
DIV_INS_SU=30,
|
||||
DIV_INS_NAMCO=31,
|
||||
DIV_INS_OPL_DRUMS=32,
|
||||
DIV_INS_MSM6258=33,
|
||||
DIV_INS_MSM6295=34,
|
||||
DIV_INS_ADPCMA=35,
|
||||
DIV_INS_ADPCMB=36,
|
||||
DIV_INS_SEGAPCM=37,
|
||||
DIV_INS_QSOUND=38,
|
||||
DIV_INS_YMZ280B=39,
|
||||
DIV_INS_RF5C68=40,
|
||||
DIV_INS_MAX,
|
||||
DIV_INS_NULL
|
||||
};
|
||||
|
@ -335,6 +343,7 @@ struct DivInstrumentAmiga {
|
|||
};
|
||||
short initSample;
|
||||
bool useNoteMap;
|
||||
bool useSample;
|
||||
bool useWave;
|
||||
unsigned char waveLen;
|
||||
SampleMap noteMap[120];
|
||||
|
@ -368,6 +377,7 @@ struct DivInstrumentAmiga {
|
|||
DivInstrumentAmiga():
|
||||
initSample(0),
|
||||
useNoteMap(false),
|
||||
useSample(false),
|
||||
useWave(false),
|
||||
waveLen(31) {
|
||||
for (SampleMap& elem: noteMap) {
|
||||
|
@ -376,6 +386,13 @@ struct DivInstrumentAmiga {
|
|||
}
|
||||
};
|
||||
|
||||
struct DivInstrumentX1_010 {
|
||||
int bankSlot;
|
||||
|
||||
DivInstrumentX1_010():
|
||||
bankSlot(0) {}
|
||||
};
|
||||
|
||||
struct DivInstrumentN163 {
|
||||
int wave, wavePos, waveLen;
|
||||
unsigned char waveMode;
|
||||
|
@ -458,13 +475,69 @@ struct DivInstrumentWaveSynth {
|
|||
};
|
||||
|
||||
struct DivInstrumentSoundUnit {
|
||||
bool useSample;
|
||||
bool switchRoles;
|
||||
DivInstrumentSoundUnit():
|
||||
useSample(false),
|
||||
switchRoles(false) {}
|
||||
};
|
||||
|
||||
struct DivInstrumentES5506 {
|
||||
struct Filter {
|
||||
enum FilterMode: unsigned char { // filter mode for pole 4,3
|
||||
FILTER_MODE_HPK2_HPK2=0,
|
||||
FILTER_MODE_HPK2_LPK1,
|
||||
FILTER_MODE_LPK2_LPK2,
|
||||
FILTER_MODE_LPK2_LPK1,
|
||||
};
|
||||
FilterMode mode;
|
||||
unsigned short k1, k2;
|
||||
Filter():
|
||||
mode(FILTER_MODE_LPK2_LPK1),
|
||||
k1(0xffff),
|
||||
k2(0xffff) {}
|
||||
};
|
||||
struct Envelope {
|
||||
unsigned short ecount;
|
||||
signed char lVRamp, rVRamp;
|
||||
signed char k1Ramp, k2Ramp;
|
||||
bool k1Slow, k2Slow;
|
||||
Envelope():
|
||||
ecount(0),
|
||||
lVRamp(0),
|
||||
rVRamp(0),
|
||||
k1Ramp(0),
|
||||
k2Ramp(0),
|
||||
k1Slow(false),
|
||||
k2Slow(false) {}
|
||||
};
|
||||
Filter filter;
|
||||
Envelope envelope;
|
||||
DivInstrumentES5506():
|
||||
filter(Filter()),
|
||||
envelope(Envelope()) {}
|
||||
};
|
||||
|
||||
struct DivInstrumentSNES {
|
||||
enum GainMode: unsigned char {
|
||||
GAIN_MODE_DIRECT=0,
|
||||
GAIN_MODE_DEC_LINEAR=4,
|
||||
GAIN_MODE_DEC_LOG=5,
|
||||
GAIN_MODE_INC_LINEAR=6,
|
||||
GAIN_MODE_INC_INVLOG=7
|
||||
};
|
||||
bool useEnv;
|
||||
GainMode gainMode;
|
||||
unsigned char gain;
|
||||
unsigned char a, d, s, r;
|
||||
DivInstrumentSNES():
|
||||
useEnv(true),
|
||||
gainMode(GAIN_MODE_DIRECT),
|
||||
gain(127),
|
||||
a(15),
|
||||
d(7),
|
||||
s(7),
|
||||
r(0) {}
|
||||
};
|
||||
|
||||
struct DivInstrument {
|
||||
String name;
|
||||
bool mode;
|
||||
|
@ -474,11 +547,14 @@ struct DivInstrument {
|
|||
DivInstrumentGB gb;
|
||||
DivInstrumentC64 c64;
|
||||
DivInstrumentAmiga amiga;
|
||||
DivInstrumentX1_010 x1_010;
|
||||
DivInstrumentN163 n163;
|
||||
DivInstrumentFDS fds;
|
||||
DivInstrumentMultiPCM multipcm;
|
||||
DivInstrumentWaveSynth ws;
|
||||
DivInstrumentSoundUnit su;
|
||||
DivInstrumentES5506 es5506;
|
||||
DivInstrumentSNES snes;
|
||||
|
||||
/**
|
||||
* save the instrument to a SafeWriter.
|
||||
|
|
|
@ -117,6 +117,46 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
ayBuf[i]=new short[ayBufLen];
|
||||
}
|
||||
}
|
||||
// PCM part
|
||||
for (int i=0; i<3; i++) {
|
||||
if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) {
|
||||
chan[i].dac.period+=chan[i].dac.rate;
|
||||
bool end=false;
|
||||
bool changed=false;
|
||||
int prev_out = chan[i].dac.out;
|
||||
while (chan[i].dac.period>rate && !end) {
|
||||
DivSample* s=parent->getSample(chan[i].dac.sample);
|
||||
if (s->getEndPosition()<=0) {
|
||||
chan[i].dac.sample=-1;
|
||||
rWrite(0x08+i,0);
|
||||
end=true;
|
||||
break;
|
||||
}
|
||||
unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>4);
|
||||
chan[i].dac.out=MAX(0,MIN(15,(dacData*chan[i].outVol)/15));
|
||||
if (prev_out!=chan[i].dac.out) {
|
||||
prev_out=chan[i].dac.out;
|
||||
changed=true;
|
||||
}
|
||||
chan[i].dac.pos++;
|
||||
if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) {
|
||||
chan[i].dac.pos=s->getLoopStartPosition();
|
||||
} else if (chan[i].dac.pos>=s->getEndPosition()) {
|
||||
chan[i].dac.sample=-1;
|
||||
rWrite(0x08+i,0);
|
||||
end=true;
|
||||
break;
|
||||
}
|
||||
chan[i].dac.period-=rate;
|
||||
}
|
||||
if (changed && !end) {
|
||||
if (!isMuted[i]) {
|
||||
rWrite(0x08+i,chan[i].dac.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
if (intellivision) {
|
||||
|
@ -157,22 +197,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
void DivPlatformAY8910::updateOutSel(bool immediate) {
|
||||
if (immediate) {
|
||||
immWrite(0x07,
|
||||
~((chan[0].psgMode&1)|
|
||||
((chan[1].psgMode&1)<<1)|
|
||||
((chan[2].psgMode&1)<<2)|
|
||||
((chan[0].psgMode&2)<<2)|
|
||||
((chan[1].psgMode&2)<<3)|
|
||||
((chan[2].psgMode&2)<<4)|
|
||||
~((chan[0].psgMode.getTone())|
|
||||
((chan[1].psgMode.getTone())<<1)|
|
||||
((chan[2].psgMode.getTone())<<2)|
|
||||
((chan[0].psgMode.getNoise())<<2)|
|
||||
((chan[1].psgMode.getNoise())<<3)|
|
||||
((chan[2].psgMode.getNoise())<<4)|
|
||||
((!ioPortA)<<6)|
|
||||
((!ioPortB)<<7)));
|
||||
} else {
|
||||
rWrite(0x07,
|
||||
~((chan[0].psgMode&1)|
|
||||
((chan[1].psgMode&1)<<1)|
|
||||
((chan[2].psgMode&1)<<2)|
|
||||
((chan[0].psgMode&2)<<2)|
|
||||
((chan[1].psgMode&2)<<3)|
|
||||
((chan[2].psgMode&2)<<4)|
|
||||
~((chan[0].psgMode.getTone())|
|
||||
((chan[1].psgMode.getTone())<<1)|
|
||||
((chan[2].psgMode.getTone())<<2)|
|
||||
((chan[0].psgMode.getNoise())<<2)|
|
||||
((chan[1].psgMode.getNoise())<<3)|
|
||||
((chan[2].psgMode.getNoise())<<4)|
|
||||
((!ioPortA)<<6)|
|
||||
((!ioPortB)<<7)));
|
||||
}
|
||||
|
@ -185,12 +225,14 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
|||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else if (intellivision && (chan[i].psgMode&4)) {
|
||||
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
||||
if (!chan[i].psgMode.dac) {
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else if (intellivision && (chan[i].psgMode.getEnvelope())) {
|
||||
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
|
@ -212,13 +254,15 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
|||
rWrite(0x06,31-chan[i].std.duty.val);
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else if (intellivision && (chan[i].psgMode&4)) {
|
||||
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
||||
if (!chan[i].psgMode.dac) {
|
||||
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else if (intellivision && (chan[i].psgMode.getEnvelope())) {
|
||||
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
|
@ -232,6 +276,20 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
if (chan[i].psgMode.dac) {
|
||||
if (dumpWrites) addWrite(0xffff0002+(i<<8),0);
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AY);
|
||||
chan[i].dac.sample=ins->amiga.getSample(chan[i].note);
|
||||
if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) {
|
||||
if (dumpWrites) {
|
||||
rWrite(0x08+i,0);
|
||||
addWrite(0xffff0000+(i<<8),chan[i].dac.sample);
|
||||
}
|
||||
chan[i].dac.pos=0;
|
||||
chan[i].dac.period=0;
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
oldWrites[0x08+i]=-1;
|
||||
oldWrites[0x0d]=-1;
|
||||
}
|
||||
|
@ -252,6 +310,19 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
||||
if (chan[i].dac.furnaceDAC) {
|
||||
double off=1.0;
|
||||
if (chan[i].dac.sample>=0 && chan[i].dac.sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[i].dac.sample);
|
||||
if (s->centerRate<1) {
|
||||
off=1.0;
|
||||
} else {
|
||||
off=8363.0/(double)s->centerRate;
|
||||
}
|
||||
}
|
||||
chan[i].dac.rate=((double)chipClock*4096.0)/(double)(MAX(1,off*chan[i].freq));
|
||||
if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate);
|
||||
}
|
||||
if (chan[i].freq>4095) chan[i].freq=4095;
|
||||
if (chan[i].keyOn) {
|
||||
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
|
||||
|
@ -307,6 +378,62 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY);
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].psgMode.dac=true;
|
||||
} else if (chan[c.chan].dac.furnaceDAC) {
|
||||
chan[c.chan].psgMode.dac=false;
|
||||
}
|
||||
if (chan[c.chan].psgMode.dac) {
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].dac.sample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dac.sample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
|
||||
break;
|
||||
} else {
|
||||
if (dumpWrites) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample);
|
||||
}
|
||||
}
|
||||
chan[c.chan].dac.pos=0;
|
||||
chan[c.chan].dac.period=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;
|
||||
}
|
||||
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].dac.furnaceDAC=true;
|
||||
} else {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].dac.sample=12*sampleBank+chan[c.chan].note%12;
|
||||
if (chan[c.chan].dac.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dac.sample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
|
||||
break;
|
||||
} else {
|
||||
if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample);
|
||||
}
|
||||
chan[c.chan].dac.pos=0;
|
||||
chan[c.chan].dac.period=0;
|
||||
chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate;
|
||||
if (dumpWrites) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate);
|
||||
}
|
||||
chan[c.chan].dac.furnaceDAC=false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -318,16 +445,21 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
if (!chan[c.chan].psgMode.dac) {
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].dac.sample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
|
||||
chan[c.chan].psgMode.dac=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
|
@ -341,14 +473,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
if (chan[c.chan].active) {
|
||||
if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
if (!chan[c.chan].psgMode.dac) {
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
if (chan[c.chan].active) {
|
||||
if (intellivision && (chan[c.chan].psgMode.getEnvelope())) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -398,15 +532,17 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_STD_NOISE_MODE:
|
||||
if (c.value<16) {
|
||||
chan[c.chan].psgMode=(c.value+1)&7;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (chan[c.chan].active) {
|
||||
if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
if (!chan[c.chan].psgMode.dac) {
|
||||
if (c.value<16) {
|
||||
chan[c.chan].psgMode=(c.value+1)&7;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (chan[c.chan].active) {
|
||||
if (intellivision && (chan[c.chan].psgMode.getEnvelope())) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode.getEnvelope())<<2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -418,16 +554,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
ayEnvMode=c.value>>4;
|
||||
rWrite(0x0d,ayEnvMode);
|
||||
if (c.value&15) {
|
||||
chan[c.chan].psgMode|=4;
|
||||
chan[c.chan].psgMode.envelope|=1;
|
||||
} else {
|
||||
chan[c.chan].psgMode&=~4;
|
||||
chan[c.chan].psgMode.envelope&=~1;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (intellivision && (chan[c.chan].psgMode&4)) {
|
||||
} else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2));
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_AY_ENVELOPE_LOW:
|
||||
|
@ -464,6 +600,15 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
|||
updateOutSel(true);
|
||||
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_MODE:
|
||||
chan[c.chan].psgMode.dac=(c.value>0)?1:0;
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 0;
|
||||
break;
|
||||
|
@ -492,10 +637,14 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) {
|
|||
isMuted[ch]=mute;
|
||||
if (isMuted[ch]) {
|
||||
rWrite(0x08+ch,0);
|
||||
} else if (intellivision && (chan[ch].psgMode&4) && chan[ch].active) {
|
||||
rWrite(0x08+ch,(chan[ch].vol&0xc)<<2);
|
||||
} else if (chan[ch].active) {
|
||||
rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode&4)<<2));
|
||||
} else if (chan[ch].active && chan[ch].psgMode.dac) {
|
||||
rWrite(0x08+ch,chan[ch].dac.out);
|
||||
} else {
|
||||
if (intellivision && (chan[ch].psgMode.getEnvelope()) && chan[ch].active) {
|
||||
rWrite(0x08+ch,(chan[ch].vol&0xc)<<2);
|
||||
} else if (chan[ch].active) {
|
||||
rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode.getEnvelope())<<2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,12 +703,6 @@ void DivPlatformAY8910::reset() {
|
|||
pendingWrites[i]=-1;
|
||||
}
|
||||
|
||||
lastBusy=60;
|
||||
dacMode=0;
|
||||
dacPeriod=0;
|
||||
dacPos=0;
|
||||
dacRate=0;
|
||||
dacSample=-1;
|
||||
sampleBank=0;
|
||||
ayEnvPeriod=0;
|
||||
ayEnvMode=0;
|
||||
|
|
|
@ -31,20 +31,83 @@ class DivPlatformAY8910: public DivDispatch {
|
|||
};
|
||||
inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
|
||||
struct Channel {
|
||||
unsigned char freqH, freqL;
|
||||
struct PSGMode {
|
||||
unsigned char tone: 1;
|
||||
unsigned char noise: 1;
|
||||
unsigned char envelope: 1;
|
||||
unsigned char dac: 1;
|
||||
|
||||
unsigned char getTone() {
|
||||
return dac?0:(tone<<0);
|
||||
}
|
||||
|
||||
unsigned char getNoise() {
|
||||
return dac?0:(noise<<1);
|
||||
}
|
||||
|
||||
unsigned char getEnvelope() {
|
||||
return dac?0:(envelope<<2);
|
||||
}
|
||||
|
||||
PSGMode& operator=(unsigned char s) {
|
||||
tone=(s>>0)&1;
|
||||
noise=(s>>1)&1;
|
||||
envelope=(s>>2)&1;
|
||||
dac=(s>>3)&1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PSGMode():
|
||||
tone(1),
|
||||
noise(0),
|
||||
envelope(0),
|
||||
dac(0) {}
|
||||
} psgMode;
|
||||
|
||||
struct DAC {
|
||||
int sample, rate, period, pos, out;
|
||||
unsigned char furnaceDAC: 1;
|
||||
|
||||
DAC():
|
||||
sample(-1),
|
||||
rate(0),
|
||||
period(0),
|
||||
pos(0),
|
||||
out(0),
|
||||
furnaceDAC(0) {}
|
||||
} dac;
|
||||
|
||||
int freq, baseFreq, note, pitch, pitch2;
|
||||
int ins;
|
||||
unsigned char psgMode, autoEnvNum, autoEnvDen;
|
||||
unsigned char autoEnvNum, autoEnvDen;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
||||
int vol, outVol;
|
||||
unsigned char pan;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
|
||||
Channel():
|
||||
psgMode(PSGMode()),
|
||||
dac(DAC()),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
note(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
ins(-1),
|
||||
autoEnvNum(0),
|
||||
autoEnvDen(0),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
portaPause(false),
|
||||
inPorta(false),
|
||||
vol(0),
|
||||
outVol(15) {}
|
||||
};
|
||||
Channel chan[3];
|
||||
bool isMuted[3];
|
||||
|
@ -60,11 +123,6 @@ class DivPlatformAY8910: public DivDispatch {
|
|||
unsigned char regPool[16];
|
||||
unsigned char lastBusy;
|
||||
|
||||
bool dacMode;
|
||||
int dacPeriod;
|
||||
int dacRate;
|
||||
int dacPos;
|
||||
int dacSample;
|
||||
unsigned char sampleBank;
|
||||
|
||||
int delay;
|
||||
|
|
|
@ -133,6 +133,46 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
ayBuf[i]=new short[ayBufLen];
|
||||
}
|
||||
}
|
||||
// PCM part
|
||||
for (int i=0; i<3; i++) {
|
||||
if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) {
|
||||
chan[i].dac.period+=chan[i].dac.rate;
|
||||
bool end=false;
|
||||
bool changed=false;
|
||||
int prev_out = chan[i].dac.out;
|
||||
while (chan[i].dac.period>rate && !end) {
|
||||
DivSample* s=parent->getSample(chan[i].dac.sample);
|
||||
if (s->getEndPosition()<=0) {
|
||||
chan[i].dac.sample=-1;
|
||||
rWrite(0x08+i,0);
|
||||
end=true;
|
||||
break;
|
||||
}
|
||||
unsigned char dacData=(((unsigned char)s->data8[chan[i].dac.pos]^0x80)>>3);
|
||||
chan[i].dac.out=MAX(0,MIN(31,(dacData*chan[i].outVol)/31));
|
||||
if (prev_out!=chan[i].dac.out) {
|
||||
prev_out=chan[i].dac.out;
|
||||
changed=true;
|
||||
}
|
||||
chan[i].dac.pos++;
|
||||
if (s->isLoopable() && chan[i].dac.pos>=s->getLoopEndPosition()) {
|
||||
chan[i].dac.pos=s->getLoopStartPosition();
|
||||
} else if (chan[i].dac.pos>=s->getEndPosition()) {
|
||||
chan[i].dac.sample=-1;
|
||||
rWrite(0x08+i,0);
|
||||
end=true;
|
||||
break;
|
||||
}
|
||||
chan[i].dac.period-=rate;
|
||||
}
|
||||
if (changed && !end) {
|
||||
if (!isMuted[i]) {
|
||||
rWrite(0x08+i,chan[i].dac.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
ay->address_w(w.addr);
|
||||
|
@ -167,22 +207,22 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
void DivPlatformAY8930::updateOutSel(bool immediate) {
|
||||
if (immediate) {
|
||||
immWrite(0x07,
|
||||
~((chan[0].psgMode&1)|
|
||||
((chan[1].psgMode&1)<<1)|
|
||||
((chan[2].psgMode&1)<<2)|
|
||||
((chan[0].psgMode&2)<<2)|
|
||||
((chan[1].psgMode&2)<<3)|
|
||||
((chan[2].psgMode&2)<<4)|
|
||||
~((chan[0].psgMode.getTone())|
|
||||
((chan[1].psgMode.getTone())<<1)|
|
||||
((chan[2].psgMode.getTone())<<2)|
|
||||
((chan[0].psgMode.getNoise())<<2)|
|
||||
((chan[1].psgMode.getNoise())<<3)|
|
||||
((chan[2].psgMode.getNoise())<<4)|
|
||||
((!ioPortA)<<6)|
|
||||
((!ioPortB)<<7)));
|
||||
} else {
|
||||
rWrite(0x07,
|
||||
~((chan[0].psgMode&1)|
|
||||
((chan[1].psgMode&1)<<1)|
|
||||
((chan[2].psgMode&1)<<2)|
|
||||
((chan[0].psgMode&2)<<2)|
|
||||
((chan[1].psgMode&2)<<3)|
|
||||
((chan[2].psgMode&2)<<4)|
|
||||
~((chan[0].psgMode.getTone())|
|
||||
((chan[1].psgMode.getTone())<<1)|
|
||||
((chan[2].psgMode.getTone())<<2)|
|
||||
((chan[0].psgMode.getNoise())<<2)|
|
||||
((chan[1].psgMode.getNoise())<<3)|
|
||||
((chan[2].psgMode.getNoise())<<4)|
|
||||
((!ioPortA)<<6)|
|
||||
((!ioPortB)<<7)));
|
||||
}
|
||||
|
@ -207,10 +247,12 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
|||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=MIN(31,chan[i].std.vol.val)-(31-(chan[i].vol&31));
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
|
||||
if (!chan[i].psgMode.dac) {
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
|
@ -232,11 +274,13 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
|||
rWrite(0x06,chan[i].std.duty.val);
|
||||
}
|
||||
if (chan[i].std.wave.had) {
|
||||
if (!chan[i].psgMode.dac) {
|
||||
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
||||
if (isMuted[i]) {
|
||||
rWrite(0x08+i,0);
|
||||
} else {
|
||||
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
|
||||
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
|
@ -250,6 +294,20 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
if (chan[i].psgMode.dac) {
|
||||
if (dumpWrites) addWrite(0xffff0002+(i<<8),0);
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AY8930);
|
||||
chan[i].dac.sample=ins->amiga.getSample(chan[i].note);
|
||||
if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) {
|
||||
if (dumpWrites) {
|
||||
rWrite(0x08+i,0);
|
||||
addWrite(0xffff0000+(i<<8),chan[i].dac.sample);
|
||||
}
|
||||
chan[i].dac.pos=0;
|
||||
chan[i].dac.period=0;
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
oldWrites[0x08+i]=-1;
|
||||
oldWrites[regMode[i]]=-1;
|
||||
}
|
||||
|
@ -281,6 +339,19 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
|||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
||||
if (chan[i].dac.furnaceDAC) {
|
||||
double off=1.0;
|
||||
if (chan[i].dac.sample>=0 && chan[i].dac.sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[i].dac.sample);
|
||||
if (s->centerRate<1) {
|
||||
off=1.0;
|
||||
} else {
|
||||
off=8363.0/(double)s->centerRate;
|
||||
}
|
||||
}
|
||||
chan[i].dac.rate=((double)chipClock*16384.0)/(double)(MAX(1,off*chan[i].freq));
|
||||
if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dac.rate);
|
||||
}
|
||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].insChanged) {
|
||||
|
@ -338,6 +409,62 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930);
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].psgMode.dac=true;
|
||||
} else if (chan[c.chan].dac.furnaceDAC) {
|
||||
chan[c.chan].psgMode.dac=false;
|
||||
}
|
||||
if (chan[c.chan].psgMode.dac) {
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].dac.sample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].dac.sample<0 || chan[c.chan].dac.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dac.sample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
|
||||
break;
|
||||
} else {
|
||||
if (dumpWrites) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample);
|
||||
}
|
||||
}
|
||||
chan[c.chan].dac.pos=0;
|
||||
chan[c.chan].dac.period=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;
|
||||
}
|
||||
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].dac.furnaceDAC=true;
|
||||
} else {
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].dac.sample=12*sampleBank+chan[c.chan].note%12;
|
||||
if (chan[c.chan].dac.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dac.sample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
|
||||
break;
|
||||
} else {
|
||||
if (dumpWrites) addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dac.sample);
|
||||
}
|
||||
chan[c.chan].dac.pos=0;
|
||||
chan[c.chan].dac.period=0;
|
||||
chan[c.chan].dac.rate=parent->getSample(chan[c.chan].dac.sample)->rate;
|
||||
if (dumpWrites) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dac.rate);
|
||||
}
|
||||
chan[c.chan].dac.furnaceDAC=false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -349,14 +476,19 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3));
|
||||
if (!chan[c.chan].psgMode.dac) {
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
chan[c.chan].dac.sample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002+(c.chan<<8),0);
|
||||
chan[c.chan].psgMode.dac=false;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
|
@ -370,13 +502,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3));
|
||||
if (!chan[c.chan].psgMode.dac) {
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLUME: {
|
||||
return chan[c.chan].vol;
|
||||
|
@ -423,11 +557,13 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_STD_NOISE_MODE:
|
||||
if (c.value<0x10) {
|
||||
chan[c.chan].psgMode=(c.value+1)&7;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (chan[c.chan].active) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode&4)<<3));
|
||||
if (!chan[c.chan].psgMode.dac) {
|
||||
chan[c.chan].psgMode=(c.value+1)&7;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else if (chan[c.chan].active) {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode.getEnvelope())<<3));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].duty=c.value&15;
|
||||
|
@ -441,14 +577,14 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
chan[c.chan].envelope.mode=c.value>>4;
|
||||
rWrite(regMode[c.chan],chan[c.chan].envelope.mode);
|
||||
if (c.value&15) {
|
||||
chan[c.chan].psgMode|=4;
|
||||
chan[c.chan].psgMode.envelope|=1;
|
||||
} else {
|
||||
chan[c.chan].psgMode&=~4;
|
||||
chan[c.chan].psgMode.envelope&=~1;
|
||||
}
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(0x08+c.chan,0);
|
||||
} else {
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3));
|
||||
rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3));
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_AY_ENVELOPE_LOW:
|
||||
|
@ -496,6 +632,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
|||
updateOutSel(true);
|
||||
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_MODE:
|
||||
chan[c.chan].psgMode.dac=(c.value>0)?1:0;
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 0;
|
||||
break;
|
||||
|
@ -523,7 +668,11 @@ void DivPlatformAY8930::muteChannel(int ch, bool mute) {
|
|||
if (isMuted[ch]) {
|
||||
rWrite(0x08+ch,0);
|
||||
} else if (chan[ch].active) {
|
||||
rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].psgMode&4)<<3));
|
||||
if (chan[ch].psgMode.dac) {
|
||||
rWrite(0x08+ch,chan[ch].dac.out&31);
|
||||
} else {
|
||||
rWrite(0x08+ch,(chan[ch].outVol&31)|((chan[ch].psgMode.getEnvelope())<<3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -578,6 +727,7 @@ void DivPlatformAY8930::reset() {
|
|||
pendingWrites[i]=-1;
|
||||
}
|
||||
|
||||
sampleBank=0;
|
||||
ayNoiseAnd=2;
|
||||
ayNoiseOr=0;
|
||||
delay=0;
|
||||
|
|
|
@ -38,20 +38,86 @@ class DivPlatformAY8930: public DivDispatch {
|
|||
slideLow(0),
|
||||
slide(0) {}
|
||||
} envelope;
|
||||
unsigned char freqH, freqL;
|
||||
|
||||
struct PSGMode {
|
||||
unsigned char tone: 1;
|
||||
unsigned char noise: 1;
|
||||
unsigned char envelope: 1;
|
||||
unsigned char dac: 1;
|
||||
|
||||
unsigned char getTone() {
|
||||
return dac?0:(tone<<0);
|
||||
}
|
||||
|
||||
unsigned char getNoise() {
|
||||
return dac?0:(noise<<1);
|
||||
}
|
||||
|
||||
unsigned char getEnvelope() {
|
||||
return dac?0:(envelope<<2);
|
||||
}
|
||||
|
||||
PSGMode& operator=(unsigned char s) {
|
||||
tone=(s>>0)&1;
|
||||
noise=(s>>1)&1;
|
||||
envelope=(s>>2)&1;
|
||||
dac=(s>>3)&1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PSGMode():
|
||||
tone(1),
|
||||
noise(0),
|
||||
envelope(0),
|
||||
dac(0) {}
|
||||
} psgMode;
|
||||
|
||||
struct DAC {
|
||||
int sample, rate, period, pos, out;
|
||||
unsigned char furnaceDAC: 1;
|
||||
|
||||
DAC():
|
||||
sample(-1),
|
||||
rate(0),
|
||||
period(0),
|
||||
pos(0),
|
||||
out(0),
|
||||
furnaceDAC(0) {}
|
||||
} dac;
|
||||
|
||||
int freq, baseFreq, note, pitch, pitch2;
|
||||
int ins;
|
||||
unsigned char psgMode, autoEnvNum, autoEnvDen, duty;
|
||||
unsigned char autoEnvNum, autoEnvDen, duty;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
||||
int vol, outVol;
|
||||
unsigned char pan;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {}
|
||||
Channel():
|
||||
envelope(Envelope()),
|
||||
psgMode(PSGMode()),
|
||||
dac(DAC()),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
note(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
ins(-1),
|
||||
autoEnvNum(0),
|
||||
autoEnvDen(0),
|
||||
duty(4),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
portaPause(false),
|
||||
inPorta(false),
|
||||
vol(0),
|
||||
outVol(31) {}
|
||||
};
|
||||
Channel chan[3];
|
||||
bool isMuted[3];
|
||||
|
@ -68,6 +134,8 @@ class DivPlatformAY8930: public DivDispatch {
|
|||
unsigned char ayNoiseAnd, ayNoiseOr;
|
||||
bool bank;
|
||||
|
||||
unsigned char sampleBank;
|
||||
|
||||
int delay;
|
||||
|
||||
bool extMode, stereo, clockSel;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define WRITE_STEREO(v) rWrite(0x50,(v))
|
||||
|
||||
#define CHIP_DIVIDER 64
|
||||
#define CHIP_FREQBASE 4000000
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
|
@ -155,7 +156,7 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
WRITE_OUTPUT(i,0);
|
||||
chan[i].samplePos++;
|
||||
} else {
|
||||
WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7);
|
||||
WRITE_OUTPUT(i,CLAMP((s->data8[chan[i].samplePos++]*chan[i].outVol)>>7,-128,127));
|
||||
}
|
||||
|
||||
if (s->isLoopable() && chan[i].samplePos>=s->getLoopEndPosition()) {
|
||||
|
@ -177,7 +178,7 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
if (chan[i].pcm) {
|
||||
chan[i].outVol=((chan[i].vol&127)*MIN(64,chan[i].std.vol.val))>>6;
|
||||
chan[i].outVol=((chan[i].vol&127)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
|
||||
} else {
|
||||
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7;
|
||||
}
|
||||
|
@ -187,11 +188,11 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arp.mode) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].std.arp.val,false);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
|
||||
chan[i].actualNote=chan[i].std.arp.val;
|
||||
} else {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].note+chan[i].std.arp.val,false);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val);
|
||||
chan[i].actualNote=chan[i].note+chan[i].std.arp.val;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
|
@ -199,7 +200,7 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
} else {
|
||||
if (chan[i].std.arp.mode && chan[i].std.arp.finished) {
|
||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].note);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].note,false);
|
||||
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].note);
|
||||
chan[i].actualNote=chan[i].note;
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
@ -231,6 +232,10 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1) {
|
||||
if (chan[i].pcm && chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||
chan[i].sampleAccum=0;
|
||||
chan[i].samplePos=0;
|
||||
}
|
||||
WRITE_LFSR(i, 0);
|
||||
WRITE_OTHER(i, 0);
|
||||
}
|
||||
|
@ -247,7 +252,7 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
off=(double)s->centerRate/8363.0;
|
||||
}
|
||||
}
|
||||
chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1);
|
||||
chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE);
|
||||
} else {
|
||||
if (chan[i].lfsr >= 0) {
|
||||
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
||||
|
@ -277,11 +282,12 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY);
|
||||
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA);
|
||||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:127;
|
||||
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
if (chan[c.chan].pcm) {
|
||||
chan[c.chan].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,c.value,false);
|
||||
chan[c.chan].sampleBaseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleAccum=0;
|
||||
chan[c.chan].samplePos=0;
|
||||
|
@ -294,7 +300,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
|
||||
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
|
@ -374,7 +380,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
int whatAMess=c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0));
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(whatAMess);
|
||||
if (chan[c.chan].pcm) {
|
||||
chan[c.chan].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,whatAMess,false);
|
||||
chan[c.chan].sampleBaseFreq=NOTE_FREQUENCY(whatAMess);
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
|
|
|
@ -48,6 +48,7 @@ class DivPlatformLynx: public DivDispatch {
|
|||
unsigned char pan;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, pcm;
|
||||
signed char vol, outVol;
|
||||
int macroVolMul;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
|
@ -77,7 +78,8 @@ class DivPlatformLynx: public DivDispatch {
|
|||
inPorta(false),
|
||||
pcm(false),
|
||||
vol(127),
|
||||
outVol(127) {}
|
||||
outVol(127),
|
||||
macroVolMul(127) {}
|
||||
};
|
||||
Channel chan[4];
|
||||
DivDispatchOscBuffer* oscBuf[4];
|
||||
|
|
|
@ -102,14 +102,54 @@ void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
}
|
||||
|
||||
void DivPlatformMSM6258::tick(bool sysTick) {
|
||||
// nothing
|
||||
for (int i=0; i<1; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.duty.had) {
|
||||
if (rateSel!=(chan[i].std.duty.val&3)) {
|
||||
rateSel=chan[i].std.duty.val&3;
|
||||
rWrite(12,rateSel);
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
if (chan[i].pan!=(chan[i].std.panL.val&3)) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
rWrite(2,chan[i].pan);
|
||||
}
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
if (clockSel!=(chan[i].std.ex1.val&1)) {
|
||||
clockSel=chan[i].std.ex1.val&1;
|
||||
rWrite(8,clockSel);
|
||||
}
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val && chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
samplePos=0;
|
||||
rWrite(0,1); // turn off
|
||||
if (chan[i].active && !chan[i].keyOff) {
|
||||
if (sample>=0 && sample<parent->song.sampleLen) {
|
||||
rWrite(0,2);
|
||||
} else {
|
||||
sample=-1;
|
||||
}
|
||||
} else {
|
||||
sample=-1;
|
||||
}
|
||||
chan[i].keyOn=false;
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformMSM6258::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (ins->type==DIV_INS_MSM6258 || ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
|
@ -130,8 +170,6 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
rWrite(0,1);
|
||||
rWrite(0,2);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -145,8 +183,8 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
|
|||
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
sample=12*sampleBank+c.value%12;
|
||||
samplePos=0;
|
||||
rWrite(0,1);
|
||||
rWrite(0,2);
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -154,18 +192,12 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
rWrite(0,1); // turn off
|
||||
sample=-1;
|
||||
samplePos=0;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
rWrite(0,1); // turn off
|
||||
sample=-1;
|
||||
samplePos=0;
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
|
|
|
@ -95,7 +95,38 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
}
|
||||
|
||||
void DivPlatformMSM6295::tick(bool sysTick) {
|
||||
// nothing
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=VOL_SCALE_LOG(chan[i].std.vol.val,chan[i].vol,8);
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
if (rateSel!=(chan[i].std.duty.val&1)) {
|
||||
rateSel=chan[i].std.duty.val&1;
|
||||
rWrite(12,!rateSel);
|
||||
}
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val && chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
rWriteDelay(0,(8<<i),60); // turn off
|
||||
if (chan[i].active && !chan[i].keyOff) {
|
||||
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||
rWrite(0,0x80|chan[i].sample); // set phrase
|
||||
rWrite(0,(16<<i)|(8-chan[i].outVol)); // turn on
|
||||
} else {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
} else {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
chan[i].keyOn=false;
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformMSM6295::dispatch(DivCommand c) {
|
||||
|
|
|
@ -46,8 +46,8 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
|||
keyOff(false),
|
||||
furnacePCM(false),
|
||||
hardReset(false),
|
||||
vol(0),
|
||||
outVol(15),
|
||||
vol(8),
|
||||
outVol(8),
|
||||
sample(-1) {}
|
||||
};
|
||||
Channel chan[4];
|
||||
|
|
|
@ -357,7 +357,7 @@ double DivPlatformOPL::NOTE_ADPCMB(int note) {
|
|||
if (adpcmChan<0) return 0;
|
||||
if (chan[adpcmChan].sample>=0 && chan[adpcmChan].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0;
|
||||
return parent->calcBaseFreq((double)chipClock/144,off,note,false);
|
||||
return parent->calcBaseFreq((double)chipClock/((oplType==3)?288:72),off,note,false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -577,7 +577,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
chan[adpcmChan].std.next();
|
||||
|
||||
if (chan[adpcmChan].std.vol.had) {
|
||||
chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(64,chan[adpcmChan].std.vol.val))/64;
|
||||
chan[adpcmChan].outVol=(chan[adpcmChan].vol*MIN(chan[adpcmChan].macroVolMul,chan[adpcmChan].std.vol.val))/chan[adpcmChan].macroVolMul;
|
||||
immWrite(18,chan[adpcmChan].outVol);
|
||||
}
|
||||
|
||||
|
@ -596,16 +596,32 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
chan[adpcmChan].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[adpcmChan].std.phaseReset.had) {
|
||||
if ((chan[adpcmChan].std.phaseReset.val==1) && chan[adpcmChan].active) {
|
||||
chan[adpcmChan].keyOn=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[adpcmChan].freqChanged) {
|
||||
if (chan[adpcmChan].freqChanged || chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) {
|
||||
if (chan[adpcmChan].sample>=0 && chan[adpcmChan].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0;
|
||||
chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/144,off);
|
||||
chan[adpcmChan].freq=parent->calcFreq(chan[adpcmChan].baseFreq,chan[adpcmChan].pitch,false,4,chan[adpcmChan].pitch2,(double)chipClock/((oplType==3)?288:72),off);
|
||||
} else {
|
||||
chan[adpcmChan].freq=0;
|
||||
}
|
||||
immWrite(16,chan[adpcmChan].freq&0xff);
|
||||
immWrite(17,(chan[adpcmChan].freq>>8)&0xff);
|
||||
if (chan[adpcmChan].keyOn || chan[adpcmChan].keyOff) {
|
||||
immWrite(7,0x01); // reset
|
||||
if (chan[adpcmChan].active && chan[adpcmChan].keyOn && !chan[adpcmChan].keyOff) {
|
||||
if (chan[adpcmChan].sample>=0 && chan[adpcmChan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[adpcmChan].sample);
|
||||
immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat
|
||||
}
|
||||
}
|
||||
chan[adpcmChan].keyOn=false;
|
||||
chan[adpcmChan].keyOff=false;
|
||||
}
|
||||
chan[adpcmChan].freqChanged=false;
|
||||
}
|
||||
}
|
||||
|
@ -749,7 +765,8 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan==adpcmChan) { // ADPCM
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
|
@ -765,13 +782,11 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
immWrite(8,0);
|
||||
immWrite(7,0x01); // reset
|
||||
immWrite(9,(s->offB>>2)&0xff);
|
||||
immWrite(10,(s->offB>>10)&0xff);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(11,(end>>2)&0xff);
|
||||
immWrite(12,(end>>10)&0xff);
|
||||
immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||
|
@ -792,25 +807,29 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroInit(NULL);
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||
break;
|
||||
}
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(8,0);
|
||||
immWrite(9,(s->offB>>2)&0xff);
|
||||
immWrite(10,(s->offB>>10)&0xff);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(11,(end>>2)&0xff);
|
||||
immWrite(12,(end>>10)&0xff);
|
||||
int freq=(65536.0*(double)s->rate)/(double)chipRateBase;
|
||||
immWrite(16,freq&0xff);
|
||||
immWrite(17,(freq>>8)&0xff);
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
immWrite(7,0x01); // reset
|
||||
immWrite(9,0);
|
||||
immWrite(10,0);
|
||||
immWrite(11,0);
|
||||
immWrite(12,0);
|
||||
break;
|
||||
}
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(8,0);
|
||||
immWrite(7,0x01); // reset
|
||||
immWrite(9,(s->offB>>2)&0xff);
|
||||
immWrite(10,(s->offB>>10)&0xff);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(11,(end>>2)&0xff);
|
||||
immWrite(12,(end>>10)&0xff);
|
||||
immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat
|
||||
int freq=(65536.0*(double)s->rate)/(double)chipRateBase;
|
||||
immWrite(16,freq&0xff);
|
||||
immWrite(17,(freq>>8)&0xff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -955,19 +974,11 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan==adpcmChan) {
|
||||
immWrite(7,0x01); // reset
|
||||
break;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
if (c.chan==adpcmChan) {
|
||||
immWrite(7,0x01); // reset
|
||||
break;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
|
|
|
@ -44,6 +44,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnacePCM, inPorta, fourOp, hardReset;
|
||||
int vol, outVol;
|
||||
unsigned char pan;
|
||||
int macroVolMul;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
|
@ -70,7 +71,8 @@ class DivPlatformOPL: public DivDispatch {
|
|||
fourOp(false),
|
||||
hardReset(false),
|
||||
vol(0),
|
||||
pan(3) {
|
||||
pan(3),
|
||||
macroVolMul(64) {
|
||||
state.ops=2;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -87,8 +87,15 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
|||
continue;
|
||||
}
|
||||
chWrite(i,0x07,0);
|
||||
chWrite(i,0x04,0xdf);
|
||||
chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3));
|
||||
signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3;
|
||||
chan[i].dacOut=CLAMP(dacData,-16,15);
|
||||
if (!isMuted[i]) {
|
||||
chWrite(i,0x04,0xc0|chan[i].outVol);
|
||||
chWrite(i,0x06,chan[i].dacOut&0x1f);
|
||||
} else {
|
||||
chWrite(i,0x04,0xc0);
|
||||
chWrite(i,0x06,0x10);
|
||||
}
|
||||
chan[i].dacPos++;
|
||||
if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->getLoopEndPosition()) {
|
||||
chan[i].dacPos=s->getLoopStartPosition();
|
||||
|
@ -234,6 +241,15 @@ void DivPlatformPCE::tick(bool sysTick) {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) {
|
||||
if (chan[i].furnaceDac && chan[i].pcm) {
|
||||
if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
|
||||
chan[i].dacPos=0;
|
||||
chan[i].dacPeriod=0;
|
||||
chWrite(i,0x04,0xc0|chan[i].vol);
|
||||
addWrite(0xffff0000+(i<<8),chan[i].dacSample);
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
chan[i].antiClickWavePos=0;
|
||||
chan[i].antiClickPeriodCount=0;
|
||||
}
|
||||
|
@ -279,13 +295,14 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:31;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].pcm=true;
|
||||
} else if (chan[c.chan].furnaceDac) {
|
||||
chan[c.chan].pcm=false;
|
||||
}
|
||||
if (chan[c.chan].pcm) {
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].furnaceDac=true;
|
||||
if (skipRegisterWrites) break;
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
|
@ -295,7 +312,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
break;
|
||||
} else {
|
||||
if (dumpWrites) {
|
||||
chWrite(c.chan,0x04,0xdf);
|
||||
chWrite(c.chan,0x04,0xc0|chan[c.chan].vol);
|
||||
addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
|
||||
}
|
||||
}
|
||||
|
@ -308,6 +325,9 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
}
|
||||
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;
|
||||
} else {
|
||||
chan[c.chan].furnaceDac=false;
|
||||
|
@ -327,7 +347,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
chan[c.chan].dacPeriod=0;
|
||||
chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate;
|
||||
if (dumpWrites) {
|
||||
chWrite(c.chan,0x04,0xdf);
|
||||
chWrite(c.chan,0x04,0xc0|chan[c.chan].vol);
|
||||
addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate);
|
||||
}
|
||||
}
|
||||
|
@ -480,6 +500,10 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
void DivPlatformPCE::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan);
|
||||
if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) {
|
||||
chWrite(ch,0x04,0xc0|chan[ch].outVol);
|
||||
chWrite(ch,0x06,chan[ch].dacOut&0x1f);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformPCE::forceIns() {
|
||||
|
|
|
@ -29,12 +29,13 @@
|
|||
class DivPlatformPCE: public DivDispatch {
|
||||
struct Channel {
|
||||
int freq, baseFreq, pitch, pitch2, note, antiClickPeriodCount, antiClickWavePos;
|
||||
int dacPeriod, dacRate;
|
||||
int dacPeriod, dacRate, dacOut;
|
||||
unsigned int dacPos;
|
||||
int dacSample, ins;
|
||||
unsigned char pan;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac, deferredWaveUpdate;
|
||||
signed char vol, outVol, wave;
|
||||
int macroVolMul;
|
||||
DivMacroInt std;
|
||||
DivWaveSynth ws;
|
||||
void macroInit(DivInstrument* which) {
|
||||
|
@ -51,6 +52,7 @@ class DivPlatformPCE: public DivDispatch {
|
|||
antiClickWavePos(0),
|
||||
dacPeriod(0),
|
||||
dacRate(0),
|
||||
dacOut(0),
|
||||
dacPos(0),
|
||||
dacSample(-1),
|
||||
ins(-1),
|
||||
|
@ -67,7 +69,8 @@ class DivPlatformPCE: public DivDispatch {
|
|||
deferredWaveUpdate(false),
|
||||
vol(31),
|
||||
outVol(31),
|
||||
wave(-1) {}
|
||||
wave(-1),
|
||||
macroVolMul(31) {}
|
||||
};
|
||||
Channel chan[6];
|
||||
DivDispatchOscBuffer* oscBuf[6];
|
||||
|
|
|
@ -36,26 +36,71 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
continue;
|
||||
}
|
||||
if (chan.useWave || (chan.sample>=0 && chan.sample<parent->song.sampleLen)) {
|
||||
chan.audPos+=chan.freq>>16;
|
||||
chan.audPos+=((!chan.useWave) && chan.audDir)?-(chan.freq>>16):(chan.freq>>16);
|
||||
chan.audSub+=(chan.freq&0xffff);
|
||||
if (chan.audSub>=0x10000) {
|
||||
chan.audSub-=0x10000;
|
||||
chan.audPos+=1;
|
||||
chan.audPos+=((!chan.useWave) && chan.audDir)?-1:1;
|
||||
}
|
||||
if (chan.useWave) {
|
||||
if (chan.audPos>=(unsigned int)(chan.audLen<<1)) {
|
||||
chan.audPos=0;
|
||||
if (chan.audPos>=(int)chan.audLen) {
|
||||
chan.audPos%=chan.audLen;
|
||||
chan.audDir=false;
|
||||
}
|
||||
output=(chan.ws.output[chan.audPos]^0x80)<<8;
|
||||
} else {
|
||||
DivSample* s=parent->getSample(chan.sample);
|
||||
if (s->getEndPosition()>0) {
|
||||
if (s->isLoopable() && chan.audPos>=(unsigned int)s->getLoopEndPosition()) {
|
||||
chan.audPos=s->getLoopStartPosition();
|
||||
} else if (chan.audPos>=(unsigned int)s->getEndPosition()) {
|
||||
chan.sample=-1;
|
||||
if (chan.audDir) {
|
||||
if (s->isLoopable()) {
|
||||
switch (s->loopMode) {
|
||||
case DIV_SAMPLE_LOOP_FORWARD:
|
||||
case DIV_SAMPLE_LOOP_PINGPONG:
|
||||
if (chan.audPos<s->getLoopStartPosition()) {
|
||||
chan.audPos=s->getLoopStartPosition()+(s->getLoopStartPosition()-chan.audPos);
|
||||
chan.audDir=false;
|
||||
}
|
||||
break;
|
||||
case DIV_SAMPLE_LOOP_BACKWARD:
|
||||
if (chan.audPos<s->getLoopStartPosition()) {
|
||||
chan.audPos=s->getLoopEndPosition()-1-(s->getLoopStartPosition()-chan.audPos);
|
||||
chan.audDir=true;
|
||||
}
|
||||
default:
|
||||
if (chan.audPos<0) {
|
||||
chan.sample=-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (chan.audPos>=s->getEndPosition()) {
|
||||
chan.sample=-1;
|
||||
}
|
||||
} else {
|
||||
if (s->isLoopable()) {
|
||||
switch (s->loopMode) {
|
||||
case DIV_SAMPLE_LOOP_FORWARD:
|
||||
if (chan.audPos>=s->getLoopEndPosition()) {
|
||||
chan.audPos=(chan.audPos+s->getLoopStartPosition())-s->getLoopEndPosition();
|
||||
chan.audDir=false;
|
||||
}
|
||||
break;
|
||||
case DIV_SAMPLE_LOOP_BACKWARD:
|
||||
case DIV_SAMPLE_LOOP_PINGPONG:
|
||||
if (chan.audPos>=s->getLoopEndPosition()) {
|
||||
chan.audPos=s->getLoopEndPosition()-1-(s->getLoopEndPosition()-1-chan.audPos);
|
||||
chan.audDir=true;
|
||||
}
|
||||
default:
|
||||
if (chan.audPos>=s->getEndPosition()) {
|
||||
chan.sample=-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (chan.audPos>=s->getEndPosition()) {
|
||||
chan.sample=-1;
|
||||
}
|
||||
}
|
||||
if (chan.audPos<(unsigned int)s->getEndPosition()) {
|
||||
if (chan.audPos>=0 && chan.audPos<s->getEndPosition()) {
|
||||
output=s->data16[chan.audPos];
|
||||
}
|
||||
} else {
|
||||
|
@ -125,6 +170,7 @@ void DivPlatformPCMDAC::tick(bool sysTick) {
|
|||
}
|
||||
if (chan.std.phaseReset.had) {
|
||||
if (chan.std.phaseReset.val==1) {
|
||||
chan.audDir=false;
|
||||
chan.audPos=0;
|
||||
}
|
||||
}
|
||||
|
@ -156,11 +202,11 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
|||
DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_AMIGA);
|
||||
if (ins->amiga.useWave) {
|
||||
chan.useWave=true;
|
||||
chan.audLen=(ins->amiga.waveLen+1)>>1;
|
||||
chan.audLen=ins->amiga.waveLen;
|
||||
if (chan.insChanged) {
|
||||
if (chan.wave<0) {
|
||||
chan.wave=0;
|
||||
chan.ws.setWidth(chan.audLen<<1);
|
||||
chan.ws.setWidth(chan.audLen);
|
||||
chan.ws.changeWave1(chan.wave);
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +223,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
|||
if (chan.setPos) {
|
||||
chan.setPos=false;
|
||||
} else {
|
||||
chan.audDir=false;
|
||||
chan.audPos=0;
|
||||
}
|
||||
chan.audSub=0;
|
||||
|
@ -191,7 +238,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
|||
chan.envVol=64;
|
||||
}
|
||||
if (chan.useWave) {
|
||||
chan.ws.init(ins,chan.audLen<<1,255,chan.insChanged);
|
||||
chan.ws.init(ins,chan.audLen,255,chan.insChanged);
|
||||
}
|
||||
chan.insChanged=false;
|
||||
break;
|
||||
|
@ -298,6 +345,7 @@ void DivPlatformPCMDAC::muteChannel(int ch, bool mute) {
|
|||
void DivPlatformPCMDAC::forceIns() {
|
||||
chan.insChanged=true;
|
||||
chan.freqChanged=true;
|
||||
chan.audDir=false;
|
||||
chan.audPos=0;
|
||||
chan.sample=-1;
|
||||
}
|
||||
|
|
|
@ -28,9 +28,10 @@
|
|||
class DivPlatformPCMDAC: public DivDispatch {
|
||||
struct Channel {
|
||||
int freq, baseFreq, pitch, pitch2;
|
||||
bool audDir;
|
||||
unsigned int audLoc;
|
||||
unsigned short audLen;
|
||||
unsigned int audPos;
|
||||
int audPos;
|
||||
int audSub;
|
||||
int sample, wave, ins;
|
||||
int note;
|
||||
|
@ -48,6 +49,7 @@ class DivPlatformPCMDAC: public DivDispatch {
|
|||
baseFreq(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
audDir(false),
|
||||
audLoc(0),
|
||||
audLen(0),
|
||||
audPos(0),
|
||||
|
|
|
@ -286,10 +286,16 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6;
|
||||
if (chan[i].isNewQSound) {
|
||||
chan[i].outVol=((chan[i].vol&0xff)*MIN(16383,chan[i].std.vol.val))/16383;
|
||||
chan[i].resVol=((chan[i].vol&0xff)*MIN(16383,chan[i].std.vol.val))/255;
|
||||
} else {
|
||||
chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6;
|
||||
chan[i].resVol=chan[i].outVol<<4;
|
||||
}
|
||||
// Check if enabled and write volume
|
||||
if (chan[i].active) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4);
|
||||
rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol);
|
||||
}
|
||||
}
|
||||
uint16_t qsound_bank = 0;
|
||||
|
@ -329,6 +335,16 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
chan[i].echo=CLAMP(chan[i].std.duty.val,0,32767);
|
||||
immWrite(Q1_ECHO+i,chan[i].echo&0x7fff);
|
||||
}
|
||||
if (chan[i].std.ex1.had) {
|
||||
immWrite(Q1_ECHO_FEEDBACK,chan[i].std.ex1.val&0x3fff);
|
||||
}
|
||||
if (chan[i].std.ex2.had) {
|
||||
immWrite(Q1_ECHO_LENGTH,0xfff-(2725-CLAMP(chan[i].std.ex2.val&0xfff,0,2725)));
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
chan[i].pitch2+=chan[i].std.pitch.val;
|
||||
|
@ -347,6 +363,11 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||
immWrite(Q1_PAN+i,chan[i].panning+0x110+(chan[i].surround?0:0x30));
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1 && chan[i].active && (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen)) {
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
|
||||
double off=1.0;
|
||||
|
@ -366,19 +387,24 @@ void DivPlatformQSound::tick(bool sysTick) {
|
|||
rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop);
|
||||
rWrite(q1_reg_map[Q1V_START][i], qsound_addr);
|
||||
rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000);
|
||||
logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop);
|
||||
//logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop);
|
||||
// Write sample address. Enable volume
|
||||
if (!chan[i].std.vol.had) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4);
|
||||
if (chan[i].isNewQSound) {
|
||||
chan[i].resVol=(chan[i].vol*16383)/255;
|
||||
} else {
|
||||
chan[i].resVol=chan[i].vol<<4;
|
||||
}
|
||||
rWrite(q1_reg_map[Q1V_VOL][i],chan[i].resVol);
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
// Disable volume
|
||||
rWrite(q1_reg_map[Q1V_VOL][i], 0);
|
||||
rWrite(q1_reg_map[Q1V_FREQ][i], 0);
|
||||
rWrite(q1_reg_map[Q1V_VOL][i],0);
|
||||
rWrite(q1_reg_map[Q1V_FREQ][i],0);
|
||||
} else if (chan[i].active) {
|
||||
//logV("ch %d frequency set to %04x, off=%f, note=%d, %04x!",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note));
|
||||
rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq);
|
||||
rWrite(q1_reg_map[Q1V_FREQ][i],chan[i].freq);
|
||||
}
|
||||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
|
@ -391,6 +417,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
chan[c.chan].isNewQSound=(ins->type==DIV_INS_QSOUND);
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(c.value);
|
||||
|
@ -407,6 +434,11 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
if (chan[c.chan].isNewQSound) {
|
||||
chan[c.chan].resVol=(chan[c.chan].outVol*16383)/255;
|
||||
} else {
|
||||
chan[c.chan].resVol=chan[c.chan].outVol<<4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -431,8 +463,13 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
// Check if enabled and write volume
|
||||
chan[c.chan].outVol=c.value;
|
||||
if (chan[c.chan].active && c.chan < 16) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][c.chan], chan[c.chan].outVol << 4);
|
||||
if (chan[c.chan].isNewQSound) {
|
||||
chan[c.chan].resVol=(chan[c.chan].outVol*16383)/255;
|
||||
} else {
|
||||
chan[c.chan].resVol=chan[c.chan].outVol<<4;
|
||||
}
|
||||
if (chan[c.chan].active && c.chan<16) {
|
||||
rWrite(q1_reg_map[Q1V_VOL][c.chan],chan[c.chan].resVol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -448,7 +485,8 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
immWrite(Q1_PAN+c.chan,chan[c.chan].panning+0x110+(chan[c.chan].surround?0:0x30));
|
||||
break;
|
||||
case DIV_CMD_QSOUND_ECHO_LEVEL:
|
||||
immWrite(Q1_ECHO+c.chan, c.value << 7);
|
||||
chan[c.chan].echo=c.value<<7;
|
||||
immWrite(Q1_ECHO+c.chan,chan[c.chan].echo&0x7fff);
|
||||
break;
|
||||
case DIV_CMD_QSOUND_ECHO_FEEDBACK:
|
||||
immWrite(Q1_ECHO_FEEDBACK, c.value << 6);
|
||||
|
|
|
@ -28,13 +28,12 @@
|
|||
class DivPlatformQSound: public DivDispatch {
|
||||
struct Channel {
|
||||
int freq, baseFreq, pitch, pitch2;
|
||||
unsigned short audLen;
|
||||
unsigned int audPos;
|
||||
int sample, wave, ins;
|
||||
int note;
|
||||
int panning;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround;
|
||||
int vol, outVol;
|
||||
int echo;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround, isNewQSound;
|
||||
int vol, outVol, resVol;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
|
@ -45,12 +44,11 @@ class DivPlatformQSound: public DivDispatch {
|
|||
baseFreq(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
audLen(0),
|
||||
audPos(0),
|
||||
sample(-1),
|
||||
ins(-1),
|
||||
note(0),
|
||||
panning(0x10),
|
||||
echo(0),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
|
@ -59,8 +57,10 @@ class DivPlatformQSound: public DivDispatch {
|
|||
inPorta(false),
|
||||
useWave(false),
|
||||
surround(true),
|
||||
isNewQSound(false),
|
||||
vol(255),
|
||||
outVol(255) {}
|
||||
outVol(255),
|
||||
resVol(4096) {}
|
||||
};
|
||||
Channel chan[19];
|
||||
DivDispatchOscBuffer* oscBuf[19];
|
||||
|
|
|
@ -83,7 +83,7 @@ void DivPlatformRF5C68::tick(bool sysTick) {
|
|||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6;
|
||||
chan[i].outVol=((chan[i].vol&0xff)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
|
||||
chWrite(i,0,chan[i].outVol);
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
|
@ -120,7 +120,13 @@ void DivPlatformRF5C68::tick(bool sysTick) {
|
|||
chan[i].panning|=(chan[i].std.panR.val&15)<<4;
|
||||
}
|
||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||
chWrite(i,0x05,isMuted[i]?0:chan[i].panning);
|
||||
chWrite(i,1,isMuted[i]?0:chan[i].panning);
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1 && chan[i].active) {
|
||||
chan[i].audPos=0;
|
||||
chan[i].setPos=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].setPos) {
|
||||
// force keyon
|
||||
|
@ -175,6 +181,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255;
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
|
|
|
@ -34,6 +34,7 @@ class DivPlatformRF5C68: public DivDispatch {
|
|||
int panning;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos;
|
||||
int vol, outVol;
|
||||
int macroVolMul;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
|
@ -57,7 +58,8 @@ class DivPlatformRF5C68: public DivDispatch {
|
|||
inPorta(false),
|
||||
setPos(false),
|
||||
vol(255),
|
||||
outVol(255) {}
|
||||
outVol(255),
|
||||
macroVolMul(64) {}
|
||||
};
|
||||
Channel chan[8];
|
||||
DivDispatchOscBuffer* oscBuf[8];
|
||||
|
|
|
@ -83,9 +83,9 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
|||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
|
||||
if (parent->song.newSegaPCM) {
|
||||
if (chan[i].isNewSegaPCM) {
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(64,chan[i].std.vol.val))>>6;
|
||||
chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
|
||||
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
|
||||
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
|
||||
if (dumpWrites) {
|
||||
|
@ -112,7 +112,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
if (chan[i].std.panL.had) {
|
||||
if (parent->song.newSegaPCM) {
|
||||
if (chan[i].isNewSegaPCM) {
|
||||
chan[i].chPanL=chan[i].std.panL.val&127;
|
||||
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
|
||||
} else {
|
||||
|
@ -124,7 +124,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
if (chan[i].std.panR.had) {
|
||||
if (parent->song.newSegaPCM) {
|
||||
if (chan[i].isNewSegaPCM) {
|
||||
chan[i].chPanR=chan[i].std.panR.val&127;
|
||||
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
|
||||
} else {
|
||||
|
@ -144,13 +144,14 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
|||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
/*if (chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].keyOff=false;
|
||||
}*/
|
||||
}
|
||||
|
||||
for (int i=0; i<16; i++) {
|
||||
if (chan[i].freqChanged) {
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1 && chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64;
|
||||
if (chan[i].furnacePCM) {
|
||||
double off=1.0;
|
||||
|
@ -164,6 +165,56 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
chan[i].freqChanged=false;
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
if (chan[i].keyOn && !chan[i].keyOff) {
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10086+(i<<3),3);
|
||||
}
|
||||
chan[i].pcm.pos=0;
|
||||
if (chan[i].furnacePCM) {
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->getSample(chan[i].pcm.sample);
|
||||
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
if (actualLength>0xfeff) actualLength=0xfeff;
|
||||
addWrite(0x10086+(i<<3),3+((s->offSegaPCM>>16)<<3));
|
||||
addWrite(0x10084+(i<<3),(s->offSegaPCM)&0xff);
|
||||
addWrite(0x10085+(i<<3),(s->offSegaPCM>>8)&0xff);
|
||||
addWrite(0x10006+(i<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8));
|
||||
if (loopStart<0 || loopStart>=actualLength) {
|
||||
addWrite(0x10086+(i<<3),2+((s->offSegaPCM>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(i<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(i<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(i<<3),((s->offSegaPCM>>16)<<3));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->getSample(chan[i].pcm.sample);
|
||||
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
if (actualLength>65536) actualLength=65536;
|
||||
addWrite(0x10086+(i<<3),3+((s->offSegaPCM>>16)<<3));
|
||||
addWrite(0x10084+(i<<3),(s->offSegaPCM)&0xff);
|
||||
addWrite(0x10085+(i<<3),(s->offSegaPCM>>8)&0xff);
|
||||
addWrite(0x10006+(i<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8));
|
||||
if (loopStart<0 || loopStart>=actualLength) {
|
||||
addWrite(0x10086+(i<<3),2+((s->offSegaPCM>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(i<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(i<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(i<<3),((s->offSegaPCM>>16)<<3));
|
||||
}
|
||||
addWrite(0x10007+(i<<3),chan[i].pcm.freq);
|
||||
}
|
||||
}
|
||||
}
|
||||
chan[i].keyOn=false;
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +228,9 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SEGAPCM) {
|
||||
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:127;
|
||||
chan[c.chan].isNewSegaPCM=(ins->type==DIV_INS_SEGAPCM || parent->song.newSegaPCM);
|
||||
chan[c.chan].pcm.sample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].pcm.sample=-1;
|
||||
|
@ -190,7 +243,6 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
chan[c.chan].pcm.pos=0;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=(c.value<<6);
|
||||
|
@ -198,24 +250,8 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].furnacePCM=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
|
||||
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
if (actualLength>0xfeff) actualLength=0xfeff;
|
||||
addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
|
||||
addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff);
|
||||
addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff);
|
||||
addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8));
|
||||
if (loopStart<0 || loopStart>=actualLength) {
|
||||
addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(c.chan<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3));
|
||||
}
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
chan[c.chan].macroInit(NULL);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
@ -229,28 +265,10 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
chan[c.chan].pcm.pos=0;
|
||||
chan[c.chan].pcm.freq=MIN(255,(parent->getSample(chan[c.chan].pcm.sample)->rate*255)/31250);
|
||||
chan[c.chan].furnacePCM=false;
|
||||
if (dumpWrites) { // Sega PCM writes
|
||||
DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
|
||||
int loopStart=s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||
int actualLength=(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||
if (actualLength>65536) actualLength=65536;
|
||||
addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
|
||||
addWrite(0x10084+(c.chan<<3),(s->offSegaPCM)&0xff);
|
||||
addWrite(0x10085+(c.chan<<3),(s->offSegaPCM>>8)&0xff);
|
||||
addWrite(0x10006+(c.chan<<3),MIN(255,((s->offSegaPCM&0xffff)+actualLength-1)>>8));
|
||||
if (loopStart<0 || loopStart>=actualLength) {
|
||||
addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3));
|
||||
} else {
|
||||
int loopPos=(s->offSegaPCM&0xffff)+loopStart+s->loopOffP;
|
||||
addWrite(0x10004+(c.chan<<3),loopPos&0xff);
|
||||
addWrite(0x10005+(c.chan<<3),(loopPos>>8)&0xff);
|
||||
addWrite(0x10086+(c.chan<<3),((s->offSegaPCM>>16)<<3));
|
||||
}
|
||||
addWrite(0x10007+(c.chan<<3),chan[c.chan].pcm.freq);
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -278,7 +296,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (parent->song.newSegaPCM) {
|
||||
if (chan[c.chan].isNewSegaPCM) {
|
||||
chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127;
|
||||
chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127;
|
||||
} else {
|
||||
|
@ -302,7 +320,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (parent->song.newSegaPCM) {
|
||||
if (chan[c.chan].isNewSegaPCM) {
|
||||
chan[c.chan].chPanL=c.value>>1;
|
||||
chan[c.chan].chPanR=c.value2>>1;
|
||||
chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127;
|
||||
|
|
|
@ -28,13 +28,12 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
protected:
|
||||
struct Channel {
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, pitch2, note, ins;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, isNewSegaPCM;
|
||||
int vol, outVol;
|
||||
unsigned char chVolL, chVolR;
|
||||
unsigned char chPanL, chPanR;
|
||||
int macroVolMul;
|
||||
|
||||
struct PCMChannel {
|
||||
int sample;
|
||||
|
@ -48,8 +47,6 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
pitch2=0;
|
||||
}
|
||||
Channel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
|
@ -64,12 +61,15 @@ class DivPlatformSegaPCM: public DivDispatch {
|
|||
inPorta(false),
|
||||
portaPause(false),
|
||||
furnacePCM(false),
|
||||
isNewSegaPCM(false),
|
||||
vol(0),
|
||||
outVol(0),
|
||||
chVolL(127),
|
||||
chVolR(127),
|
||||
chPanL(127),
|
||||
chPanR(127) {}
|
||||
chPanR(127),
|
||||
macroVolMul(64),
|
||||
pcm(PCMChannel()) {}
|
||||
};
|
||||
Channel chan[16];
|
||||
DivDispatchOscBuffer* oscBuf[16];
|
||||
|
|
|
@ -256,12 +256,12 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SU);
|
||||
if (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->su.useSample)) {
|
||||
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample);
|
||||
if (chan[c.chan].pcm && !(ins->type==DIV_INS_AMIGA || ins->amiga.useSample)) {
|
||||
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample);
|
||||
writeControl(c.chan);
|
||||
writeControlUpper(c.chan);
|
||||
}
|
||||
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->su.useSample);
|
||||
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
|
|
@ -251,7 +251,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SWAN);
|
||||
if (c.chan==1) {
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
pcm=true;
|
||||
} else if (furnaceDac) {
|
||||
pcm=false;
|
||||
|
@ -260,7 +260,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
if (skipRegisterWrites) break;
|
||||
dacPos=0;
|
||||
dacPeriod=0;
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
dacSample=ins->amiga.getSample(c.value);
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
dacSample=-1;
|
||||
|
|
|
@ -193,6 +193,25 @@ void DivPlatformVRC6::tick(bool sysTick) {
|
|||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val && chan[i].active) {
|
||||
if ((i!=2) && (!chan[i].pcm)) {
|
||||
if (dumpWrites) addWrite(0xffff0002+(i<<8),0);
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_VRC6);
|
||||
chan[i].dacSample=ins->amiga.getSample(chan[i].note);
|
||||
if (chan[i].dacSample<0 || chan[i].dacSample>=parent->song.sampleLen) {
|
||||
if (dumpWrites) {
|
||||
chWrite(i,2,0x80);
|
||||
chWrite(i,0,isMuted[i]?0:0x80);
|
||||
addWrite(0xffff0000+(i<<8),chan[i].dacSample);
|
||||
}
|
||||
chan[i].dacPos=0;
|
||||
chan[i].dacPeriod=0;
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
if (i==2) { // sawtooth
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,14)-1;
|
||||
|
@ -233,14 +252,14 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_ON:
|
||||
if (c.chan!=2) { // pulse wave
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VRC6);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].pcm=true;
|
||||
} else if (chan[c.chan].furnaceDac) {
|
||||
chan[c.chan].pcm=false;
|
||||
}
|
||||
if (chan[c.chan].pcm) {
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#include <math.h>
|
||||
|
||||
//#define rWrite(a,v) pendingWrites[a]=v;
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) { x1_010->ram_w(a,v); if (dumpWrites) { addWrite(a,v); } }
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) { x1_010.ram_w(a,v); if (dumpWrites) { addWrite(a,v); } }
|
||||
|
||||
#define chRead(c,a) x1_010->ram_r((c<<3)|(a&7))
|
||||
#define chRead(c,a) x1_010.ram_r((c<<3)|(a&7))
|
||||
#define chWrite(c,a,v) rWrite((c<<3)|(a&7),v)
|
||||
#define waveWrite(c,a,v) rWrite(0x1000|(chan[c].waveBank<<11)|(c<<7)|(a&0x7f),(v-128)&0xff)
|
||||
#define envFill(c,a) rWrite(0x800|(c<<7)|(a&0x7f),(chan[c].lvol<<4)|chan[c].rvol)
|
||||
|
@ -240,10 +240,10 @@ const char* DivPlatformX1_010::getEffectName(unsigned char effect) {
|
|||
|
||||
void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
x1_010->tick();
|
||||
x1_010.tick();
|
||||
|
||||
signed int tempL=x1_010->output(0);
|
||||
signed int tempR=x1_010->output(1);
|
||||
signed int tempL=x1_010.output(0);
|
||||
signed int tempR=x1_010.output(1);
|
||||
|
||||
if (tempL<-32768) tempL=-32768;
|
||||
if (tempL>32767) tempL=32767;
|
||||
|
@ -255,11 +255,23 @@ void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
bufR[h]=stereo?tempR:bufL[h];
|
||||
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=x1_010->chan_out(i);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=x1_010.chan_out(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8 DivPlatformX1_010::read_byte(u32 address) {
|
||||
if ((sampleMem!=NULL) && (address<getSampleMemCapacity())) {
|
||||
if (isBanked) {
|
||||
address=((bankSlot[(address>>17)&7]<<17)|(address&0x1ffff))&0xffffff;
|
||||
} else {
|
||||
address&=0xfffff;
|
||||
}
|
||||
return sampleMem[address];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double DivPlatformX1_010::NoteX1_010(int ch, int note) {
|
||||
if (chan[ch].pcm) { // PCM note
|
||||
double off=8192.0;
|
||||
|
@ -345,7 +357,7 @@ void DivPlatformX1_010::tick(bool sysTick) {
|
|||
for (int i=0; i<16; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
signed char macroVol=((chan[i].vol&15)*MIN(chan[i].furnacePCM?64:15,chan[i].std.vol.val))/(chan[i].furnacePCM?64:15);
|
||||
signed char macroVol=((chan[i].vol&15)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/(chan[i].macroVolMul);
|
||||
if ((!isMuted[i]) && (macroVol!=chan[i].outVol)) {
|
||||
chan[i].outVol=macroVol;
|
||||
chan[i].envChanged=true;
|
||||
|
@ -475,6 +487,12 @@ void DivPlatformX1_010::tick(bool sysTick) {
|
|||
if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val && chan[i].active && chan[i].pcm) {
|
||||
chWrite(i,0,0);
|
||||
refreshControl(i);
|
||||
}
|
||||
}
|
||||
if (chan[i].active) {
|
||||
if (chan[i].ws.tick()) {
|
||||
updateWave(i);
|
||||
|
@ -549,8 +567,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_ON: {
|
||||
chWrite(c.chan,0,0); // reset previous note
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_X1_010);
|
||||
if ((ins->type==DIV_INS_AMIGA) || chan[c.chan].pcm) {
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:15;
|
||||
if ((ins->type==DIV_INS_AMIGA || ins->amiga.useSample) || chan[c.chan].pcm) {
|
||||
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
|
@ -562,9 +581,18 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
chWrite(c.chan,4,(s->offX1_010>>12)&0xff);
|
||||
int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded
|
||||
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
|
||||
if (isBanked) {
|
||||
chan[c.chan].bankSlot=ins->x1_010.bankSlot;
|
||||
bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17;
|
||||
unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(s->offX1_010&0x1ffff);
|
||||
chWrite(c.chan,4,(bankedOffs>>12)&0xff);
|
||||
int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded
|
||||
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
|
||||
} else {
|
||||
chWrite(c.chan,4,(s->offX1_010>>12)&0xff);
|
||||
int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded
|
||||
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note);
|
||||
|
@ -594,9 +622,17 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
chWrite(c.chan,4,(s->offX1_010>>12)&0xff);
|
||||
int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded
|
||||
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
|
||||
if (isBanked) {
|
||||
bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17;
|
||||
unsigned int bankedOffs=(chan[c.chan].bankSlot<<17)|(s->offX1_010&0x1ffff);
|
||||
chWrite(c.chan,4,(bankedOffs>>12)&0xff);
|
||||
int end=(bankedOffs+MIN(s->length8,0x1ffff)+0xfff)&~0xfff; // padded
|
||||
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
|
||||
} else {
|
||||
chWrite(c.chan,4,(s->offX1_010>>12)&0xff);
|
||||
int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded
|
||||
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
|
||||
}
|
||||
chan[c.chan].baseFreq=(((unsigned int)s->rate)<<4)/(chipClock/512);
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
|
@ -813,6 +849,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
chan[c.chan].autoEnvDen=c.value&15;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
case DIV_CMD_X1_010_SAMPLE_BANK_SLOT:
|
||||
chan[c.chan].bankSlot=c.value&7;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 15;
|
||||
break;
|
||||
|
@ -853,7 +892,7 @@ DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) {
|
|||
|
||||
unsigned char* DivPlatformX1_010::getRegisterPool() {
|
||||
for (int i=0; i<0x2000; i++) {
|
||||
regPool[i]=x1_010->ram_r(i);
|
||||
regPool[i]=x1_010.ram_r(i);
|
||||
}
|
||||
return regPool;
|
||||
}
|
||||
|
@ -871,12 +910,16 @@ void DivPlatformX1_010::reset() {
|
|||
chan[i].ws.setEngine(parent);
|
||||
chan[i].ws.init(NULL,128,255,false);
|
||||
}
|
||||
x1_010->reset();
|
||||
x1_010.reset();
|
||||
sampleBank=0;
|
||||
// set per-channel initial panning
|
||||
for (int i=0; i<16; i++) {
|
||||
chWrite(i,0,0);
|
||||
}
|
||||
// set initial bank
|
||||
for (int b=0; b<8; b++) {
|
||||
bankSlot[b]=b;
|
||||
}
|
||||
}
|
||||
|
||||
bool DivPlatformX1_010::isStereo() {
|
||||
|
@ -931,15 +974,15 @@ void DivPlatformX1_010::poke(std::vector<DivRegWrite>& wlist) {
|
|||
}
|
||||
|
||||
const void* DivPlatformX1_010::getSampleMem(int index) {
|
||||
return index == 0 ? sampleMem : 0;
|
||||
return index >= 0 ? sampleMem : 0;
|
||||
}
|
||||
|
||||
size_t DivPlatformX1_010::getSampleMemCapacity(int index) {
|
||||
return index == 0 ? 1048576 : 0;
|
||||
return index == 0 ? (isBanked?16777216:1048576):0;
|
||||
}
|
||||
|
||||
size_t DivPlatformX1_010::getSampleMemUsage(int index) {
|
||||
return index == 0 ? sampleMemLen : 0;
|
||||
return index >= 0 ? sampleMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformX1_010::renderSamples() {
|
||||
|
@ -949,12 +992,14 @@ void DivPlatformX1_010::renderSamples() {
|
|||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
int paddedLen=(s->length8+4095)&(~0xfff);
|
||||
if (isBanked) {
|
||||
// fit sample bank size to 128KB for Seta 2 external bankswitching logic (not emulated yet!)
|
||||
if (paddedLen>131072) {
|
||||
paddedLen=131072;
|
||||
}
|
||||
if ((memPos&0xfe0000)!=((memPos+paddedLen)&0xfe0000)) {
|
||||
memPos=(memPos+0x1ffff)&0xfe0000;
|
||||
if (paddedLen>131072) {
|
||||
paddedLen=131072;
|
||||
}
|
||||
if ((memPos&0xfe0000)!=((memPos+paddedLen)&0xfe0000)) {
|
||||
memPos=(memPos+0x1ffff)&0xfe0000;
|
||||
}
|
||||
}
|
||||
if (memPos>=getSampleMemCapacity()) {
|
||||
logW("out of X1-010 memory for sample %d!",i);
|
||||
|
@ -972,6 +1017,10 @@ void DivPlatformX1_010::renderSamples() {
|
|||
sampleMemLen=memPos+256;
|
||||
}
|
||||
|
||||
void DivPlatformX1_010::setBanked(bool banked) {
|
||||
isBanked=banked;
|
||||
}
|
||||
|
||||
int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
|
@ -984,9 +1033,7 @@ int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned in
|
|||
setFlags(flags);
|
||||
sampleMem=new unsigned char[getSampleMemCapacity()];
|
||||
sampleMemLen=0;
|
||||
intf.memory=sampleMem;
|
||||
x1_010=new x1_010_core(intf);
|
||||
x1_010->reset();
|
||||
x1_010.reset();
|
||||
reset();
|
||||
return 16;
|
||||
}
|
||||
|
@ -995,7 +1042,6 @@ void DivPlatformX1_010::quit() {
|
|||
for (int i=0; i<16; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
delete x1_010;
|
||||
delete[] sampleMem;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,18 +26,7 @@
|
|||
#include "../waveSynth.h"
|
||||
#include "sound/x1_010/x1_010.hpp"
|
||||
|
||||
class DivX1_010Interface: public x1_010_mem_intf {
|
||||
public:
|
||||
unsigned char* memory;
|
||||
int sampleBank;
|
||||
virtual u8 read_byte(u32 address) override {
|
||||
if (memory==NULL) return 0;
|
||||
return memory[address & 0xfffff];
|
||||
}
|
||||
DivX1_010Interface(): memory(NULL), sampleBank(0) {}
|
||||
};
|
||||
|
||||
class DivPlatformX1_010: public DivDispatch {
|
||||
class DivPlatformX1_010: public DivDispatch, public x1_010_mem_intf {
|
||||
struct Channel {
|
||||
struct Envelope {
|
||||
struct EnvFlag {
|
||||
|
@ -84,7 +73,9 @@ class DivPlatformX1_010: public DivDispatch {
|
|||
unsigned char pan, autoEnvNum, autoEnvDen;
|
||||
bool active, insChanged, envChanged, freqChanged, keyOn, keyOff, inPorta, furnacePCM, pcm;
|
||||
int vol, outVol, lvol, rvol;
|
||||
int macroVolMul;
|
||||
unsigned char waveBank;
|
||||
unsigned int bankSlot;
|
||||
Envelope env;
|
||||
DivMacroInt std;
|
||||
DivWaveSynth ws;
|
||||
|
@ -109,7 +100,9 @@ class DivPlatformX1_010: public DivDispatch {
|
|||
pan(255), autoEnvNum(0), autoEnvDen(0),
|
||||
active(false), insChanged(true), envChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), furnacePCM(false), pcm(false),
|
||||
vol(15), outVol(15), lvol(15), rvol(15),
|
||||
waveBank(0) {}
|
||||
macroVolMul(15),
|
||||
waveBank(0),
|
||||
bankSlot(0) {}
|
||||
};
|
||||
Channel chan[16];
|
||||
DivDispatchOscBuffer* oscBuf[16];
|
||||
|
@ -118,14 +111,18 @@ class DivPlatformX1_010: public DivDispatch {
|
|||
unsigned char* sampleMem;
|
||||
size_t sampleMemLen;
|
||||
unsigned char sampleBank;
|
||||
DivX1_010Interface intf;
|
||||
x1_010_core* x1_010;
|
||||
x1_010_core x1_010;
|
||||
|
||||
bool isBanked=false;
|
||||
unsigned int bankSlot[8];
|
||||
|
||||
unsigned char regPool[0x2000];
|
||||
double NoteX1_010(int ch, int note);
|
||||
void updateWave(int ch);
|
||||
void updateEnvelope(int ch);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
u8 read_byte(u32 address);
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
|
@ -150,8 +147,13 @@ class DivPlatformX1_010: public DivDispatch {
|
|||
void renderSamples();
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
void setBanked(bool banked);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformX1_010():
|
||||
DivDispatch(),
|
||||
x1_010_mem_intf(),
|
||||
x1_010(*this) {}
|
||||
~DivPlatformX1_010();
|
||||
};
|
||||
|
||||
|
|
|
@ -647,12 +647,46 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
|||
chan[i].keyOff=false;
|
||||
}
|
||||
}
|
||||
// RSS
|
||||
for (int i=9; i<15; i++) {
|
||||
if (chan[i].furnacePCM) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
if (globalRSSVolume!=(chan[i].std.duty.val&0x3f)) {
|
||||
globalRSSVolume=chan[i].std.duty.val&0x3f;
|
||||
immWrite(0x11,globalRSSVolume);
|
||||
}
|
||||
}
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if ((chan[i].std.phaseReset.val==1) && chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) {
|
||||
immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol));
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
writeRSSOff|=(1<<(i-9));
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
writeRSSOn|=(1<<(i-9));
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ADPCM-B
|
||||
if (chan[15].furnacePCM) {
|
||||
chan[15].std.next();
|
||||
|
||||
if (chan[15].std.vol.had) {
|
||||
chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol.val))/64;
|
||||
chan[15].outVol=(chan[15].vol*MIN(chan[15].macroVolMul,chan[15].std.vol.val))/chan[15].macroVolMul;
|
||||
immWrite(0x10b,chan[15].outVol);
|
||||
}
|
||||
|
||||
|
@ -671,16 +705,42 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
|||
chan[15].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[15].std.panL.had) {
|
||||
if (chan[15].pan!=(chan[15].std.panL.val&3)) {
|
||||
chan[15].pan=chan[15].std.panL.val&3;
|
||||
if (!isMuted[15]) {
|
||||
immWrite(0x101,(isMuted[15]?0:(chan[15].pan<<6))|2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[15].std.phaseReset.had) {
|
||||
if ((chan[15].std.phaseReset.val==1) && chan[15].active) {
|
||||
chan[15].keyOn=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[15].freqChanged) {
|
||||
if (chan[15].sample>=0 && chan[15].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0;
|
||||
chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off);
|
||||
} else {
|
||||
chan[15].freq=0;
|
||||
if (chan[15].freqChanged || chan[15].keyOn || chan[15].keyOff) {
|
||||
if (chan[15].furnacePCM) {
|
||||
if (chan[15].sample>=0 && chan[15].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0;
|
||||
chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off);
|
||||
} else {
|
||||
chan[15].freq=0;
|
||||
}
|
||||
}
|
||||
immWrite(0x109,chan[15].freq&0xff);
|
||||
immWrite(0x10a,(chan[15].freq>>8)&0xff);
|
||||
if (chan[15].keyOn || chan[15].keyOff) {
|
||||
immWrite(0x100,0x01); // reset
|
||||
if (chan[15].active && chan[15].keyOn && !chan[15].keyOff) {
|
||||
if (chan[15].sample>=0 && chan[15].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[15].sample);
|
||||
immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat
|
||||
}
|
||||
}
|
||||
chan[15].keyOn=false;
|
||||
chan[15].keyOff=false;
|
||||
}
|
||||
chan[15].freqChanged=false;
|
||||
}
|
||||
|
||||
|
@ -740,7 +800,8 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan>14) { // ADPCM-B
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
|
@ -761,7 +822,6 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
immWrite(0x104,(end>>5)&0xff);
|
||||
immWrite(0x105,(end>>13)&0xff);
|
||||
immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
|
||||
immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||
|
@ -782,6 +842,24 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroInit(NULL);
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||
break;
|
||||
}
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
immWrite(0x102,(s->offB>>5)&0xff);
|
||||
immWrite(0x103,(s->offB>>13)&0xff);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(0x104,(end>>5)&0xff);
|
||||
immWrite(0x105,(end>>13)&0xff);
|
||||
immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
|
||||
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
||||
immWrite(0x109,freq&0xff);
|
||||
immWrite(0x10a,(freq>>8)&0xff);
|
||||
immWrite(0x10b,chan[c.chan].outVol);
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
immWrite(0x100,0x01); // reset
|
||||
immWrite(0x102,0);
|
||||
immWrite(0x103,0);
|
||||
|
@ -789,26 +867,31 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
immWrite(0x105,0);
|
||||
break;
|
||||
}
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x102,(s->offB>>5)&0xff);
|
||||
immWrite(0x103,(s->offB>>13)&0xff);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(0x104,(end>>5)&0xff);
|
||||
immWrite(0x105,(end>>13)&0xff);
|
||||
immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
|
||||
immWrite(0x100,(s->isLoopable())?0xb0:0xa0); // start/repeat
|
||||
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
||||
immWrite(0x109,freq&0xff);
|
||||
immWrite(0x10a,(freq>>8)&0xff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.chan>8) { // RSS
|
||||
if (skipRegisterWrites) break;
|
||||
if (!isMuted[c.chan]) {
|
||||
writeRSSOn|=(1<<(c.chan-9));
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
}
|
||||
immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
if (skipRegisterWrites) break;
|
||||
if (chan[c.chan].furnacePCM) {
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].macroInit(NULL);
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
break;
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
|
@ -861,28 +944,12 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan>14) {
|
||||
immWrite(0x100,0x01); // reset
|
||||
break;
|
||||
}
|
||||
if (c.chan>8) {
|
||||
writeRSSOff|=1<<(c.chan-9);
|
||||
break;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
if (c.chan>14) {
|
||||
immWrite(0x100,0x01); // reset
|
||||
break;
|
||||
}
|
||||
if (c.chan>8) {
|
||||
writeRSSOff|=1<<(c.chan-9);
|
||||
break;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
|
@ -901,7 +968,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
if (c.chan>8) { // ADPCM-A
|
||||
immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
break;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
|
@ -936,7 +1003,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
if (c.chan>8) {
|
||||
immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
immWrite(0x18+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
break;
|
||||
}
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
|
@ -1205,7 +1272,7 @@ void DivPlatformYM2608::muteChannel(int ch, bool mute) {
|
|||
immWrite(0x101,(isMuted[ch]?0:(chan[ch].pan<<6))|2);
|
||||
}
|
||||
if (ch>8) { // ADPCM-A
|
||||
immWrite(0x18+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol));
|
||||
immWrite(0x18+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].outVol));
|
||||
return;
|
||||
}
|
||||
if (ch>5) { // PSG
|
||||
|
@ -1313,6 +1380,7 @@ void DivPlatformYM2608::reset() {
|
|||
sampleBank=0;
|
||||
writeRSSOff=0;
|
||||
writeRSSOn=0;
|
||||
globalRSSVolume=0x3f;
|
||||
|
||||
delay=0;
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
int vol, outVol;
|
||||
int sample;
|
||||
unsigned char pan;
|
||||
int macroVolMul;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
|
@ -84,7 +85,8 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
vol(0),
|
||||
outVol(15),
|
||||
sample(-1),
|
||||
pan(3) {}
|
||||
pan(3),
|
||||
macroVolMul(255) {}
|
||||
};
|
||||
Channel chan[16];
|
||||
DivDispatchOscBuffer* oscBuf[16];
|
||||
|
@ -99,6 +101,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
DivPlatformAY8910* ay;
|
||||
unsigned char sampleBank;
|
||||
unsigned char writeRSSOff, writeRSSOn;
|
||||
int globalRSSVolume;
|
||||
|
||||
bool extMode;
|
||||
unsigned char prescale;
|
||||
|
|
|
@ -18,15 +18,8 @@
|
|||
*/
|
||||
|
||||
#include "ym2610.h"
|
||||
#include "sound/ymfm/ymfm.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
const char* regCheatSheetYM2610[]={
|
||||
// SSG
|
||||
"SSG_FreqL_A", "000",
|
||||
|
@ -235,85 +228,6 @@ const char* regCheatSheetYM2610[]={
|
|||
NULL
|
||||
};
|
||||
|
||||
const void* DivPlatformYM2610Base::getSampleMem(int index) {
|
||||
return index == 0 ? adpcmAMem : index == 1 ? adpcmBMem : NULL;
|
||||
}
|
||||
|
||||
size_t DivPlatformYM2610Base::getSampleMemCapacity(int index) {
|
||||
return index == 0 ? 16777216 : index == 1 ? 16777216 : 0;
|
||||
}
|
||||
|
||||
size_t DivPlatformYM2610Base::getSampleMemUsage(int index) {
|
||||
return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610Base::renderSamples() {
|
||||
memset(adpcmAMem,0,getSampleMemCapacity(0));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
int paddedLen=(s->lengthA+255)&(~0xff);
|
||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||
memPos=(memPos+0xfffff)&0xf00000;
|
||||
}
|
||||
if (memPos>=getSampleMemCapacity(0)) {
|
||||
logW("out of ADPCM-A memory for sample %d!",i);
|
||||
break;
|
||||
}
|
||||
if (memPos+paddedLen>=getSampleMemCapacity(0)) {
|
||||
memcpy(adpcmAMem+memPos,s->dataA,getSampleMemCapacity(0)-memPos);
|
||||
logW("out of ADPCM-A memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
|
||||
}
|
||||
s->offA=memPos;
|
||||
memPos+=paddedLen;
|
||||
}
|
||||
adpcmAMemLen=memPos+256;
|
||||
|
||||
memset(adpcmBMem,0,getSampleMemCapacity(1));
|
||||
|
||||
memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||
memPos=(memPos+0xfffff)&0xf00000;
|
||||
}
|
||||
if (memPos>=getSampleMemCapacity(1)) {
|
||||
logW("out of ADPCM-B memory for sample %d!",i);
|
||||
break;
|
||||
}
|
||||
if (memPos+paddedLen>=getSampleMemCapacity(1)) {
|
||||
memcpy(adpcmBMem+memPos,s->dataB,getSampleMemCapacity(1)-memPos);
|
||||
logW("out of ADPCM-B memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||
}
|
||||
s->offB=memPos;
|
||||
memPos+=paddedLen;
|
||||
}
|
||||
adpcmBMemLen=memPos+256;
|
||||
}
|
||||
|
||||
int DivPlatformYM2610Base::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
parent=p;
|
||||
adpcmAMem=new unsigned char[getSampleMemCapacity(0)];
|
||||
adpcmAMemLen=0;
|
||||
adpcmBMem=new unsigned char[getSampleMemCapacity(1)];
|
||||
adpcmBMemLen=0;
|
||||
iface.adpcmAMem=adpcmAMem;
|
||||
iface.adpcmBMem=adpcmBMem;
|
||||
iface.sampleBank=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610Base::quit() {
|
||||
delete[] adpcmAMem;
|
||||
delete[] adpcmBMem;
|
||||
}
|
||||
|
||||
const char** DivPlatformYM2610::getRegisterSheet() {
|
||||
return regCheatSheetYM2610;
|
||||
}
|
||||
|
@ -438,24 +352,6 @@ const char* DivPlatformYM2610::getEffectName(unsigned char effect) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
double DivPlatformYM2610::NOTE_OPNB(int ch, int note) {
|
||||
if (ch>6) { // ADPCM
|
||||
return NOTE_ADPCMB(note);
|
||||
} else if (ch>3) { // PSG
|
||||
return NOTE_PERIODIC(note);
|
||||
}
|
||||
// FM
|
||||
return NOTE_FNUM_BLOCK(note,11);
|
||||
}
|
||||
|
||||
double DivPlatformYM2610::NOTE_ADPCMB(int note) {
|
||||
if (chan[13].sample>=0 && chan[13].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[13].sample)->centerRate)/8363.0;
|
||||
return parent->calcBaseFreq((double)chipClock/144,off,note,false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int os[2];
|
||||
|
||||
|
@ -501,20 +397,20 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
bufL[h]=os[0];
|
||||
bufR[h]=os[1];
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1));
|
||||
}
|
||||
|
||||
ssge->get_last_out(ssgOut);
|
||||
for (int i=4; i<7; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-4];
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||
}
|
||||
|
||||
for (int i=7; i<13; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-7]->get_last_out(0)+adpcmAChan[i-7]->get_last_out(1);
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1);
|
||||
}
|
||||
|
||||
oscBuf[13]->data[oscBuf[13]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -528,7 +424,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
|||
ay->getRegisterWrites().clear();
|
||||
|
||||
// FM
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
if (i==1 && extMode) continue;
|
||||
chan[i].std.next();
|
||||
|
||||
|
@ -689,41 +585,108 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
// ADPCM-B
|
||||
if (chan[13].furnacePCM) {
|
||||
chan[13].std.next();
|
||||
|
||||
if (chan[13].std.vol.had) {
|
||||
chan[13].outVol=(chan[13].vol*MIN(64,chan[13].std.vol.val))/64;
|
||||
immWrite(0x1b,chan[13].outVol);
|
||||
}
|
||||
|
||||
if (chan[13].std.arp.had) {
|
||||
if (!chan[13].inPorta) {
|
||||
if (chan[13].std.arp.mode) {
|
||||
chan[13].baseFreq=NOTE_ADPCMB(chan[13].std.arp.val);
|
||||
} else {
|
||||
chan[13].baseFreq=NOTE_ADPCMB(chan[13].note+(signed char)chan[13].std.arp.val);
|
||||
// ADPCM-A
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
if (chan[i].furnacePCM) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
if (globalADPCMAVolume!=(chan[i].std.duty.val&0x3f)) {
|
||||
globalADPCMAVolume=chan[i].std.duty.val&0x3f;
|
||||
immWrite(0x101,globalADPCMAVolume);
|
||||
}
|
||||
}
|
||||
chan[13].freqChanged=true;
|
||||
} else {
|
||||
if (chan[13].std.arp.mode && chan[13].std.arp.finished) {
|
||||
chan[13].baseFreq=NOTE_ADPCMB(chan[13].note);
|
||||
chan[13].freqChanged=true;
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if ((chan[i].std.phaseReset.val==1) && chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) {
|
||||
immWrite(0x108+(i-adpcmAChanOffs),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol));
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
writeADPCMAOff|=(1<<(i-adpcmAChanOffs));
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||
writeADPCMAOn|=(1<<(i-adpcmAChanOffs));
|
||||
}
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[13].freqChanged) {
|
||||
if (chan[13].sample>=0 && chan[13].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[13].sample)->centerRate)/8363.0;
|
||||
chan[13].freq=parent->calcFreq(chan[13].baseFreq,chan[13].pitch,false,4,chan[13].pitch2,(double)chipClock/144,off);
|
||||
} else {
|
||||
chan[13].freq=0;
|
||||
// ADPCM-B
|
||||
if (chan[adpcmBChanOffs].furnacePCM) {
|
||||
chan[adpcmBChanOffs].std.next();
|
||||
|
||||
if (chan[adpcmBChanOffs].std.vol.had) {
|
||||
chan[adpcmBChanOffs].outVol=(chan[adpcmBChanOffs].vol*MIN(chan[adpcmBChanOffs].macroVolMul,chan[adpcmBChanOffs].std.vol.val))/chan[adpcmBChanOffs].macroVolMul;
|
||||
immWrite(0x1b,chan[adpcmBChanOffs].outVol);
|
||||
}
|
||||
immWrite(0x19,chan[13].freq&0xff);
|
||||
immWrite(0x1a,(chan[13].freq>>8)&0xff);
|
||||
chan[13].freqChanged=false;
|
||||
|
||||
if (chan[adpcmBChanOffs].std.arp.had) {
|
||||
if (!chan[adpcmBChanOffs].inPorta) {
|
||||
if (chan[adpcmBChanOffs].std.arp.mode) {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].std.arp.val);
|
||||
} else {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note+(signed char)chan[adpcmBChanOffs].std.arp.val);
|
||||
}
|
||||
}
|
||||
chan[adpcmBChanOffs].freqChanged=true;
|
||||
} else {
|
||||
if (chan[adpcmBChanOffs].std.arp.mode && chan[adpcmBChanOffs].std.arp.finished) {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note);
|
||||
chan[adpcmBChanOffs].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[adpcmBChanOffs].std.panL.had) {
|
||||
if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) {
|
||||
chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3;
|
||||
if (!isMuted[adpcmBChanOffs]) {
|
||||
immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[adpcmBChanOffs].std.phaseReset.had) {
|
||||
if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) {
|
||||
chan[adpcmBChanOffs].keyOn=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) {
|
||||
if (chan[adpcmBChanOffs].furnacePCM) {
|
||||
if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0;
|
||||
chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off);
|
||||
} else {
|
||||
chan[adpcmBChanOffs].freq=0;
|
||||
}
|
||||
immWrite(0x19,chan[adpcmBChanOffs].freq&0xff);
|
||||
immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff);
|
||||
}
|
||||
if (chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) {
|
||||
immWrite(0x10,0x01); // reset
|
||||
if (chan[adpcmBChanOffs].active && chan[adpcmBChanOffs].keyOn && !chan[adpcmBChanOffs].keyOff) {
|
||||
if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[adpcmBChanOffs].sample);
|
||||
immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
|
||||
}
|
||||
}
|
||||
chan[adpcmBChanOffs].keyOn=false;
|
||||
chan[adpcmBChanOffs].keyOff=false;
|
||||
}
|
||||
chan[adpcmBChanOffs].freqChanged=false;
|
||||
}
|
||||
|
||||
if (writeADPCMAOff) {
|
||||
immWrite(0x100,0x80|writeADPCMAOff);
|
||||
writeADPCMAOff=0;
|
||||
}
|
||||
|
||||
for (int i=16; i<512; i++) {
|
||||
|
@ -733,7 +696,7 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
if (i==1 && extMode) continue;
|
||||
if (chan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
@ -761,18 +724,24 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
|||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
||||
if (writeADPCMAOn) {
|
||||
immWrite(0x100,writeADPCMAOn);
|
||||
writeADPCMAOn=0;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||
if (c.chan>3 && c.chan<7) {
|
||||
c.chan-=4;
|
||||
if (c.chan>=psgChanOffs && c.chan<7) {
|
||||
c.chan-=psgChanOffs;
|
||||
return ay->dispatch(c);
|
||||
}
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan>12) { // ADPCM-B
|
||||
if (c.chan>=adpcmBChanOffs) { // ADPCM-B
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
|
@ -793,7 +762,6 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||
|
@ -814,50 +782,104 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroInit(NULL);
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||
immWrite(0x10,0x01); // reset
|
||||
immWrite(0x12,0);
|
||||
immWrite(0x13,0);
|
||||
immWrite(0x14,0);
|
||||
immWrite(0x15,0);
|
||||
break;
|
||||
}
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x12,(s->offB>>8)&0xff);
|
||||
immWrite(0x13,s->offB>>16);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
|
||||
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
||||
immWrite(0x19,freq&0xff);
|
||||
immWrite(0x1a,(freq>>8)&0xff);
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x12,(s->offB>>8)&0xff);
|
||||
immWrite(0x13,s->offB>>16);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
||||
immWrite(0x19,freq&0xff);
|
||||
immWrite(0x1a,(freq>>8)&0xff);
|
||||
immWrite(0x1b,chan[c.chan].outVol);
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
immWrite(0x10,0x01); // reset
|
||||
immWrite(0x12,0);
|
||||
immWrite(0x13,0);
|
||||
immWrite(0x14,0);
|
||||
immWrite(0x15,0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.chan>6) { // ADPCM-A
|
||||
if (skipRegisterWrites) break;
|
||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||
immWrite(0x100,0x80|(1<<(c.chan-7)));
|
||||
immWrite(0x110+c.chan-7,0);
|
||||
immWrite(0x118+c.chan-7,0);
|
||||
immWrite(0x120+c.chan-7,0);
|
||||
immWrite(0x128+c.chan-7,0);
|
||||
break;
|
||||
if (c.chan>=adpcmAChanOffs) { // ADPCM-A
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
}
|
||||
if (skipRegisterWrites) break;
|
||||
if (chan[c.chan].furnacePCM) {
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff);
|
||||
immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16);
|
||||
int end=s->offA+s->lengthA-1;
|
||||
immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff);
|
||||
immWrite(0x128+c.chan-adpcmAChanOffs,end>>16);
|
||||
immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs));
|
||||
immWrite(0x110+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x118+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x120+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x128+c.chan-adpcmAChanOffs,0);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].sample=-1;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||
break;
|
||||
}
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff);
|
||||
immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16);
|
||||
int end=s->offA+s->lengthA-1;
|
||||
immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff);
|
||||
immWrite(0x128+c.chan-adpcmAChanOffs,end>>16);
|
||||
immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs));
|
||||
immWrite(0x110+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x118+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x120+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x128+c.chan-adpcmAChanOffs,0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x110+c.chan-7,(s->offA>>8)&0xff);
|
||||
immWrite(0x118+c.chan-7,s->offA>>16);
|
||||
int end=s->offA+s->lengthA-1;
|
||||
immWrite(0x120+c.chan-7,(end>>8)&0xff);
|
||||
immWrite(0x128+c.chan-7,end>>16);
|
||||
immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
immWrite(0x100,0x00|(1<<(c.chan-7)));
|
||||
break;
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (c.chan<4) {
|
||||
if (c.chan<psgChanOffs) {
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
|
@ -905,28 +927,12 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan>12) {
|
||||
immWrite(0x10,0x01); // reset
|
||||
break;
|
||||
}
|
||||
if (c.chan>6) {
|
||||
immWrite(0x100,0x80|(1<<(c.chan-7)));
|
||||
break;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
if (c.chan>12) {
|
||||
immWrite(0x10,0x01); // reset
|
||||
break;
|
||||
}
|
||||
if (c.chan>6) {
|
||||
immWrite(0x100,0x80|(1<<(c.chan-7)));
|
||||
break;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
|
@ -940,12 +946,12 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (c.chan>12) { // ADPCM-B
|
||||
if (c.chan>=adpcmBChanOffs) { // ADPCM-B
|
||||
immWrite(0x1b,chan[c.chan].outVol);
|
||||
break;
|
||||
}
|
||||
if (c.chan>6) { // ADPCM-A
|
||||
immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
if (c.chan>=adpcmAChanOffs) { // ADPCM-A
|
||||
immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
break;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
|
@ -959,6 +965,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_ADPCMA_GLOBAL_VOLUME: {
|
||||
if (globalADPCMAVolume!=(c.value&0x3f)) {
|
||||
globalADPCMAVolume=c.value&0x3f;
|
||||
immWrite(0x101,globalADPCMAVolume&0x3f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLUME: {
|
||||
return chan[c.chan].vol;
|
||||
break;
|
||||
|
@ -975,25 +988,25 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
} else {
|
||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
if (c.chan>12) {
|
||||
if (c.chan>=adpcmBChanOffs) {
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
break;
|
||||
}
|
||||
if (c.chan>6) {
|
||||
immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
if (c.chan>=adpcmAChanOffs) {
|
||||
immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
break;
|
||||
}
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PITCH: {
|
||||
if (c.chan==13 && !chan[c.chan].furnacePCM) break;
|
||||
if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break;
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
if (c.chan>3 || parent->song.linearPitch==2) { // PSG, ADPCM-B
|
||||
if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B
|
||||
int destFreq=NOTE_OPNB(c.chan,c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
|
@ -1027,7 +1040,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
iface.sampleBank=sampleBank;
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (c.chan==13 && !chan[c.chan].furnacePCM) break;
|
||||
if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break;
|
||||
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
|
@ -1044,13 +1057,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
if (c.chan>3) break;
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
chan[c.chan].state.fb=c.value&7;
|
||||
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: {
|
||||
if (c.chan>3) break;
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.mult=c.value2&15;
|
||||
|
@ -1058,7 +1071,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
if (c.chan>3) break;
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.tl=c.value2;
|
||||
|
@ -1070,7 +1083,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.chan>3) break;
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -1221,13 +1234,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
return 0;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
if (c.chan>12) return 255;
|
||||
if (c.chan>6) return 31;
|
||||
if (c.chan>3) return 15;
|
||||
if (c.chan>=adpcmBChanOffs) return 255;
|
||||
if (c.chan>=adpcmAChanOffs) return 31;
|
||||
if (c.chan>=psgChanOffs) return 15;
|
||||
return 127;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (c.chan>3) {
|
||||
if (c.chan>=psgChanOffs) {
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
|
||||
}
|
||||
|
@ -1245,15 +1258,8 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
|
||||
void DivPlatformYM2610::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch>12) { // ADPCM-B
|
||||
immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6));
|
||||
}
|
||||
if (ch>6) { // ADPCM-A
|
||||
immWrite(0x108+(ch-7),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol));
|
||||
return;
|
||||
}
|
||||
if (ch>3) { // PSG
|
||||
ay->muteChannel(ch-4,mute);
|
||||
if (ch>=psgChanOffs) { // PSG
|
||||
DivPlatformYM2610Base::muteChannel(ch,mute);
|
||||
return;
|
||||
}
|
||||
// FM
|
||||
|
@ -1261,7 +1267,7 @@ void DivPlatformYM2610::muteChannel(int ch, bool mute) {
|
|||
}
|
||||
|
||||
void DivPlatformYM2610::forceIns() {
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
|
@ -1284,7 +1290,7 @@ void DivPlatformYM2610::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
for (int i=7; i<14; i++) {
|
||||
for (int i=adpcmAChanOffs; i<=adpcmBChanOffs; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
|
||||
|
@ -1301,7 +1307,7 @@ void* DivPlatformYM2610::getChanState(int ch) {
|
|||
}
|
||||
|
||||
DivMacroInt* DivPlatformYM2610::getChanMacroInt(int ch) {
|
||||
if (ch>=4 && ch<7) return ay->getChanMacroInt(ch-4);
|
||||
if (ch>=psgChanOffs && ch<adpcmAChanOffs) return ay->getChanMacroInt(ch-psgChanOffs);
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
|
@ -1336,17 +1342,20 @@ void DivPlatformYM2610::reset() {
|
|||
chan[i]=DivPlatformYM2610::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
chan[i].vol=0x7f;
|
||||
chan[i].outVol=0x7f;
|
||||
}
|
||||
for (int i=4; i<7; i++) {
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
chan[i].vol=0x0f;
|
||||
chan[i].outVol=0x0f;
|
||||
}
|
||||
for (int i=7; i<13; i++) {
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
chan[i].vol=0x1f;
|
||||
chan[i].outVol=0x1f;
|
||||
}
|
||||
chan[13].vol=0xff;
|
||||
chan[adpcmBChanOffs].vol=0xff;
|
||||
chan[adpcmBChanOffs].outVol=0xff;
|
||||
|
||||
for (int i=0; i<512; i++) {
|
||||
oldWrites[i]=-1;
|
||||
|
@ -1355,6 +1364,7 @@ void DivPlatformYM2610::reset() {
|
|||
|
||||
lastBusy=60;
|
||||
sampleBank=0;
|
||||
DivPlatformYM2610Base::reset();
|
||||
|
||||
delay=0;
|
||||
|
||||
|
@ -1366,10 +1376,6 @@ void DivPlatformYM2610::reset() {
|
|||
// PCM volume
|
||||
immWrite(0x101,0x3f); // A
|
||||
immWrite(0x1b,0xff); // B
|
||||
|
||||
ay->reset();
|
||||
ay->getRegisterWrites().clear();
|
||||
ay->flushWrites();
|
||||
}
|
||||
|
||||
bool DivPlatformYM2610::isStereo() {
|
||||
|
@ -1377,7 +1383,7 @@ bool DivPlatformYM2610::isStereo() {
|
|||
}
|
||||
|
||||
bool DivPlatformYM2610::keyOffAffectsArp(int ch) {
|
||||
return (ch>3);
|
||||
return (ch>=psgChanOffs);
|
||||
}
|
||||
|
||||
void DivPlatformYM2610::notifyInsChange(int ins) {
|
||||
|
@ -1398,46 +1404,13 @@ void DivPlatformYM2610::setSkipRegisterWrites(bool value) {
|
|||
ay->setSkipRegisterWrites(value);
|
||||
}
|
||||
|
||||
void DivPlatformYM2610::setFlags(unsigned int flags) {
|
||||
switch (flags&0xff) {
|
||||
default:
|
||||
case 0x00:
|
||||
chipClock=8000000.0;
|
||||
break;
|
||||
case 0x01:
|
||||
chipClock=24167829/3;
|
||||
break;
|
||||
}
|
||||
rate=chipClock/16;
|
||||
for (int i=0; i<14; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
DivPlatformYM2610Base::init(p, channels, sugRate, flags);
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<14; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
fm=new ymfm::ym2610(iface);
|
||||
setFlags(flags);
|
||||
// YM2149, 2MHz
|
||||
ay=new DivPlatformAY8910(true,chipClock,32);
|
||||
ay->init(p,3,sugRate,16);
|
||||
ay->toggleRegisterDump(true);
|
||||
reset();
|
||||
return 14;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610::quit() {
|
||||
for (int i=0; i<14; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
ay->quit();
|
||||
delete ay;
|
||||
delete fm;
|
||||
DivPlatformYM2610Base::quit();
|
||||
}
|
||||
|
|
|
@ -19,41 +19,9 @@
|
|||
|
||||
#ifndef _YM2610_H
|
||||
#define _YM2610_H
|
||||
#include "fmshared_OPN.h"
|
||||
#include "../macroInt.h"
|
||||
#include "ay.h"
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
#include "ym2610shared.h"
|
||||
|
||||
class DivYM2610Interface: public ymfm::ymfm_interface {
|
||||
public:
|
||||
unsigned char* adpcmAMem;
|
||||
unsigned char* adpcmBMem;
|
||||
int sampleBank;
|
||||
uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address);
|
||||
void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data);
|
||||
DivYM2610Interface(): adpcmAMem(NULL), adpcmBMem(NULL), sampleBank(0) {}
|
||||
};
|
||||
|
||||
class DivPlatformYM2610Base: public DivPlatformOPN {
|
||||
protected:
|
||||
unsigned char* adpcmAMem;
|
||||
size_t adpcmAMemLen;
|
||||
unsigned char* adpcmBMem;
|
||||
size_t adpcmBMemLen;
|
||||
DivYM2610Interface iface;
|
||||
|
||||
public:
|
||||
const void* getSampleMem(int index);
|
||||
size_t getSampleMemCapacity(int index);
|
||||
size_t getSampleMemUsage(int index);
|
||||
void renderSamples();
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformYM2610Base():
|
||||
DivPlatformOPN(9440540.0, 72, 32) {}
|
||||
};
|
||||
|
||||
class DivPlatformYM2610: public DivPlatformYM2610Base {
|
||||
class DivPlatformYM2610: public DivPlatformYM2610Base<14> {
|
||||
protected:
|
||||
const unsigned short chanOffs[4]={
|
||||
0x01, 0x02, 0x101, 0x102
|
||||
|
@ -67,64 +35,8 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
|
|||
1, 2, 4, 5
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
DivInstrumentFM state;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins;
|
||||
unsigned char psgMode, autoEnvNum, autoEnvDen;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
|
||||
int vol, outVol;
|
||||
int sample;
|
||||
unsigned char pan;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
Channel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
portaPauseFreq(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
psgMode(1),
|
||||
autoEnvNum(0),
|
||||
autoEnvDen(0),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
portaPause(false),
|
||||
inPorta(false),
|
||||
furnacePCM(false),
|
||||
hardReset(false),
|
||||
vol(0),
|
||||
outVol(15),
|
||||
sample(-1),
|
||||
pan(3) {}
|
||||
};
|
||||
Channel chan[14];
|
||||
DivDispatchOscBuffer* oscBuf[14];
|
||||
bool isMuted[14];
|
||||
ymfm::ym2610* fm;
|
||||
ymfm::ym2610::output_data fmout;
|
||||
|
||||
DivPlatformAY8910* ay;
|
||||
|
||||
unsigned char sampleBank;
|
||||
|
||||
bool extMode;
|
||||
|
||||
double NOTE_OPNB(int ch, int note);
|
||||
double NOTE_ADPCMB(int note);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
|
||||
public:
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
|
@ -146,9 +58,10 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
|
|||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
void setFlags(unsigned int flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformYM2610():
|
||||
DivPlatformYM2610Base<14>(1,4,7,13) {}
|
||||
~DivPlatformYM2610();
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "sound/ymfm/ymfm.h"
|
||||
#include "ym2610.h"
|
||||
#include "../engine.h"
|
||||
#include "ym2610shared.h"
|
||||
|
||||
uint8_t DivYM2610Interface::ymfm_external_read(ymfm::access_class type, uint32_t address) {
|
||||
switch (type) {
|
||||
|
|
|
@ -18,14 +18,8 @@
|
|||
*/
|
||||
|
||||
#include "ym2610b.h"
|
||||
#include "sound/ymfm/ymfm.h"
|
||||
#include "../engine.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
const char* regCheatSheetYM2610B[]={
|
||||
// SSG
|
||||
"SSG_FreqL_A", "000",
|
||||
|
@ -422,24 +416,6 @@ const char* DivPlatformYM2610B::getEffectName(unsigned char effect) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
double DivPlatformYM2610B::NOTE_OPNB(int ch, int note) {
|
||||
if (ch>8) { // ADPCM-B
|
||||
return NOTE_ADPCMB(note);
|
||||
} else if (ch>5) { // PSG
|
||||
return NOTE_PERIODIC(note);
|
||||
}
|
||||
// FM
|
||||
return NOTE_FNUM_BLOCK(note,11);
|
||||
}
|
||||
|
||||
double DivPlatformYM2610B::NOTE_ADPCMB(int note) {
|
||||
if (chan[15].sample>=0 && chan[15].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0;
|
||||
return parent->calcBaseFreq((double)chipClock/144,off,note,false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
static int os[2];
|
||||
|
||||
|
@ -484,20 +460,20 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
bufR[h]=os[1];
|
||||
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1));
|
||||
}
|
||||
|
||||
ssge->get_last_out(ssgOut);
|
||||
for (int i=6; i<9; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6];
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||
}
|
||||
|
||||
for (int i=9; i<15; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1);
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1);
|
||||
}
|
||||
|
||||
oscBuf[15]->data[oscBuf[15]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +487,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
|||
ay->getRegisterWrites().clear();
|
||||
|
||||
// FM
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
if (i==2 && extMode) continue;
|
||||
chan[i].std.next();
|
||||
|
||||
|
@ -671,41 +647,108 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
|||
chan[i].keyOff=false;
|
||||
}
|
||||
}
|
||||
// ADPCM-B
|
||||
if (chan[15].furnacePCM) {
|
||||
chan[15].std.next();
|
||||
|
||||
if (chan[15].std.vol.had) {
|
||||
chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol.val))/64;
|
||||
immWrite(0x1b,chan[15].outVol);
|
||||
}
|
||||
|
||||
if (chan[15].std.arp.had) {
|
||||
if (!chan[15].inPorta) {
|
||||
if (chan[15].std.arp.mode) {
|
||||
chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp.val);
|
||||
} else {
|
||||
chan[15].baseFreq=NOTE_ADPCMB(chan[15].note+(signed char)chan[15].std.arp.val);
|
||||
// ADPCM-A
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
if (chan[i].furnacePCM) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
|
||||
}
|
||||
if (chan[i].std.duty.had) {
|
||||
if (globalADPCMAVolume!=(chan[i].std.duty.val&0x3f)) {
|
||||
globalADPCMAVolume=chan[i].std.duty.val&0x3f;
|
||||
immWrite(0x101,globalADPCMAVolume);
|
||||
}
|
||||
}
|
||||
chan[15].freqChanged=true;
|
||||
} else {
|
||||
if (chan[15].std.arp.mode && chan[15].std.arp.finished) {
|
||||
chan[15].baseFreq=NOTE_ADPCMB(chan[15].note);
|
||||
chan[15].freqChanged=true;
|
||||
if (chan[i].std.panL.had) {
|
||||
chan[i].pan=chan[i].std.panL.val&3;
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if ((chan[i].std.phaseReset.val==1) && chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
if (!isMuted[i] && (chan[i].std.vol.had || chan[i].std.panL.had)) {
|
||||
immWrite(0x108+(i-adpcmAChanOffs),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol));
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
writeADPCMAOff|=(1<<(i-adpcmAChanOffs));
|
||||
chan[i].keyOff=false;
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||
writeADPCMAOn|=(1<<(i-adpcmAChanOffs));
|
||||
}
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[15].freqChanged) {
|
||||
if (chan[15].sample>=0 && chan[15].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0;
|
||||
chan[15].freq=parent->calcFreq(chan[15].baseFreq,chan[15].pitch,false,4,chan[15].pitch2,(double)chipClock/144,off);
|
||||
} else {
|
||||
chan[15].freq=0;
|
||||
// ADPCM-B
|
||||
if (chan[adpcmBChanOffs].furnacePCM) {
|
||||
chan[adpcmBChanOffs].std.next();
|
||||
|
||||
if (chan[adpcmBChanOffs].std.vol.had) {
|
||||
chan[adpcmBChanOffs].outVol=(chan[adpcmBChanOffs].vol*MIN(chan[adpcmBChanOffs].macroVolMul,chan[adpcmBChanOffs].std.vol.val))/chan[adpcmBChanOffs].macroVolMul;
|
||||
immWrite(0x1b,chan[adpcmBChanOffs].outVol);
|
||||
}
|
||||
immWrite(0x19,chan[15].freq&0xff);
|
||||
immWrite(0x1a,(chan[15].freq>>8)&0xff);
|
||||
chan[15].freqChanged=false;
|
||||
|
||||
if (chan[adpcmBChanOffs].std.arp.had) {
|
||||
if (!chan[adpcmBChanOffs].inPorta) {
|
||||
if (chan[adpcmBChanOffs].std.arp.mode) {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].std.arp.val);
|
||||
} else {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note+(signed char)chan[adpcmBChanOffs].std.arp.val);
|
||||
}
|
||||
}
|
||||
chan[adpcmBChanOffs].freqChanged=true;
|
||||
} else {
|
||||
if (chan[adpcmBChanOffs].std.arp.mode && chan[adpcmBChanOffs].std.arp.finished) {
|
||||
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(chan[adpcmBChanOffs].note);
|
||||
chan[adpcmBChanOffs].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[adpcmBChanOffs].std.panL.had) {
|
||||
if (chan[adpcmBChanOffs].pan!=(chan[adpcmBChanOffs].std.panL.val&3)) {
|
||||
chan[adpcmBChanOffs].pan=chan[adpcmBChanOffs].std.panL.val&3;
|
||||
if (!isMuted[adpcmBChanOffs]) {
|
||||
immWrite(0x11,(isMuted[adpcmBChanOffs]?0:(chan[adpcmBChanOffs].pan<<6)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[adpcmBChanOffs].std.phaseReset.had) {
|
||||
if ((chan[adpcmBChanOffs].std.phaseReset.val==1) && chan[adpcmBChanOffs].active) {
|
||||
chan[adpcmBChanOffs].keyOn=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[adpcmBChanOffs].freqChanged || chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) {
|
||||
if (chan[adpcmBChanOffs].furnacePCM) {
|
||||
if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0;
|
||||
chan[adpcmBChanOffs].freq=parent->calcFreq(chan[adpcmBChanOffs].baseFreq,chan[adpcmBChanOffs].pitch,false,4,chan[adpcmBChanOffs].pitch2,(double)chipClock/144,off);
|
||||
} else {
|
||||
chan[adpcmBChanOffs].freq=0;
|
||||
}
|
||||
immWrite(0x19,chan[adpcmBChanOffs].freq&0xff);
|
||||
immWrite(0x1a,(chan[adpcmBChanOffs].freq>>8)&0xff);
|
||||
}
|
||||
if (chan[adpcmBChanOffs].keyOn || chan[adpcmBChanOffs].keyOff) {
|
||||
immWrite(0x10,0x01); // reset
|
||||
if (chan[adpcmBChanOffs].active && chan[adpcmBChanOffs].keyOn && !chan[adpcmBChanOffs].keyOff) {
|
||||
if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[adpcmBChanOffs].sample);
|
||||
immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
|
||||
}
|
||||
}
|
||||
chan[adpcmBChanOffs].keyOn=false;
|
||||
chan[adpcmBChanOffs].keyOff=false;
|
||||
}
|
||||
chan[adpcmBChanOffs].freqChanged=false;
|
||||
}
|
||||
|
||||
if (writeADPCMAOff) {
|
||||
immWrite(0x100,0x80|writeADPCMAOff);
|
||||
writeADPCMAOff=0;
|
||||
}
|
||||
|
||||
for (int i=16; i<512; i++) {
|
||||
|
@ -715,7 +758,7 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
if (i==2 && extMode) continue;
|
||||
if (chan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
@ -743,18 +786,24 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
|||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
||||
if (writeADPCMAOn) {
|
||||
immWrite(0x100,writeADPCMAOn);
|
||||
writeADPCMAOn=0;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||
if (c.chan>5 && c.chan<9) {
|
||||
c.chan-=6;
|
||||
if (c.chan>=psgChanOffs && c.chan<adpcmAChanOffs) {
|
||||
c.chan-=psgChanOffs;
|
||||
return ay->dispatch(c);
|
||||
}
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan>14) { // ADPCM-B
|
||||
if (c.chan>=adpcmBChanOffs) { // ADPCM-B
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:255;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
|
@ -775,7 +824,6 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||
|
@ -796,45 +844,99 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
chan[c.chan].macroInit(NULL);
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||
immWrite(0x10,0x01); // reset
|
||||
immWrite(0x12,0);
|
||||
immWrite(0x13,0);
|
||||
immWrite(0x14,0);
|
||||
immWrite(0x15,0);
|
||||
break;
|
||||
}
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x12,(s->offB>>8)&0xff);
|
||||
immWrite(0x13,s->offB>>16);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
|
||||
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
||||
immWrite(0x19,freq&0xff);
|
||||
immWrite(0x1a,(freq>>8)&0xff);
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x12,(s->offB>>8)&0xff);
|
||||
immWrite(0x13,s->offB>>16);
|
||||
int end=s->offB+s->lengthB-1;
|
||||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
||||
immWrite(0x19,freq&0xff);
|
||||
immWrite(0x1a,(freq>>8)&0xff);
|
||||
immWrite(0x1b,chan[c.chan].outVol);
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
immWrite(0x10,0x01); // reset
|
||||
immWrite(0x12,0);
|
||||
immWrite(0x13,0);
|
||||
immWrite(0x14,0);
|
||||
immWrite(0x15,0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.chan>8) { // ADPCM-A
|
||||
if (skipRegisterWrites) break;
|
||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||
immWrite(0x100,0x80|(1<<(c.chan-9)));
|
||||
immWrite(0x110+c.chan-9,0);
|
||||
immWrite(0x118+c.chan-9,0);
|
||||
immWrite(0x120+c.chan-9,0);
|
||||
immWrite(0x128+c.chan-9,0);
|
||||
break;
|
||||
if (c.chan>=adpcmAChanOffs) { // ADPCM-A
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31;
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA) {
|
||||
chan[c.chan].furnacePCM=true;
|
||||
} else {
|
||||
chan[c.chan].furnacePCM=false;
|
||||
}
|
||||
if (skipRegisterWrites) break;
|
||||
if (chan[c.chan].furnacePCM) {
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff);
|
||||
immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16);
|
||||
int end=s->offA+s->lengthA-1;
|
||||
immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff);
|
||||
immWrite(0x128+c.chan-adpcmAChanOffs,end>>16);
|
||||
immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs));
|
||||
immWrite(0x110+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x118+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x120+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x128+c.chan-adpcmAChanOffs,0);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].sample=-1;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
||||
break;
|
||||
}
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x110+c.chan-adpcmAChanOffs,(s->offA>>8)&0xff);
|
||||
immWrite(0x118+c.chan-adpcmAChanOffs,s->offA>>16);
|
||||
int end=s->offA+s->lengthA-1;
|
||||
immWrite(0x120+c.chan-adpcmAChanOffs,(end>>8)&0xff);
|
||||
immWrite(0x128+c.chan-adpcmAChanOffs,end>>16);
|
||||
immWrite(0x108+c.chan-adpcmAChanOffs,isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
writeADPCMAOff|=(1<<(c.chan-adpcmAChanOffs));
|
||||
immWrite(0x110+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x118+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x120+c.chan-adpcmAChanOffs,0);
|
||||
immWrite(0x128+c.chan-adpcmAChanOffs,0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
immWrite(0x110+c.chan-9,(s->offA>>8)&0xff);
|
||||
immWrite(0x118+c.chan-9,s->offA>>16);
|
||||
int end=s->offA+s->lengthA-1;
|
||||
immWrite(0x120+c.chan-9,(end>>8)&0xff);
|
||||
immWrite(0x128+c.chan-9,end>>16);
|
||||
immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
immWrite(0x100,0x00|(1<<(c.chan-9)));
|
||||
break;
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||
|
@ -887,28 +989,12 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan>14) {
|
||||
immWrite(0x10,0x01); // reset
|
||||
break;
|
||||
}
|
||||
if (c.chan>8) {
|
||||
immWrite(0x100,0x80|(1<<(c.chan-9)));
|
||||
break;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
if (c.chan>14) {
|
||||
immWrite(0x10,0x01); // reset
|
||||
break;
|
||||
}
|
||||
if (c.chan>8) {
|
||||
immWrite(0x100,0x80|(1<<(c.chan-9)));
|
||||
break;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
|
@ -922,12 +1008,12 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (c.chan>14) { // ADPCM-B
|
||||
if (c.chan>=adpcmBChanOffs) { // ADPCM-B
|
||||
immWrite(0x1b,chan[c.chan].outVol);
|
||||
break;
|
||||
}
|
||||
if (c.chan>8) { // ADPCM-A
|
||||
immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
if (c.chan>=adpcmAChanOffs) { // ADPCM-A
|
||||
immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
break;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
|
@ -941,6 +1027,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_ADPCMA_GLOBAL_VOLUME: {
|
||||
if (globalADPCMAVolume!=(c.value&0x3f)) {
|
||||
globalADPCMAVolume=c.value&0x3f;
|
||||
immWrite(0x101,globalADPCMAVolume&0x3f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLUME: {
|
||||
return chan[c.chan].vol;
|
||||
break;
|
||||
|
@ -957,25 +1050,25 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
} else {
|
||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
if (c.chan>14) {
|
||||
if (c.chan>=adpcmBChanOffs) {
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
break;
|
||||
}
|
||||
if (c.chan>8) {
|
||||
immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
||||
if (c.chan>=adpcmAChanOffs) {
|
||||
immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||
break;
|
||||
}
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PITCH: {
|
||||
if (c.chan==15 && !chan[c.chan].furnacePCM) break;
|
||||
if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break;
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
if (c.chan>5 || parent->song.linearPitch==2) { // PSG, ADPCM-B
|
||||
if (c.chan>=psgChanOffs || parent->song.linearPitch==2) { // PSG, ADPCM-B
|
||||
int destFreq=NOTE_OPNB(c.chan,c.value2);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
|
@ -1009,7 +1102,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
iface.sampleBank=sampleBank;
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (c.chan==15 && !chan[c.chan].furnacePCM) break;
|
||||
if (c.chan==adpcmBChanOffs && !chan[c.chan].furnacePCM) break;
|
||||
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
|
@ -1026,13 +1119,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
if (c.chan>5) break;
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
chan[c.chan].state.fb=c.value&7;
|
||||
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: {
|
||||
if (c.chan>5) break;
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.mult=c.value2&15;
|
||||
|
@ -1040,7 +1133,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
if (c.chan>5) break;
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.tl=c.value2;
|
||||
|
@ -1052,7 +1145,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.chan>5) break;
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -1203,13 +1296,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
return 0;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
if (c.chan>14) return 255;
|
||||
if (c.chan>8) return 31;
|
||||
if (c.chan>5) return 15;
|
||||
if (c.chan>=adpcmBChanOffs) return 255;
|
||||
if (c.chan>=adpcmAChanOffs) return 31;
|
||||
if (c.chan>=psgChanOffs) return 15;
|
||||
return 127;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (c.chan>5) {
|
||||
if (c.chan>=psgChanOffs) {
|
||||
if (chan[c.chan].active && c.value2) {
|
||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
|
||||
}
|
||||
|
@ -1227,15 +1320,8 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
|
||||
void DivPlatformYM2610B::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch>14) { // ADPCM-B
|
||||
immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6));
|
||||
}
|
||||
if (ch>8) { // ADPCM-A
|
||||
immWrite(0x108+(ch-9),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].vol));
|
||||
return;
|
||||
}
|
||||
if (ch>5) { // PSG
|
||||
ay->muteChannel(ch-6,mute);
|
||||
if (ch>=psgChanOffs) { // PSG
|
||||
DivPlatformYM2610Base::muteChannel(ch,mute);
|
||||
return;
|
||||
}
|
||||
// FM
|
||||
|
@ -1243,7 +1329,7 @@ void DivPlatformYM2610B::muteChannel(int ch, bool mute) {
|
|||
}
|
||||
|
||||
void DivPlatformYM2610B::forceIns() {
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
|
@ -1266,7 +1352,7 @@ void DivPlatformYM2610B::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
for (int i=9; i<16; i++) {
|
||||
for (int i=adpcmAChanOffs; i<=adpcmBChanOffs; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
|
||||
|
@ -1283,7 +1369,7 @@ void* DivPlatformYM2610B::getChanState(int ch) {
|
|||
}
|
||||
|
||||
DivMacroInt* DivPlatformYM2610B::getChanMacroInt(int ch) {
|
||||
if (ch>=6 && ch<9) return ay->getChanMacroInt(ch-6);
|
||||
if (ch>=psgChanOffs && ch<adpcmAChanOffs) return ay->getChanMacroInt(ch-psgChanOffs);
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
|
@ -1318,17 +1404,20 @@ void DivPlatformYM2610B::reset() {
|
|||
chan[i]=DivPlatformYM2610B::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
}
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
chan[i].vol=0x7f;
|
||||
chan[i].outVol=0x7f;
|
||||
}
|
||||
for (int i=6; i<9; i++) {
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
chan[i].vol=0x0f;
|
||||
chan[i].outVol=0x0f;
|
||||
}
|
||||
for (int i=9; i<15; i++) {
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
chan[i].vol=0x1f;
|
||||
chan[i].outVol=0x1f;
|
||||
}
|
||||
chan[15].vol=0xff;
|
||||
chan[adpcmBChanOffs].vol=0xff;
|
||||
chan[adpcmBChanOffs].outVol=0xff;
|
||||
|
||||
for (int i=0; i<512; i++) {
|
||||
oldWrites[i]=-1;
|
||||
|
@ -1337,6 +1426,7 @@ void DivPlatformYM2610B::reset() {
|
|||
|
||||
lastBusy=60;
|
||||
sampleBank=0;
|
||||
DivPlatformYM2610Base::reset();
|
||||
|
||||
delay=0;
|
||||
|
||||
|
@ -1359,7 +1449,7 @@ bool DivPlatformYM2610B::isStereo() {
|
|||
}
|
||||
|
||||
bool DivPlatformYM2610B::keyOffAffectsArp(int ch) {
|
||||
return (ch>5);
|
||||
return (ch>=psgChanOffs);
|
||||
}
|
||||
|
||||
void DivPlatformYM2610B::notifyInsChange(int ins) {
|
||||
|
@ -1380,46 +1470,13 @@ void DivPlatformYM2610B::setSkipRegisterWrites(bool value) {
|
|||
ay->setSkipRegisterWrites(value);
|
||||
}
|
||||
|
||||
void DivPlatformYM2610B::setFlags(unsigned int flags) {
|
||||
switch (flags&0xff) {
|
||||
default:
|
||||
case 0x00:
|
||||
chipClock=8000000.0;
|
||||
break;
|
||||
case 0x01:
|
||||
chipClock=24167829/3;
|
||||
break;
|
||||
}
|
||||
rate=chipClock/16;
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
DivPlatformYM2610Base::init(p, channels, sugRate, flags);
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<16; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
fm=new ymfm::ym2610b(iface);
|
||||
setFlags(flags);
|
||||
// YM2149, 2MHz
|
||||
ay=new DivPlatformAY8910(true,chipClock,32);
|
||||
ay->init(p,3,sugRate,16);
|
||||
ay->toggleRegisterDump(true);
|
||||
reset();
|
||||
return 16;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610B::quit() {
|
||||
for (int i=0; i<16; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
ay->quit();
|
||||
delete ay;
|
||||
delete fm;
|
||||
DivPlatformYM2610Base::quit();
|
||||
}
|
||||
|
|
|
@ -19,12 +19,9 @@
|
|||
|
||||
#ifndef _YM2610B_H
|
||||
#define _YM2610B_H
|
||||
#include "ym2610.h"
|
||||
#include "../macroInt.h"
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
#include "ym2610shared.h"
|
||||
|
||||
|
||||
class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
||||
class DivPlatformYM2610B: public DivPlatformYM2610Base<16> {
|
||||
protected:
|
||||
const unsigned short chanOffs[6]={
|
||||
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
|
||||
|
@ -34,65 +31,8 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
|||
0, 1, 2, 4, 5, 6
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
DivInstrumentFM state;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins;
|
||||
unsigned char psgMode, autoEnvNum, autoEnvDen;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
|
||||
int vol, outVol;
|
||||
int sample;
|
||||
unsigned char pan;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
Channel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
portaPauseFreq(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
psgMode(1),
|
||||
autoEnvNum(0),
|
||||
autoEnvDen(0),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
portaPause(false),
|
||||
inPorta(false),
|
||||
furnacePCM(false),
|
||||
hardReset(false),
|
||||
vol(0),
|
||||
outVol(15),
|
||||
sample(-1),
|
||||
pan(3) {}
|
||||
};
|
||||
Channel chan[16];
|
||||
DivDispatchOscBuffer* oscBuf[16];
|
||||
bool isMuted[16];
|
||||
ymfm::ym2610b* fm;
|
||||
ymfm::ym2610b::output_data fmout;
|
||||
|
||||
DivPlatformAY8910* ay;
|
||||
unsigned char sampleBank;
|
||||
|
||||
bool extMode;
|
||||
double fmFreqBase=9440540;
|
||||
unsigned char ayDiv=32;
|
||||
|
||||
double NOTE_OPNB(int ch, int note);
|
||||
double NOTE_ADPCMB(int note);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
|
||||
public:
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
|
@ -114,9 +54,10 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
|||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
void setFlags(unsigned int flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformYM2610B():
|
||||
DivPlatformYM2610Base<16>(2,6,9,15) {}
|
||||
~DivPlatformYM2610B();
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -18,31 +18,27 @@
|
|||
*/
|
||||
|
||||
#include "ym2610bext.h"
|
||||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||
if (c.chan<2) {
|
||||
if (c.chan<extChanOffs) {
|
||||
return DivPlatformYM2610B::dispatch(c);
|
||||
}
|
||||
if (c.chan>5) {
|
||||
if (c.chan>(extChanOffs+3)) {
|
||||
c.chan-=3;
|
||||
return DivPlatformYM2610B::dispatch(c);
|
||||
}
|
||||
int ch=c.chan-2;
|
||||
int ch=c.chan-extChanOffs;
|
||||
int ordch=orderedOps[ch];
|
||||
if (!extMode) {
|
||||
c.chan=2;
|
||||
c.chan=extChanOffs;
|
||||
return DivPlatformYM2610B::dispatch(c);
|
||||
}
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
// TODO: how does this work?!
|
||||
if (isOpMuted[ch]) {
|
||||
|
@ -61,8 +57,8 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+0x90,op.ssgEnv&15);
|
||||
}
|
||||
if (opChan[ch].insChanged) { // TODO how does this work?
|
||||
rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
||||
rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
rWrite(chanOffs[extChanOffs]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
||||
rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
}
|
||||
opChan[ch].insChanged=false;
|
||||
|
||||
|
@ -83,7 +79,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_VOLUME: {
|
||||
opChan[ch].vol=c.value;
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
|
@ -115,7 +111,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
opChan[i].pan=opChan[ch].pan;
|
||||
}
|
||||
}
|
||||
rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PITCH: {
|
||||
|
@ -165,19 +161,19 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
chan[2].state.fb=c.value&7;
|
||||
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
|
||||
chan[extChanOffs].state.fb=c.value&7;
|
||||
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: { // TODO
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: { // TODO
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (isOutput[ins->fm.alg][c.value]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
||||
|
@ -189,15 +185,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_AR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
|
@ -205,15 +201,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
|
@ -221,15 +217,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
|
@ -237,15 +233,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
|
@ -253,15 +249,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
|
@ -269,15 +265,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
|
@ -285,15 +281,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
break;
|
||||
|
@ -301,15 +297,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
|
@ -317,15 +313,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_SSG: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
break;
|
||||
|
@ -408,31 +404,31 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) {
|
||||
if (ch<2) {
|
||||
if (ch<extChanOffs) {
|
||||
DivPlatformYM2610B::muteChannel(ch,mute);
|
||||
return;
|
||||
}
|
||||
if (ch>5) {
|
||||
if (ch>(extChanOffs+3)) {
|
||||
DivPlatformYM2610B::muteChannel(ch-3,mute);
|
||||
return;
|
||||
}
|
||||
isOpMuted[ch-2]=mute;
|
||||
isOpMuted[ch-extChanOffs]=mute;
|
||||
|
||||
int ordch=orderedOps[ch-2];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch-2].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
int ordch=orderedOps[ch-extChanOffs];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch-extChanOffs].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch-2]) {
|
||||
if (isOpMuted[ch-extChanOffs]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (isOutput[ins->fm.alg][ordch]) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-extChanOffs].vol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformYM2610BExt::forceIns() {
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
|
@ -469,7 +465,7 @@ void DivPlatformYM2610BExt::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
for (int i=6; i<16; i++) {
|
||||
for (int i=adpcmAChanOffs; i<=adpcmBChanOffs; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
ay->forceIns();
|
||||
|
@ -488,21 +484,21 @@ void DivPlatformYM2610BExt::forceIns() {
|
|||
}
|
||||
|
||||
void* DivPlatformYM2610BExt::getChanState(int ch) {
|
||||
if (ch>=6) return &chan[ch-3];
|
||||
if (ch>=2) return &opChan[ch-2];
|
||||
if (ch>=(extChanOffs+4)) return &chan[ch-3];
|
||||
if (ch>=extChanOffs) return &opChan[ch-extChanOffs];
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) {
|
||||
if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9);
|
||||
if (ch>=6) return &chan[ch-3].std;
|
||||
if (ch>=2) return NULL; // currently not implemented
|
||||
if (ch>=(psgChanOffs+3) && ch<(adpcmAChanOffs+3)) return ay->getChanMacroInt(ch-psgChanOffs-3);
|
||||
if (ch>=(extChanOffs+4)) return &chan[ch-3].std;
|
||||
if (ch>=extChanOffs) return NULL; // currently not implemented
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) {
|
||||
if (ch>=6) return oscBuf[ch-3];
|
||||
if (ch<3) return oscBuf[ch];
|
||||
if (ch>=(extChanOffs+4)) return oscBuf[ch-3];
|
||||
if (ch<(extChanOffs+1)) return oscBuf[ch];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -520,7 +516,7 @@ void DivPlatformYM2610BExt::reset() {
|
|||
}
|
||||
|
||||
bool DivPlatformYM2610BExt::keyOffAffectsArp(int ch) {
|
||||
return (ch>8);
|
||||
return (ch>=(psgChanOffs+3));
|
||||
}
|
||||
|
||||
void DivPlatformYM2610BExt::notifyInsChange(int ins) {
|
||||
|
|
|
@ -22,19 +22,7 @@
|
|||
#include "ym2610b.h"
|
||||
|
||||
class DivPlatformYM2610BExt: public DivPlatformYM2610B {
|
||||
struct OpChannel {
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
||||
int vol;
|
||||
unsigned char pan;
|
||||
// UGLY
|
||||
OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false),
|
||||
inPorta(false), vol(0), pan(3) {}
|
||||
};
|
||||
OpChannel opChan[4];
|
||||
DivPlatformYM2610Base::OpChannel opChan[4];
|
||||
bool isOpMuted[4];
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
|
|
|
@ -18,31 +18,27 @@
|
|||
*/
|
||||
|
||||
#include "ym2610ext.h"
|
||||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||
if (c.chan<1) {
|
||||
if (c.chan<extChanOffs) {
|
||||
return DivPlatformYM2610::dispatch(c);
|
||||
}
|
||||
if (c.chan>4) {
|
||||
if (c.chan>(extChanOffs+3)) {
|
||||
c.chan-=3;
|
||||
return DivPlatformYM2610::dispatch(c);
|
||||
}
|
||||
int ch=c.chan-1;
|
||||
int ch=c.chan-extChanOffs;
|
||||
int ordch=orderedOps[ch];
|
||||
if (!extMode) {
|
||||
c.chan=2;
|
||||
c.chan=extChanOffs;
|
||||
return DivPlatformYM2610::dispatch(c);
|
||||
}
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
// TODO: how does this work?!
|
||||
if (isOpMuted[ch]) {
|
||||
|
@ -61,8 +57,8 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+0x90,op.ssgEnv&15);
|
||||
}
|
||||
if (opChan[ch].insChanged) { // TODO how does this work?
|
||||
rWrite(chanOffs[1]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
||||
rWrite(chanOffs[1]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
rWrite(chanOffs[extChanOffs]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
||||
rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
}
|
||||
opChan[ch].insChanged=false;
|
||||
|
||||
|
@ -83,7 +79,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_VOLUME: {
|
||||
opChan[ch].vol=c.value;
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
|
@ -115,7 +111,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
opChan[i].pan=opChan[ch].pan;
|
||||
}
|
||||
}
|
||||
rWrite(chanOffs[1]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
rWrite(chanOffs[extChanOffs]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PITCH: {
|
||||
|
@ -165,19 +161,19 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
chan[1].state.fb=c.value&7;
|
||||
rWrite(chanOffs[1]+ADDR_FB_ALG,(chan[1].state.alg&7)|(chan[1].state.fb<<3));
|
||||
chan[extChanOffs].state.fb=c.value&7;
|
||||
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: { // TODO
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: { // TODO
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (isOutput[ins->fm.alg][c.value]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
||||
|
@ -189,15 +185,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_AR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
|
@ -205,15 +201,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
|
@ -221,15 +217,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
|
@ -237,15 +233,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
|
@ -253,15 +249,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
|
@ -269,15 +265,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
|
@ -285,15 +281,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
break;
|
||||
|
@ -301,15 +297,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
|
@ -317,15 +313,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_SSG: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[c.value]];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
break;
|
||||
|
@ -408,31 +404,31 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) {
|
||||
if (ch<1) {
|
||||
if (ch<extChanOffs) {
|
||||
DivPlatformYM2610::muteChannel(ch,mute);
|
||||
return;
|
||||
}
|
||||
if (ch>4) {
|
||||
if (ch>(extChanOffs+3)) {
|
||||
DivPlatformYM2610::muteChannel(ch-3,mute);
|
||||
return;
|
||||
}
|
||||
isOpMuted[ch-1]=mute;
|
||||
isOpMuted[ch-extChanOffs]=mute;
|
||||
|
||||
int ordch=orderedOps[ch-1];
|
||||
int ordch=orderedOps[ch-extChanOffs];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[ordch];
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (isOutput[ins->fm.alg][ordch]) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-extChanOffs].vol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformYM2610Ext::forceIns() {
|
||||
for (int i=0; i<4; i++) {
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
|
@ -469,7 +465,7 @@ void DivPlatformYM2610Ext::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
for (int i=4; i<14; i++) {
|
||||
for (int i=adpcmAChanOffs; i<=adpcmBChanOffs; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
ay->forceIns();
|
||||
|
@ -488,21 +484,21 @@ void DivPlatformYM2610Ext::forceIns() {
|
|||
}
|
||||
|
||||
void* DivPlatformYM2610Ext::getChanState(int ch) {
|
||||
if (ch>=5) return &chan[ch-3];
|
||||
if (ch>=1) return &opChan[ch-1];
|
||||
if (ch>=(extChanOffs+4)) return &chan[ch-3];
|
||||
if (ch>=extChanOffs) return &opChan[ch-extChanOffs];
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) {
|
||||
if (ch>=7 && ch<10) return ay->getChanMacroInt(ch-7);
|
||||
if (ch>=5) return &chan[ch-3].std;
|
||||
if (ch>=1) return NULL; // currently not implemented
|
||||
if (ch>=(psgChanOffs+3) && ch<(adpcmAChanOffs+3)) return ay->getChanMacroInt(ch-psgChanOffs-3);
|
||||
if (ch>=(extChanOffs+4)) return &chan[ch-3].std;
|
||||
if (ch>=extChanOffs) return NULL; // currently not implemented
|
||||
return &chan[ch].std;
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) {
|
||||
if (ch>=5) return oscBuf[ch-3];
|
||||
if (ch<2) return oscBuf[ch];
|
||||
if (ch>=(extChanOffs+4)) return oscBuf[ch-3];
|
||||
if (ch<(extChanOffs+1)) return oscBuf[ch];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -520,7 +516,7 @@ void DivPlatformYM2610Ext::reset() {
|
|||
}
|
||||
|
||||
bool DivPlatformYM2610Ext::keyOffAffectsArp(int ch) {
|
||||
return (ch>7);
|
||||
return (ch>=(psgChanOffs+3));
|
||||
}
|
||||
|
||||
void DivPlatformYM2610Ext::notifyInsChange(int ins) {
|
||||
|
|
|
@ -22,19 +22,7 @@
|
|||
#include "ym2610.h"
|
||||
|
||||
class DivPlatformYM2610Ext: public DivPlatformYM2610 {
|
||||
struct OpChannel {
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
||||
int vol;
|
||||
unsigned char pan;
|
||||
// UGLY
|
||||
OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false),
|
||||
inPorta(false), vol(0), pan(3) {}
|
||||
};
|
||||
OpChannel opChan[4];
|
||||
DivPlatformYM2610Base::OpChannel opChan[4];
|
||||
bool isOpMuted[4];
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
|
|
315
src/engine/platform/ym2610shared.h
Normal file
315
src/engine/platform/ym2610shared.h
Normal file
|
@ -0,0 +1,315 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 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 _YM2610SHARED_H
|
||||
#define _YM2610SHARED_H
|
||||
#include "fmshared_OPN.h"
|
||||
#include "../macroInt.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include "ay.h"
|
||||
#include "sound/ymfm/ymfm.h"
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
#include <string.h>
|
||||
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
class DivYM2610Interface: public ymfm::ymfm_interface {
|
||||
public:
|
||||
unsigned char* adpcmAMem;
|
||||
unsigned char* adpcmBMem;
|
||||
int sampleBank;
|
||||
uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address);
|
||||
void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data);
|
||||
DivYM2610Interface():
|
||||
adpcmAMem(NULL),
|
||||
adpcmBMem(NULL),
|
||||
sampleBank(0) {}
|
||||
};
|
||||
|
||||
template<int ChanNum>
|
||||
class DivPlatformYM2610Base: public DivPlatformOPN {
|
||||
protected:
|
||||
struct Channel {
|
||||
DivInstrumentFM state;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins;
|
||||
unsigned char psgMode, autoEnvNum, autoEnvDen;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
|
||||
int vol, outVol;
|
||||
int sample;
|
||||
unsigned char pan;
|
||||
int macroVolMul;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
Channel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
portaPauseFreq(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
psgMode(1),
|
||||
autoEnvNum(0),
|
||||
autoEnvDen(0),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
portaPause(false),
|
||||
inPorta(false),
|
||||
furnacePCM(false),
|
||||
hardReset(false),
|
||||
vol(0),
|
||||
outVol(15),
|
||||
sample(-1),
|
||||
pan(3),
|
||||
macroVolMul(255) {}
|
||||
};
|
||||
|
||||
struct OpChannel {
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
||||
int vol;
|
||||
unsigned char pan;
|
||||
// UGLY
|
||||
OpChannel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
pitch2(0),
|
||||
portaPauseFreq(0),
|
||||
ins(-1),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
portaPause(false),
|
||||
inPorta(false),
|
||||
vol(0),
|
||||
pan(3) {}
|
||||
};
|
||||
Channel chan[ChanNum];
|
||||
DivDispatchOscBuffer* oscBuf[ChanNum];
|
||||
bool isMuted[ChanNum];
|
||||
|
||||
ymfm::ym2610b* fm;
|
||||
ymfm::ym2610b::output_data fmout;
|
||||
DivPlatformAY8910* ay;
|
||||
|
||||
unsigned char* adpcmAMem;
|
||||
size_t adpcmAMemLen;
|
||||
unsigned char* adpcmBMem;
|
||||
size_t adpcmBMemLen;
|
||||
DivYM2610Interface iface;
|
||||
|
||||
unsigned char sampleBank;
|
||||
|
||||
bool extMode;
|
||||
|
||||
unsigned char writeADPCMAOff, writeADPCMAOn;
|
||||
int globalADPCMAVolume;
|
||||
|
||||
const int extChanOffs, psgChanOffs, adpcmAChanOffs, adpcmBChanOffs;
|
||||
const int chanNum=ChanNum;
|
||||
|
||||
double NOTE_OPNB(int ch, int note) {
|
||||
if (ch>=adpcmBChanOffs) { // ADPCM
|
||||
return NOTE_ADPCMB(note);
|
||||
} else if (ch>=psgChanOffs) { // PSG
|
||||
return NOTE_PERIODIC(note);
|
||||
}
|
||||
// FM
|
||||
return NOTE_FNUM_BLOCK(note,11);
|
||||
}
|
||||
double NOTE_ADPCMB(int note) {
|
||||
if (chan[adpcmBChanOffs].sample>=0 && chan[adpcmBChanOffs].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[adpcmBChanOffs].sample)->centerRate)/8363.0;
|
||||
return parent->calcBaseFreq((double)chipClock/144,off,note,false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
void reset() {
|
||||
writeADPCMAOff=0;
|
||||
writeADPCMAOn=0;
|
||||
globalADPCMAVolume=0x3f;
|
||||
|
||||
ay->reset();
|
||||
ay->getRegisterWrites().clear();
|
||||
ay->flushWrites();
|
||||
}
|
||||
|
||||
void muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch>=adpcmBChanOffs) { // ADPCM-B
|
||||
immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6));
|
||||
}
|
||||
if (ch>=adpcmAChanOffs) { // ADPCM-A
|
||||
immWrite(0x108+(ch-adpcmAChanOffs),isMuted[ch]?0:((chan[ch].pan<<6)|chan[ch].outVol));
|
||||
return;
|
||||
}
|
||||
if (ch>=psgChanOffs) { // PSG
|
||||
ay->muteChannel(ch-psgChanOffs,mute);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool isStereo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
const void* getSampleMem(int index) {
|
||||
return index == 0 ? adpcmAMem : index == 1 ? adpcmBMem : NULL;
|
||||
}
|
||||
|
||||
size_t getSampleMemCapacity(int index) {
|
||||
return index == 0 ? 16777216 : index == 1 ? 16777216 : 0;
|
||||
}
|
||||
|
||||
size_t getSampleMemUsage(int index) {
|
||||
return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0;
|
||||
}
|
||||
|
||||
void renderSamples() {
|
||||
memset(adpcmAMem,0,getSampleMemCapacity(0));
|
||||
|
||||
size_t memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
int paddedLen=(s->lengthA+255)&(~0xff);
|
||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||
memPos=(memPos+0xfffff)&0xf00000;
|
||||
}
|
||||
if (memPos>=getSampleMemCapacity(0)) {
|
||||
logW("out of ADPCM-A memory for sample %d!",i);
|
||||
break;
|
||||
}
|
||||
if (memPos+paddedLen>=getSampleMemCapacity(0)) {
|
||||
memcpy(adpcmAMem+memPos,s->dataA,getSampleMemCapacity(0)-memPos);
|
||||
logW("out of ADPCM-A memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
|
||||
}
|
||||
s->offA=memPos;
|
||||
memPos+=paddedLen;
|
||||
}
|
||||
adpcmAMemLen=memPos+256;
|
||||
|
||||
memset(adpcmBMem,0,getSampleMemCapacity(1));
|
||||
|
||||
memPos=0;
|
||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||
DivSample* s=parent->song.sample[i];
|
||||
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||
memPos=(memPos+0xfffff)&0xf00000;
|
||||
}
|
||||
if (memPos>=getSampleMemCapacity(1)) {
|
||||
logW("out of ADPCM-B memory for sample %d!",i);
|
||||
break;
|
||||
}
|
||||
if (memPos+paddedLen>=getSampleMemCapacity(1)) {
|
||||
memcpy(adpcmBMem+memPos,s->dataB,getSampleMemCapacity(1)-memPos);
|
||||
logW("out of ADPCM-B memory for sample %d!",i);
|
||||
} else {
|
||||
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||
}
|
||||
s->offB=memPos;
|
||||
memPos+=paddedLen;
|
||||
}
|
||||
adpcmBMemLen=memPos+256;
|
||||
}
|
||||
|
||||
void setFlags(unsigned int flags) {
|
||||
switch (flags&0xff) {
|
||||
default:
|
||||
case 0x00:
|
||||
chipClock=8000000.0;
|
||||
break;
|
||||
case 0x01:
|
||||
chipClock=24167829/3;
|
||||
break;
|
||||
}
|
||||
rate=fm->sample_rate(chipClock);
|
||||
for (int i=0; i<ChanNum; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
int init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<ChanNum; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
adpcmAMem=new unsigned char[getSampleMemCapacity(0)];
|
||||
adpcmAMemLen=0;
|
||||
adpcmBMem=new unsigned char[getSampleMemCapacity(1)];
|
||||
adpcmBMemLen=0;
|
||||
iface.adpcmAMem=adpcmAMem;
|
||||
iface.adpcmBMem=adpcmBMem;
|
||||
iface.sampleBank=0;
|
||||
fm=new ymfm::ym2610b(iface);
|
||||
fm->set_fidelity(ymfm::OPN_FIDELITY_MIN);
|
||||
setFlags(flags);
|
||||
// YM2149, 2MHz
|
||||
ay=new DivPlatformAY8910(true,chipClock,32);
|
||||
ay->init(p,3,sugRate,16);
|
||||
ay->toggleRegisterDump(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void quit() {
|
||||
for (int i=0; i<ChanNum; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
ay->quit();
|
||||
delete ay;
|
||||
delete[] adpcmAMem;
|
||||
delete[] adpcmBMem;
|
||||
}
|
||||
|
||||
DivPlatformYM2610Base(int ext, int psg, int adpcmA, int adpcmB):
|
||||
DivPlatformOPN(9440540.0, 72, 32),
|
||||
extChanOffs(ext),
|
||||
psgChanOffs(psg),
|
||||
adpcmAChanOffs(adpcmA),
|
||||
adpcmBChanOffs(adpcmB) {}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -94,7 +94,7 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
|
|||
for (int i=0; i<8; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6;
|
||||
chan[i].outVol=((chan[i].vol&0xff)*MIN(chan[i].macroVolMul,chan[i].std.vol.val))/chan[i].macroVolMul;
|
||||
writeOutVol(i);
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
|
@ -122,9 +122,19 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.panL.had) { // panning
|
||||
chan[i].panning=MIN((chan[i].std.panL.val*15/16+15)/2+1,15);
|
||||
if (chan[i].isNewYMZ) {
|
||||
chan[i].panning=8+chan[i].std.panL.val;
|
||||
} else {
|
||||
chan[i].panning=MIN((chan[i].std.panL.val*15/16+15)/2+1,15);
|
||||
}
|
||||
rWrite(0x03+i*4,chan[i].panning);
|
||||
}
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if ((chan[i].std.phaseReset.val==1) && chan[i].active) {
|
||||
chan[i].audPos=0;
|
||||
chan[i].setPos=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].setPos) {
|
||||
// force keyon
|
||||
chan[i].keyOn=true;
|
||||
|
@ -207,6 +217,8 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
chan[c.chan].isNewYMZ=ins->type==DIV_INS_YMZ280B;
|
||||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255;
|
||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
|
|
|
@ -32,8 +32,9 @@ class DivPlatformYMZ280B: public DivDispatch {
|
|||
int sample, wave, ins;
|
||||
int note;
|
||||
int panning;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos, isNewYMZ;
|
||||
int vol, outVol;
|
||||
int macroVolMul;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
|
@ -56,8 +57,10 @@ class DivPlatformYMZ280B: public DivDispatch {
|
|||
keyOff(false),
|
||||
inPorta(false),
|
||||
setPos(false),
|
||||
isNewYMZ(false),
|
||||
vol(255),
|
||||
outVol(255) {}
|
||||
outVol(255),
|
||||
macroVolMul(64) {}
|
||||
};
|
||||
Channel chan[8];
|
||||
DivDispatchOscBuffer* oscBuf[8];
|
||||
|
|
|
@ -165,6 +165,7 @@ const char* cmdName[]={
|
|||
"X1_010_ENVELOPE_PERIOD",
|
||||
"X1_010_ENVELOPE_SLIDE",
|
||||
"X1_010_AUTO_ENVELOPE",
|
||||
"X1_010_SAMPLE_BANK_SLOT",
|
||||
|
||||
"WS_SWEEP_TIME",
|
||||
"WS_SWEEP_AMOUNT",
|
||||
|
@ -189,6 +190,8 @@ const char* cmdName[]={
|
|||
"DIV_CMD_SU_SYNC_PERIOD_LOW",
|
||||
"DIV_CMD_SU_SYNC_PERIOD_HIGH",
|
||||
|
||||
"ADPCMA_GLOBAL_VOLUME",
|
||||
|
||||
"ALWAYS_SET_VOLUME"
|
||||
};
|
||||
|
||||
|
|
|
@ -944,8 +944,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"},
|
||||
{"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmHardResetEffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
@ -956,8 +956,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"},
|
||||
{"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"},
|
||||
{DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmHardResetEffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
@ -1331,8 +1331,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"},
|
||||
{"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA},
|
||||
fmHardResetEffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
@ -1343,8 +1343,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"},
|
||||
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA},
|
||||
fmHardResetEffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
@ -1418,6 +1418,7 @@ void DivEngine::registerSystems() {
|
|||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
|
||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68, DIV_INS_RF5C68},
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}
|
||||
);
|
||||
|
||||
|
@ -1489,8 +1490,8 @@ void DivEngine::registerSystems() {
|
|||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16"},
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM},
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
[](int,unsigned char,unsigned char) -> bool {return false;},
|
||||
segaPCMPostEffectHandler
|
||||
);
|
||||
|
@ -1522,8 +1523,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"},
|
||||
{"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmHardResetEffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
@ -1630,8 +1631,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"},
|
||||
{"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmHardResetEffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
@ -1642,8 +1643,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"},
|
||||
{"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"},
|
||||
{DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmHardResetEffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
@ -1685,8 +1686,8 @@ void DivEngine::registerSystems() {
|
|||
{"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "ADPCM 1", "ADPCM 2", "ADPCM 3"},
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "A1", "A2", "A3"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
|
||||
{DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND, DIV_INS_QSOUND},
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
[this](int ch, unsigned char effect, unsigned char effectVal) -> bool {
|
||||
switch (effect) {
|
||||
case 0x10: // echo feedback
|
||||
|
@ -1739,8 +1740,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"},
|
||||
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmHardResetEffectHandler,
|
||||
fmPostEffectHandler
|
||||
);
|
||||
|
@ -1751,8 +1752,8 @@ void DivEngine::registerSystems() {
|
|||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"},
|
||||
{"P1", "P2", "P3", "P4", "P5"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM, DIV_INS_SEGAPCM},
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
[](int,unsigned char,unsigned char) -> bool {return false;},
|
||||
segaPCMPostEffectHandler
|
||||
);
|
||||
|
@ -1840,7 +1841,7 @@ void DivEngine::registerSystems() {
|
|||
|
||||
sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef(
|
||||
"Ensoniq ES5506", NULL, 0xb1, 0, 32, false, true, 0, false,
|
||||
"a sample chip used in the Gravis Ultrasound, popular in the PC (DOS) demoscene.",
|
||||
"a sample chip used in the Ensoniq's unique TransWave synthesizers, and SoundScape series PC ISA soundcards (which are yet another (partially) Sound Blaster compatible ones with emulated OPL3 and MIDI ROMpler).",
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"},
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
|
@ -1853,8 +1854,8 @@ void DivEngine::registerSystems() {
|
|||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "ADPCM"},
|
||||
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "P"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM},
|
||||
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_ADPCMB},
|
||||
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA},
|
||||
{},
|
||||
oplEffectHandler,
|
||||
fmOPLPostEffectHandler
|
||||
);
|
||||
|
@ -1866,7 +1867,7 @@ void DivEngine::registerSystems() {
|
|||
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "P"},
|
||||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_NULL},
|
||||
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA},
|
||||
oplEffectHandler,
|
||||
fmOPLPostEffectHandler
|
||||
);
|
||||
|
@ -1966,8 +1967,8 @@ void DivEngine::registerSystems() {
|
|||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
|
||||
{"CH1", "CH2", "CH3", "CH4"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_MSM6295, DIV_INS_MSM6295, DIV_INS_MSM6295, DIV_INS_MSM6295},
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
{},
|
||||
[this](int ch, unsigned char effect, unsigned char effectVal) -> bool {
|
||||
switch (effect) {
|
||||
case 0x20: // select rate
|
||||
|
@ -1986,8 +1987,8 @@ void DivEngine::registerSystems() {
|
|||
{"Sample"},
|
||||
{"PCM"},
|
||||
{DIV_CH_PCM},
|
||||
{DIV_INS_MSM6258},
|
||||
{DIV_INS_AMIGA},
|
||||
{},
|
||||
[this](int ch, unsigned char effect, unsigned char effectVal) -> bool {
|
||||
switch (effect) {
|
||||
case 0x20: // select rate
|
||||
|
@ -2009,6 +2010,7 @@ void DivEngine::registerSystems() {
|
|||
{"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8"},
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8"},
|
||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||
{DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B, DIV_INS_YMZ280B},
|
||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}
|
||||
);
|
||||
|
||||
|
|
|
@ -318,6 +318,38 @@ void FurnaceGUI::drawInsList() {
|
|||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL_DRUMS]);
|
||||
name=fmt::sprintf(ICON_FA_COFFEE " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_MSM6258:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM6258]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_MSM6295:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MSM6295]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_ADPCMA:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_ADPCMA]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_ADPCMB:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_ADPCMB]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_SEGAPCM:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SEGAPCM]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_QSOUND:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_QSOUND]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_YMZ280B:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_YMZ280B]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
case DIV_INS_RF5C68:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_RF5C68]);
|
||||
name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
break;
|
||||
default:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]);
|
||||
name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "../engine/platform/nes.h"
|
||||
#include "../engine/platform/c64.h"
|
||||
#include "../engine/platform/arcade.h"
|
||||
#include "../engine/platform/segapcm.h"
|
||||
#include "../engine/platform/ym2610.h"
|
||||
#include "../engine/platform/ym2610ext.h"
|
||||
#include "../engine/platform/ym2610b.h"
|
||||
|
@ -36,9 +37,12 @@
|
|||
#include "../engine/platform/tia.h"
|
||||
#include "../engine/platform/saa.h"
|
||||
#include "../engine/platform/amiga.h"
|
||||
#include "../engine/platform/qsound.h"
|
||||
#include "../engine/platform/x1_010.h"
|
||||
#include "../engine/platform/n163.h"
|
||||
#include "../engine/platform/vrc6.h"
|
||||
#include "../engine/platform/lynx.h"
|
||||
#include "../engine/platform/pcmdac.h"
|
||||
#include "../engine/platform/dummy.h"
|
||||
|
||||
#define GENESIS_DEBUG \
|
||||
|
@ -48,6 +52,7 @@
|
|||
ImGui::Text("* freq: %d",ch->freq); \
|
||||
ImGui::Text(" - base: %d",ch->baseFreq); \
|
||||
ImGui::Text(" - pitch: %d",ch->pitch); \
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2); \
|
||||
ImGui::Text("- note: %d",ch->note); \
|
||||
ImGui::Text("- ins: %d",ch->ins); \
|
||||
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||
|
@ -68,6 +73,7 @@
|
|||
ImGui::Text("* freq: %d",ch->freq); \
|
||||
ImGui::Text(" - base: %d",ch->baseFreq); \
|
||||
ImGui::Text(" - pitch: %d",ch->pitch); \
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2); \
|
||||
ImGui::Text("- note: %d",ch->note); \
|
||||
ImGui::Text("- ins: %d",ch->ins); \
|
||||
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||
|
@ -111,6 +117,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("- duty: %d",ch->duty);
|
||||
|
@ -133,17 +140,20 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("* DAC:");
|
||||
ImGui::Text(" - period: %d",ch->dacPeriod);
|
||||
ImGui::Text(" - rate: %d",ch->dacRate);
|
||||
ImGui::Text(" - pos: %d",ch->dacPos);
|
||||
ImGui::Text(" - out: %d",ch->dacOut);
|
||||
ImGui::Text(" - sample: %d",ch->dacSample);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("- pan: %.2x",ch->pan);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::Text("- wave: %d",ch->wave);
|
||||
ImGui::Text("- macroVolMul: %d",ch->macroVolMul);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
|
@ -161,6 +171,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text(" - prev: %d",ch->prevFreq);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
|
@ -185,6 +196,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text(" - prev: %d",ch->prevFreq);
|
||||
ImGui::Text("- testWhen: %d",ch->testWhen);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
|
@ -218,6 +230,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("- KOnCycles: %d",ch->konCycles);
|
||||
|
@ -231,8 +244,140 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||
ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause");
|
||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT: {
|
||||
DivPlatformSegaPCM::Channel* ch=(DivPlatformSegaPCM::Channel*)data;
|
||||
ImGui::Text("> SegaPCM");
|
||||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("* PCM:");
|
||||
ImGui::Text(" - sample: %d",ch->pcm.sample);
|
||||
ImGui::Text(" - pos: %d",ch->pcm.pos);
|
||||
ImGui::Text(" - len: %d",ch->pcm.len);
|
||||
ImGui::Text(" - freq: %d",ch->pcm.freq);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::Text("- chVolL: %.2x",ch->chVolL);
|
||||
ImGui::Text("- chVolR: %.2x",ch->chVolR);
|
||||
ImGui::Text("- chPanL: %.2x",ch->chPanL);
|
||||
ImGui::Text("- chPanR: %.2x",ch->chPanR);
|
||||
ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||
ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause");
|
||||
ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM");
|
||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
||||
ImGui::TextColored(ch->isNewSegaPCM?colorOn:colorOff,">> IsNewSegaPCM");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_AY8910: {
|
||||
DivPlatformAY8910::Channel* ch=(DivPlatformAY8910::Channel*)data;
|
||||
ImGui::Text("> AY-3-8910");
|
||||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("* psgMode:");
|
||||
ImGui::Text(" - tone: %d",ch->psgMode.tone);
|
||||
ImGui::Text(" - noise: %d",ch->psgMode.noise);
|
||||
ImGui::Text(" - envelope: %d",ch->psgMode.envelope);
|
||||
ImGui::Text(" - dac: %d",ch->psgMode.dac);
|
||||
ImGui::Text("* DAC:");
|
||||
ImGui::Text(" - sample: %d",ch->dac.sample);
|
||||
ImGui::Text(" - rate: %d",ch->dac.rate);
|
||||
ImGui::Text(" - period: %d",ch->dac.period);
|
||||
ImGui::Text(" - pos: %d",ch->dac.pos);
|
||||
ImGui::Text(" - out: %d",ch->dac.out);
|
||||
ImGui::Text("- autoEnvNum: %.2x",ch->autoEnvNum);
|
||||
ImGui::Text("- autoEnvDen: %.2x",ch->autoEnvDen);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||
ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause");
|
||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
||||
ImGui::TextColored(ch->dac.furnaceDAC?colorOn:colorOff,">> furnaceDAC");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_AY8930: {
|
||||
DivPlatformAY8930::Channel* ch=(DivPlatformAY8930::Channel*)data;
|
||||
ImGui::Text("> AY8930");
|
||||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("- duty: %d",ch->duty);
|
||||
ImGui::Text("* envelope:");
|
||||
ImGui::Text(" - mode: %d",ch->envelope.mode);
|
||||
ImGui::Text(" - period: %d",ch->envelope.period);
|
||||
ImGui::Text(" * slide: %d",ch->envelope.slide);
|
||||
ImGui::Text(" - low: %d",ch->envelope.slideLow);
|
||||
ImGui::Text("* psgMode:");
|
||||
ImGui::Text(" - tone: %d",ch->psgMode.tone);
|
||||
ImGui::Text(" - noise: %d",ch->psgMode.noise);
|
||||
ImGui::Text(" - envelope: %d",ch->psgMode.envelope);
|
||||
ImGui::Text(" - dac: %d",ch->psgMode.dac);
|
||||
ImGui::Text("* DAC:");
|
||||
ImGui::Text(" - sample: %d",ch->dac.sample);
|
||||
ImGui::Text(" - rate: %d",ch->dac.rate);
|
||||
ImGui::Text(" - period: %d",ch->dac.period);
|
||||
ImGui::Text(" - pos: %d",ch->dac.pos);
|
||||
ImGui::Text(" - out: %d",ch->dac.out);
|
||||
ImGui::Text("- autoEnvNum: %.2x",ch->autoEnvNum);
|
||||
ImGui::Text("- autoEnvDen: %.2x",ch->autoEnvDen);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||
ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause");
|
||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
||||
ImGui::TextColored(ch->dac.furnaceDAC?colorOn:colorOff,">> furnaceDAC");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_QSOUND: {
|
||||
DivPlatformQSound::Channel* ch=(DivPlatformQSound::Channel*)data;
|
||||
ImGui::Text("> QSound");
|
||||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("- sample: %d",ch->sample);
|
||||
ImGui::Text("- echo: %d",ch->echo);
|
||||
ImGui::Text("- panning: %d",ch->panning);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::Text("- resVol: %.2x",ch->resVol);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
||||
ImGui::TextColored(ch->useWave?colorOn:colorOff,">> UseWave");
|
||||
ImGui::TextColored(ch->surround?colorOn:colorOff,">> Surround");
|
||||
ImGui::TextColored(ch->isNewQSound?colorOn:colorOff,">> IsNewQSound");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_X1_010: {
|
||||
|
@ -241,6 +386,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("* freq: %.4x",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- wave: %d",ch->wave);
|
||||
ImGui::Text("- sample: %d",ch->sample);
|
||||
|
@ -254,6 +400,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text(" - autoEnvNum: %.2x",ch->autoEnvNum);
|
||||
ImGui::Text(" - autoEnvDen: %.2x",ch->autoEnvDen);
|
||||
ImGui::Text("- WaveBank: %d",ch->waveBank);
|
||||
ImGui::Text("- bankSlot: %d",ch->bankSlot);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::Text("- Lvol: %.2x",ch->lvol);
|
||||
|
@ -282,6 +429,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("* freq: %.4x",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("- wave: %d",ch->wave);
|
||||
ImGui::Text("- wavepos: %d",ch->wavePos);
|
||||
|
@ -312,6 +460,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::Text("* freq: %d",ch->freq);
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("- note: %d",ch->note);
|
||||
ImGui::Text("* DAC:");
|
||||
ImGui::Text(" - period: %d",ch->dacPeriod);
|
||||
|
@ -333,6 +482,71 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
|||
ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_LYNX: {
|
||||
DivPlatformLynx::Channel* ch=(DivPlatformLynx::Channel*)data;
|
||||
ImGui::Text("> Lynx");
|
||||
ImGui::Text("* freq:");
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("* FreqDiv:");
|
||||
ImGui::Text(" - clockDivider: %d",ch->fd.clockDivider);
|
||||
ImGui::Text(" - backup: %d",ch->fd.backup);
|
||||
ImGui::Text("* note: %d",ch->note);
|
||||
ImGui::Text(" - actualNote: %d",ch->actualNote);
|
||||
ImGui::Text("* Sample:");
|
||||
ImGui::Text(" - sample: %d",ch->sample);
|
||||
ImGui::Text(" - pos: %d",ch->samplePos);
|
||||
ImGui::Text(" - accum: %d",ch->sampleAccum);
|
||||
ImGui::Text(" * freq: %d",ch->sampleFreq);
|
||||
ImGui::Text(" - base: %d",ch->sampleBaseFreq);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("* duty:");
|
||||
ImGui::Text(" - int_feedback7: %d",ch->duty.int_feedback7);
|
||||
ImGui::Text(" - feedback: %d",ch->duty.feedback);
|
||||
ImGui::Text("- pan: %.2x",ch->pan);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||
ImGui::Text("- macroVolMul: %.2x",ch->macroVolMul);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
||||
ImGui::TextColored(ch->pcm?colorOn:colorOff,">> DAC");
|
||||
break;
|
||||
}
|
||||
case DIV_SYSTEM_PCM_DAC: {
|
||||
DivPlatformPCMDAC::Channel* ch=(DivPlatformPCMDAC::Channel*)data;
|
||||
ImGui::Text("> PCM DAC");
|
||||
ImGui::Text("* freq:");
|
||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||
ImGui::Text("* note: %d",ch->note);
|
||||
ImGui::Text("* Sample: %d",ch->sample);
|
||||
ImGui::Text(" - dir: %d",ch->audDir);
|
||||
ImGui::Text(" - loc: %d",ch->audLoc);
|
||||
ImGui::Text(" - len: %d",ch->audLen);
|
||||
ImGui::Text(" * pos: %d",ch->audPos);
|
||||
ImGui::Text(" - sub: %d",ch->audSub);
|
||||
ImGui::Text("- wave: %d",ch->wave);
|
||||
ImGui::Text("- ins: %d",ch->ins);
|
||||
ImGui::Text("- panL: %.2x",ch->panL);
|
||||
ImGui::Text("- panR: %.2x",ch->panR);
|
||||
ImGui::Text("- vol: %.2x",ch->vol);
|
||||
ImGui::Text("- envVol: %.2x",ch->envVol);
|
||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
||||
ImGui::TextColored(ch->useWave?colorOn:colorOff,">> UseWave");
|
||||
ImGui::TextColored(ch->setPos?colorOn:colorOff,">> SetPos");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ImGui::Text("Unimplemented chip! Help!");
|
||||
break;
|
||||
|
|
|
@ -155,6 +155,14 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_INSTR_SU,
|
||||
GUI_COLOR_INSTR_NAMCO,
|
||||
GUI_COLOR_INSTR_OPL_DRUMS,
|
||||
GUI_COLOR_INSTR_MSM6258,
|
||||
GUI_COLOR_INSTR_MSM6295,
|
||||
GUI_COLOR_INSTR_ADPCMA,
|
||||
GUI_COLOR_INSTR_ADPCMB,
|
||||
GUI_COLOR_INSTR_SEGAPCM,
|
||||
GUI_COLOR_INSTR_QSOUND,
|
||||
GUI_COLOR_INSTR_YMZ280B,
|
||||
GUI_COLOR_INSTR_RF5C68,
|
||||
GUI_COLOR_INSTR_UNKNOWN,
|
||||
|
||||
GUI_COLOR_CHANNEL_FM,
|
||||
|
|
|
@ -84,7 +84,7 @@ const char* insTypes[DIV_INS_MAX+1]={
|
|||
"FM (4-operator)",
|
||||
"Game Boy",
|
||||
"C64",
|
||||
"Sample",
|
||||
"Generic Sample",
|
||||
"PC Engine",
|
||||
"AY-3-8910/SSG",
|
||||
"AY8930",
|
||||
|
@ -113,6 +113,14 @@ const char* insTypes[DIV_INS_MAX+1]={
|
|||
"Sound Unit",
|
||||
"Namco WSG",
|
||||
"OPL (drums)",
|
||||
"MSM6258",
|
||||
"MSM6295",
|
||||
"ADPCM-A",
|
||||
"ADPCM-B",
|
||||
"SegaPCM",
|
||||
"QSound",
|
||||
"YMZ280B",
|
||||
"RF5C68",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -768,6 +776,14 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_NAMCO,"",ImVec4(1.0f,1.0f,0.0f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_ADPCMB,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_SEGAPCM,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_QSOUND,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_YMZ280B,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)),
|
||||
|
|
|
@ -250,6 +250,10 @@ const char* suControlBits[5]={
|
|||
"ring mod", "low pass", "high pass", "band pass", NULL
|
||||
};
|
||||
|
||||
const char* es5506FilterModes[4]={
|
||||
"HP/K2, HP/K2", "HP/K2, LP/K1", "LP/K2, LP/K2", "LP/K2, LP/K1",
|
||||
};
|
||||
|
||||
const char* panBits[3]={
|
||||
"right", "left", NULL
|
||||
};
|
||||
|
@ -258,6 +262,14 @@ const char* oneBit[2]={
|
|||
"on", NULL
|
||||
};
|
||||
|
||||
const char* es5506EnvelopeModes[3]={
|
||||
"k1 slowdown", "k2 slowdown", NULL
|
||||
};
|
||||
|
||||
const char* es5506ControlModes[2]={
|
||||
"pause", NULL
|
||||
};
|
||||
|
||||
const int orderedOps[4]={
|
||||
0, 2, 1, 3
|
||||
};
|
||||
|
@ -314,6 +326,27 @@ String macroHoverLoop(int id, float val) {
|
|||
return "";
|
||||
}
|
||||
|
||||
String macroHoverES5506FilterMode(int id, float val) {
|
||||
String mode="???";
|
||||
switch (((int)val)&3) {
|
||||
case 0:
|
||||
mode="HP/K2, HP/K2";
|
||||
break;
|
||||
case 1:
|
||||
mode="HP/K2, LP/K1";
|
||||
break;
|
||||
case 2:
|
||||
mode="LP/K2, LP/K2";
|
||||
break;
|
||||
case 3:
|
||||
mode="LP/K2, LP/K1";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return fmt::sprintf("%d: %s",id,mode);
|
||||
}
|
||||
|
||||
String macroLFOWaves(int id, float val) {
|
||||
switch (((int)val)&3) {
|
||||
case 0:
|
||||
|
@ -3174,9 +3207,9 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::EndDisabled();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ins->type==DIV_INS_C64) if (ImGui::BeginTabItem("C64")) {
|
||||
|
@ -3296,97 +3329,133 @@ void FurnaceGUI::drawInsEdit() {
|
|||
P(ImGui::Checkbox("Don't test/gate before new note",&ins->c64.noTest));
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SU) if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) {
|
||||
String sName;
|
||||
if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) {
|
||||
sName="none selected";
|
||||
} else {
|
||||
sName=e->song.sample[ins->amiga.initSample]->name;
|
||||
}
|
||||
if (ins->type==DIV_INS_SU) {
|
||||
P(ImGui::Checkbox("Use sample",&ins->su.useSample));
|
||||
P(ImGui::Checkbox("Switch roles of frequency and phase reset timer",&ins->su.switchRoles));
|
||||
}
|
||||
if (ImGui::BeginCombo("Initial Sample",sName.c_str())) {
|
||||
String id;
|
||||
for (int i=0; i<e->song.sampleLen; i++) {
|
||||
id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name);
|
||||
if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER
|
||||
ins->amiga.initSample=i;
|
||||
if (ins->type==DIV_INS_PCE ||
|
||||
ins->type==DIV_INS_MSM6258 ||
|
||||
ins->type==DIV_INS_MSM6295 ||
|
||||
ins->type==DIV_INS_ADPCMA ||
|
||||
ins->type==DIV_INS_ADPCMB ||
|
||||
ins->type==DIV_INS_SEGAPCM ||
|
||||
ins->type==DIV_INS_QSOUND ||
|
||||
ins->type==DIV_INS_YMZ280B ||
|
||||
ins->type==DIV_INS_RF5C68 ||
|
||||
ins->type==DIV_INS_AMIGA ||
|
||||
ins->type==DIV_INS_MULTIPCM ||
|
||||
ins->type==DIV_INS_MIKEY ||
|
||||
ins->type==DIV_INS_X1_010 ||
|
||||
ins->type==DIV_INS_SWAN ||
|
||||
ins->type==DIV_INS_AY ||
|
||||
ins->type==DIV_INS_AY8930 ||
|
||||
ins->type==DIV_INS_VRC6 ||
|
||||
ins->type==DIV_INS_SU ||
|
||||
ins->type==DIV_INS_SNES ||
|
||||
ins->type==DIV_INS_ES5506) {
|
||||
if (ImGui::BeginTabItem((ins->type==DIV_INS_SU)?"Sound Unit":"Sample")) {
|
||||
String sName;
|
||||
if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) {
|
||||
sName="none selected";
|
||||
} else {
|
||||
sName=e->song.sample[ins->amiga.initSample]->name;
|
||||
}
|
||||
if (ins->type==DIV_INS_PCE ||
|
||||
ins->type==DIV_INS_MIKEY ||
|
||||
ins->type==DIV_INS_X1_010 ||
|
||||
ins->type==DIV_INS_SWAN ||
|
||||
ins->type==DIV_INS_AY ||
|
||||
ins->type==DIV_INS_AY8930 ||
|
||||
ins->type==DIV_INS_VRC6 ||
|
||||
ins->type==DIV_INS_SU) {
|
||||
P(ImGui::Checkbox("Use sample",&ins->amiga.useSample));
|
||||
if (ins->type==DIV_INS_SU) {
|
||||
P(ImGui::Checkbox("Switch roles of frequency and phase reset timer",&ins->su.switchRoles));
|
||||
}
|
||||
if (ins->type==DIV_INS_X1_010) {
|
||||
if (ImGui::InputInt("Sample bank slot##BANKSLOT",&ins->x1_010.bankSlot,1,4)) { PARAMETER
|
||||
if (ins->x1_010.bankSlot<0) ins->x1_010.bankSlot=0;
|
||||
if (ins->x1_010.bankSlot>=7) ins->x1_010.bankSlot=7;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave));
|
||||
if (ins->amiga.useWave) {
|
||||
int len=ins->amiga.waveLen+1;
|
||||
if (ImGui::InputInt("Width",&len,2,16)) {
|
||||
if (len<2) len=2;
|
||||
if (len>256) len=256;
|
||||
ins->amiga.waveLen=(len&(~1))-1;
|
||||
PARAMETER
|
||||
if (ImGui::BeginCombo("Initial Sample",sName.c_str())) {
|
||||
String id;
|
||||
for (int i=0; i<e->song.sampleLen; i++) {
|
||||
id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name);
|
||||
if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER
|
||||
ins->amiga.initSample=i;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
P(ImGui::Checkbox("Use wavetable (Amiga only)",&ins->amiga.useWave));
|
||||
if (ins->amiga.useWave) {
|
||||
int len=ins->amiga.waveLen+1;
|
||||
if (ImGui::InputInt("Width",&len,2,16)) {
|
||||
if (len<2) len=2;
|
||||
if (len>256) len=256;
|
||||
ins->amiga.waveLen=(len&(~1))-1;
|
||||
PARAMETER
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::BeginDisabled(ins->amiga.useWave);
|
||||
P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap));
|
||||
if (ins->amiga.useNoteMap) {
|
||||
// TODO: frequency map?
|
||||
if (ImGui::BeginTable("NoteMap",2,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch);
|
||||
//ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::BeginDisabled(ins->amiga.useWave);
|
||||
P(ImGui::Checkbox("Use sample map (does not work yet!)",&ins->amiga.useNoteMap));
|
||||
if (ins->amiga.useNoteMap) {
|
||||
// TODO: frequency map?
|
||||
if (ImGui::BeginTable("NoteMap",2,ImGuiTableFlags_ScrollY|ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch);
|
||||
//ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableSetupScrollFreeze(0,1);
|
||||
ImGui::TableSetupScrollFreeze(0,1);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Sample");
|
||||
/*ImGui::TableNextColumn();
|
||||
ImGui::Text("Frequency");*/
|
||||
for (int i=0; i<120; i++) {
|
||||
DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i];
|
||||
ImGui::TableNextRow();
|
||||
ImGui::PushID(fmt::sprintf("NM_%d",i).c_str());
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",noteNames[60+i]);
|
||||
ImGui::TableNextColumn();
|
||||
if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) {
|
||||
sName="-- empty --";
|
||||
sampleMap.map=-1;
|
||||
} else {
|
||||
sName=e->song.sample[sampleMap.map]->name;
|
||||
}
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::BeginCombo("##SM",sName.c_str())) {
|
||||
String id;
|
||||
if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER
|
||||
sampleMap.map=-1;
|
||||
}
|
||||
for (int j=0; j<e->song.sampleLen; j++) {
|
||||
id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name);
|
||||
if (ImGui::Selectable(id.c_str(),sampleMap.map==j)) { PARAMETER
|
||||
sampleMap.map=j;
|
||||
if (sampleMap.freq<=0) sampleMap.freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0));
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::Text("Sample");
|
||||
/*ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##SF",&sampleMap.freq,50,500)) { PARAMETER
|
||||
if (sampleMap.freq<0) sampleMap.freq=0;
|
||||
if (sampleMap.freq>262144) sampleMap.freq=262144;
|
||||
}*/
|
||||
ImGui::PopID();
|
||||
ImGui::Text("Frequency");*/
|
||||
for (int i=0; i<120; i++) {
|
||||
DivInstrumentAmiga::SampleMap& sampleMap=ins->amiga.noteMap[i];
|
||||
ImGui::TableNextRow();
|
||||
ImGui::PushID(fmt::sprintf("NM_%d",i).c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",noteNames[60+i]);
|
||||
ImGui::TableNextColumn();
|
||||
if (sampleMap.map<0 || sampleMap.map>=e->song.sampleLen) {
|
||||
sName="-- empty --";
|
||||
sampleMap.map=-1;
|
||||
} else {
|
||||
sName=e->song.sample[sampleMap.map]->name;
|
||||
}
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::BeginCombo("##SM",sName.c_str())) {
|
||||
String id;
|
||||
if (ImGui::Selectable("-- empty --",sampleMap.map==-1)) { PARAMETER
|
||||
sampleMap.map=-1;
|
||||
}
|
||||
for (int j=0; j<e->song.sampleLen; j++) {
|
||||
id=fmt::sprintf("%d: %s",j,e->song.sample[j]->name);
|
||||
if (ImGui::Selectable(id.c_str(),sampleMap.map==j)) { PARAMETER
|
||||
sampleMap.map=j;
|
||||
if (sampleMap.freq<=0) sampleMap.freq=(int)((double)e->song.sample[j]->centerRate*pow(2.0,((double)i-48.0)/12.0));
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
/*ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##SF",&sampleMap.freq,50,500)) { PARAMETER
|
||||
if (sampleMap.freq<0) sampleMap.freq=0;
|
||||
if (sampleMap.freq>262144) sampleMap.freq=262144;
|
||||
}*/
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem(settings.c163Name.c_str())) {
|
||||
if (ImGui::InputInt("Waveform##WAVE",&ins->n163.wave,1,10)) { PARAMETER
|
||||
|
@ -3453,25 +3522,44 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ins->type==DIV_INS_ES5506) if (ImGui::BeginTabItem("ES5506")) {
|
||||
if (ImGui::BeginTable("ESParams",2,ImGuiTableFlags_SizingStretchSame)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
// filter
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Filter 4,3 Mode",ImGuiDataType_U8,&ins->es5506.filter.mode,&_ZERO,&_THREE,es5506FilterModes[ins->es5506.filter.mode&3])); rightClickable
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Filter K1",ImGuiDataType_U16,&ins->es5506.filter.k1,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Filter K2",ImGuiDataType_U16,&ins->es5506.filter.k2,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable
|
||||
// envelope
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Envelope count",ImGuiDataType_U16,&ins->es5506.envelope.ecount,&_ZERO,&_FIVE_HUNDRED_ELEVEN)); rightClickable
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Left Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.lVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Right Volume Ramp",ImGuiDataType_S8,&ins->es5506.envelope.rVRamp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Filter K1 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k1Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(CWSliderScalar("Filter K2 Ramp",ImGuiDataType_S8,&ins->es5506.envelope.k2Ramp,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN)); rightClickable
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("K1 Ramp Slowdown",&ins->es5506.envelope.k1Slow);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("K2 Ramp Slowdown",&ins->es5506.envelope.k2Slow);
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ins->type==DIV_INS_MULTIPCM) {
|
||||
if (ImGui::BeginTabItem("MultiPCM")) {
|
||||
String sName;
|
||||
if (ins->amiga.initSample<0 || ins->amiga.initSample>=e->song.sampleLen) {
|
||||
sName="none selected";
|
||||
} else {
|
||||
sName=e->song.sample[ins->amiga.initSample]->name;
|
||||
}
|
||||
if (ImGui::BeginCombo("Initial Sample",sName.c_str())) {
|
||||
String id;
|
||||
for (int i=0; i<e->song.sampleLen; i++) {
|
||||
id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name);
|
||||
if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) {
|
||||
ins->amiga.initSample=i;
|
||||
PARAMETER
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale);
|
||||
if (ImGui::BeginTable("MultiPCMADSRParams",7,ImGuiTableFlags_NoHostExtendX)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x);
|
||||
|
@ -3555,14 +3643,110 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
if (ins->type==DIV_INS_SNES) if (ImGui::BeginTabItem("SNES")) {
|
||||
P(ImGui::Checkbox("Use envelope",&ins->snes.useEnv));
|
||||
ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale);
|
||||
if (ins->snes.useEnv) {
|
||||
if (ImGui::BeginTable("SNESEnvParams",5,ImGuiTableFlags_NoHostExtendX)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x);
|
||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x);
|
||||
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x);
|
||||
ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_TEXT("A");
|
||||
ImGui::TextUnformatted("A");
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_TEXT("D");
|
||||
ImGui::TextUnformatted("D");
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_TEXT("S");
|
||||
ImGui::TextUnformatted("S");
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_TEXT("R");
|
||||
ImGui::TextUnformatted("R");
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_TEXT("Envelope");
|
||||
ImGui::TextUnformatted("Envelope");
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->snes.a,&_ZERO,&_FIFTEEN));
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->snes.d,&_ZERO,&_SEVEN));
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->snes.s,&_ZERO,&_SEVEN));
|
||||
ImGui::TableNextColumn();
|
||||
P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE));
|
||||
ImGui::TableNextColumn();
|
||||
drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.r,ins->snes.r,(14-ins->snes.s*2),(ins->snes.r==0),0,0,7,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
} else {
|
||||
if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x);
|
||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_TEXT("Gain Mode");
|
||||
ImGui::TextUnformatted("Gain Mode");
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_TEXT("Gain");
|
||||
ImGui::TextUnformatted("Gain");
|
||||
ImGui::TableNextColumn();
|
||||
CENTER_TEXT("Envelope");
|
||||
ImGui::TextUnformatted("Envelope");
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::RadioButton("Direct",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)) {
|
||||
ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT;
|
||||
PARAMETER;
|
||||
}
|
||||
if (ImGui::RadioButton("Decrease (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR)) {
|
||||
ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR;
|
||||
PARAMETER;
|
||||
}
|
||||
if (ImGui::RadioButton("Decrease (logarithmic)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG)) {
|
||||
ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG;
|
||||
PARAMETER;
|
||||
}
|
||||
if (ImGui::RadioButton("Increase (linear)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_LINEAR)) {
|
||||
ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR;
|
||||
PARAMETER;
|
||||
}
|
||||
if (ImGui::RadioButton("Increase (bent line)",ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_INC_INVLOG)) {
|
||||
ins->snes.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG;
|
||||
PARAMETER;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
unsigned char gainMax=(ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT)?127:31;
|
||||
if (ins->snes.gain>gainMax) ins->snes.gain=gainMax;
|
||||
P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax));
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Envelope goes here...");
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ins->type==DIV_INS_GB ||
|
||||
(ins->type==DIV_INS_AMIGA && ins->amiga.useWave) ||
|
||||
ins->type==DIV_INS_X1_010 ||
|
||||
(ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) ||
|
||||
ins->type==DIV_INS_N163 ||
|
||||
ins->type==DIV_INS_FDS ||
|
||||
ins->type==DIV_INS_SWAN ||
|
||||
ins->type==DIV_INS_PCE ||
|
||||
(ins->type==DIV_INS_SWAN && !ins->amiga.useSample) ||
|
||||
(ins->type==DIV_INS_PCE && !ins->amiga.useSample) ||
|
||||
ins->type==DIV_INS_SCC ||
|
||||
ins->type==DIV_INS_SNES ||
|
||||
ins->type==DIV_INS_NAMCO) {
|
||||
if (ImGui::BeginTabItem("Wavetable")) {
|
||||
if (ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled)) {
|
||||
|
@ -3725,7 +3909,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if ((ins->type==DIV_INS_PCE || ins->type==DIV_INS_AY8930)) {
|
||||
if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_AY8930) {
|
||||
volMax=31;
|
||||
}
|
||||
if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VERA || ins->type==DIV_INS_VRC6_SAW) {
|
||||
|
@ -3734,7 +3918,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_AMIGA) {
|
||||
volMax=64;
|
||||
}
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU) {
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_SEGAPCM || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_SU || ins->type==DIV_INS_OPZ) {
|
||||
volMax=127;
|
||||
}
|
||||
if (ins->type==DIV_INS_GB) {
|
||||
|
@ -3750,6 +3934,24 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_FDS) {
|
||||
volMax=32;
|
||||
}
|
||||
if (ins->type==DIV_INS_ES5506) {
|
||||
volMax=65535;
|
||||
}
|
||||
if (ins->type==DIV_INS_MSM6258) {
|
||||
volMax=0;
|
||||
}
|
||||
if (ins->type==DIV_INS_MSM6295) {
|
||||
volMax=8;
|
||||
}
|
||||
if (ins->type==DIV_INS_ADPCMA) {
|
||||
volMax=31;
|
||||
}
|
||||
if (ins->type==DIV_INS_ADPCMB || ins->type==DIV_INS_YMZ280B || ins->type==DIV_INS_RF5C68) {
|
||||
volMax=255;
|
||||
}
|
||||
if (ins->type==DIV_INS_QSOUND) {
|
||||
volMax=16383;
|
||||
}
|
||||
|
||||
const char* dutyLabel="Duty/Noise";
|
||||
int dutyMin=0;
|
||||
|
@ -3766,33 +3968,33 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_FM) {
|
||||
dutyMax=32;
|
||||
}
|
||||
if ((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)) {
|
||||
dutyMax=31;
|
||||
if (ins->type==DIV_INS_AY) {
|
||||
dutyMax=ins->amiga.useSample?0:31;
|
||||
}
|
||||
if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_FM) {
|
||||
dutyLabel="Noise Freq";
|
||||
}
|
||||
if (ins->type==DIV_INS_MIKEY) {
|
||||
dutyLabel="Duty/Int";
|
||||
dutyMax=10;
|
||||
dutyMax=ins->amiga.useSample?0:10;
|
||||
}
|
||||
if (ins->type==DIV_INS_BEEPER) {
|
||||
dutyLabel="Pulse Width";
|
||||
dutyMax=255;
|
||||
}
|
||||
if (ins->type==DIV_INS_AY8930) {
|
||||
dutyMax=255;
|
||||
dutyMax=ins->amiga.useSample?0:255;
|
||||
}
|
||||
if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC) {
|
||||
if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_SCC || ins->type==DIV_INS_PET || ins->type==DIV_INS_VIC || ins->type==DIV_INS_SEGAPCM) {
|
||||
dutyMax=0;
|
||||
}
|
||||
if (ins->type==DIV_INS_PCE || ins->type==DIV_INS_NAMCO) {
|
||||
if ((ins->type==DIV_INS_PCE && !ins->amiga.useSample) || ins->type==DIV_INS_NAMCO) {
|
||||
dutyLabel="Noise";
|
||||
dutyMax=1;
|
||||
dutyMax=(ins->type==DIV_INS_PCE && !ins->amiga.useSample)?0:1;
|
||||
}
|
||||
if (ins->type==DIV_INS_SWAN) {
|
||||
dutyLabel="Noise";
|
||||
dutyMax=8;
|
||||
dutyMax=ins->amiga.useSample?0:8;
|
||||
}
|
||||
if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) {
|
||||
dutyMax=0;
|
||||
|
@ -3807,19 +4009,42 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
if (ins->type==DIV_INS_VRC6) {
|
||||
dutyLabel="Duty";
|
||||
dutyMax=7;
|
||||
dutyMax=ins->amiga.useSample?0:7;
|
||||
}
|
||||
if (ins->type==DIV_INS_SU) {
|
||||
dutyMax=127;
|
||||
}
|
||||
if (ins->type==DIV_INS_ES5506) {
|
||||
dutyLabel="Filter Mode";
|
||||
dutyMax=3;
|
||||
}
|
||||
if (ins->type==DIV_INS_MSM6258) {
|
||||
dutyLabel="Frequency Divider";
|
||||
dutyMax=2;
|
||||
}
|
||||
if (ins->type==DIV_INS_MSM6295) {
|
||||
dutyLabel="Frequency Divider";
|
||||
dutyMax=1;
|
||||
}
|
||||
if (ins->type==DIV_INS_ADPCMA) {
|
||||
dutyLabel="Global Volume";
|
||||
dutyMax=63;
|
||||
}
|
||||
if (ins->type==DIV_INS_ADPCMB || ins->type==DIV_INS_YMZ280B || ins->type==DIV_INS_RF5C68) {
|
||||
dutyMax=0;
|
||||
}
|
||||
if (ins->type==DIV_INS_QSOUND) {
|
||||
dutyLabel="Echo Level";
|
||||
dutyMax=32767;
|
||||
}
|
||||
|
||||
const char* waveLabel="Waveform";
|
||||
int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:255;
|
||||
bool bitMode=false;
|
||||
if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) {
|
||||
bitMode=true;
|
||||
int waveMax=(ins->type==DIV_INS_VERA)?3:255;
|
||||
bool waveBitMode=false;
|
||||
if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_SAA1099) {
|
||||
waveBitMode=true;
|
||||
}
|
||||
if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6 || ins->type==DIV_INS_VRC6_SAW) waveMax=0;
|
||||
if (ins->type==DIV_INS_STD || ins->type==DIV_INS_VRC6_SAW) waveMax=0;
|
||||
if (ins->type==DIV_INS_TIA || ins->type==DIV_INS_VIC || ins->type==DIV_INS_OPLL) waveMax=15;
|
||||
if (ins->type==DIV_INS_C64) waveMax=4;
|
||||
if (ins->type==DIV_INS_SAA1099) waveMax=2;
|
||||
|
@ -3829,13 +4054,21 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_SU) waveMax=7;
|
||||
if (ins->type==DIV_INS_PET) {
|
||||
waveMax=8;
|
||||
bitMode=true;
|
||||
waveBitMode=true;
|
||||
}
|
||||
if (ins->type==DIV_INS_VRC6) {
|
||||
waveMax=ins->amiga.useSample?255:0;
|
||||
}
|
||||
|
||||
if (ins->type==DIV_INS_OPLL) {
|
||||
waveLabel="Patch";
|
||||
}
|
||||
|
||||
if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) {
|
||||
waveMax=ins->amiga.useSample?255:3;
|
||||
waveBitMode=ins->amiga.useSample?false:true;
|
||||
}
|
||||
|
||||
const char** waveNames=NULL;
|
||||
if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) waveNames=ayShapeBits;
|
||||
if (ins->type==DIV_INS_C64) waveNames=c64ShapeBits;
|
||||
|
@ -3850,8 +4083,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
if (ins->type==DIV_INS_X1_010) {
|
||||
dutyMax=0;
|
||||
ex1Max=7;
|
||||
ex2Max=255;
|
||||
ex1Max=ins->amiga.useSample?0:7;
|
||||
ex2Max=ins->amiga.useSample?0:255;
|
||||
ex2Bit=false;
|
||||
}
|
||||
if (ins->type==DIV_INS_N163) {
|
||||
|
@ -3866,7 +4099,18 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ex1Max=16383;
|
||||
ex2Max=255;
|
||||
}
|
||||
if (ins->type==DIV_INS_MSM6258) {
|
||||
ex1Max=1;
|
||||
}
|
||||
if (ins->type==DIV_INS_QSOUND) {
|
||||
ex1Max=16383;
|
||||
ex2Max=2725;
|
||||
}
|
||||
if (ins->type==DIV_INS_SAA1099) ex1Max=8;
|
||||
if (ins->type==DIV_INS_ES5506) {
|
||||
ex1Max=65535;
|
||||
ex2Max=65535;
|
||||
}
|
||||
|
||||
int panMin=0;
|
||||
int panMax=0;
|
||||
|
@ -3878,21 +4122,34 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ins->type==DIV_INS_OPL_DRUMS ||
|
||||
ins->type==DIV_INS_GB ||
|
||||
ins->type==DIV_INS_OPZ ||
|
||||
ins->type==DIV_INS_VERA) {
|
||||
ins->type==DIV_INS_MSM6258 ||
|
||||
ins->type==DIV_INS_VERA ||
|
||||
ins->type==DIV_INS_ADPCMA ||
|
||||
ins->type==DIV_INS_ADPCMB) {
|
||||
panMax=1;
|
||||
panSingle=true;
|
||||
}
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
panMax=127;
|
||||
}
|
||||
if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099 || ins->type==DIV_INS_NAMCO) {
|
||||
if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099 || ins->type==DIV_INS_NAMCO || ins->type==DIV_INS_RF5C68) {
|
||||
panMax=15;
|
||||
}
|
||||
if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) {
|
||||
if (ins->type==DIV_INS_SEGAPCM) {
|
||||
panMax=127;
|
||||
}
|
||||
if (ins->type==DIV_INS_AMIGA) {
|
||||
if (ins->std.panLMacro.mode) {
|
||||
panMin=-16;
|
||||
panMax=16;
|
||||
} else {
|
||||
panMin=0;
|
||||
panMax=127;
|
||||
}
|
||||
}
|
||||
if (ins->type==DIV_INS_QSOUND) {
|
||||
panMin=-16;
|
||||
panMax=16;
|
||||
panSingleNoBit=true;
|
||||
}
|
||||
if (ins->type==DIV_INS_MULTIPCM) {
|
||||
if (ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_YMZ280B) {
|
||||
panMin=-7;
|
||||
panMax=7;
|
||||
panSingleNoBit=true;
|
||||
|
@ -3902,6 +4159,9 @@ void FurnaceGUI::drawInsEdit() {
|
|||
panMax=127;
|
||||
panSingleNoBit=true;
|
||||
}
|
||||
if (ins->type==DIV_INS_ES5506) {
|
||||
panMax=65535;
|
||||
}
|
||||
|
||||
if (volMax>0) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
||||
|
@ -3910,27 +4170,32 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (dutyMax>0) {
|
||||
if (ins->type==DIV_INS_MIKEY) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,0,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,mikeyFeedbackBits));
|
||||
} else if (ins->type==DIV_INS_ES5506) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,¯oHoverES5506FilterMode));
|
||||
} else {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,dutyMin,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
}
|
||||
}
|
||||
if (waveMax>0) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(bitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,bitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0)));
|
||||
macroList.push_back(FurnaceGUIMacroDesc(waveLabel,&ins->std.waveMacro,0,waveMax,(waveBitMode && ins->type!=DIV_INS_PET)?64:160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,waveBitMode,waveNames,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0)));
|
||||
}
|
||||
if (panMax>0) {
|
||||
if (panSingle) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,panBits));
|
||||
} else if (ins->type==DIV_INS_QSOUND) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||
} else {
|
||||
if (panSingleNoBit || (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode)) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Panning",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL));
|
||||
} else {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Panning (left)",&ins->std.panLMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER],false,(ins->type==DIV_INS_AMIGA)?macroQSoundMode:NULL));
|
||||
}
|
||||
if (!panSingleNoBit) {
|
||||
if (ins->type==DIV_INS_AMIGA && ins->std.panLMacro.mode) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Surround",&ins->std.panRMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||
} else {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,(31+panMax-panMin),uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Panning (right)",&ins->std.panRMacro,panMin,panMax,CLAMP(31+panMax-panMin,32,160),uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3943,14 +4208,25 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ins->type==DIV_INS_OPZ ||
|
||||
ins->type==DIV_INS_PCE ||
|
||||
ins->type==DIV_INS_GB ||
|
||||
ins->type==DIV_INS_MSM6258 ||
|
||||
ins->type==DIV_INS_MSM6295 ||
|
||||
ins->type==DIV_INS_ADPCMA ||
|
||||
ins->type==DIV_INS_ADPCMB ||
|
||||
ins->type==DIV_INS_SEGAPCM ||
|
||||
ins->type==DIV_INS_QSOUND ||
|
||||
ins->type==DIV_INS_YMZ280B ||
|
||||
ins->type==DIV_INS_RF5C68 ||
|
||||
ins->type==DIV_INS_AMIGA ||
|
||||
ins->type==DIV_INS_OPLL ||
|
||||
ins->type==DIV_INS_AY ||
|
||||
ins->type==DIV_INS_AY8930 ||
|
||||
ins->type==DIV_INS_SWAN ||
|
||||
ins->type==DIV_INS_MULTIPCM ||
|
||||
(ins->type==DIV_INS_VRC6 && ins->amiga.useSample) ||
|
||||
ins->type==DIV_INS_SU ||
|
||||
ins->type==DIV_INS_MIKEY) {
|
||||
ins->type==DIV_INS_MIKEY ||
|
||||
ins->type==DIV_INS_ES5506 ||
|
||||
(ins->type==DIV_INS_X1_010 && ins->amiga.useSample)) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||
}
|
||||
if (ex1Max>0) {
|
||||
|
@ -3958,7 +4234,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc("Filter Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,filtModeBits));
|
||||
} else if (ins->type==DIV_INS_SAA1099) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,saaEnvBits));
|
||||
} else if (ins->type==DIV_INS_X1_010) {
|
||||
} else if (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope Mode",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,x1_010EnvBits));
|
||||
} else if (ins->type==DIV_INS_N163) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Wave Length",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
|
@ -3966,6 +4242,12 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc("Mod Depth",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else if (ins->type==DIV_INS_SU) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Cutoff",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else if (ins->type==DIV_INS_ES5506) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Filter K1",&ins->std.ex1Macro,((ins->std.ex1Macro.mode==1)?(-ex1Max):0),ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode));
|
||||
} else if (ins->type==DIV_INS_MSM6258) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Clock Divider",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else if (ins->type==DIV_INS_QSOUND) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Echo Feedback",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
}
|
||||
|
@ -3979,6 +4261,10 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc("Mod Speed",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else if (ins->type==DIV_INS_SU) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Resonance",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else if (ins->type==DIV_INS_ES5506) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Filter K2",&ins->std.ex2Macro,((ins->std.ex2Macro.mode==1)?(-ex2Max):0),ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER],false,macroRelativeMode));
|
||||
} else if (ins->type==DIV_INS_QSOUND) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Echo Buffer Len",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
} else {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits));
|
||||
}
|
||||
|
@ -3987,7 +4273,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex3Macro,0,2,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,c64SpecialBits));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Test/Gate",&ins->std.ex4Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||
}
|
||||
if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) {
|
||||
if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || (ins->type==DIV_INS_X1_010 && !ins->amiga.useSample)) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Num",&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("AutoEnv Den",&ins->std.algMacro,0,15,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
}
|
||||
|
@ -4009,6 +4295,15 @@ void FurnaceGUI::drawInsEdit() {
|
|||
macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.ex3Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,suControlBits));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Phase Reset Timer",&ins->std.ex4Macro,0,65535,160,uiColors[GUI_COLOR_MACRO_OTHER])); // again reuse code from resonance macro but use ex4 instead
|
||||
}
|
||||
if (ins->type==DIV_INS_ES5506) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope counter",&ins->std.ex3Macro,0,511,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope left volume ramp",&ins->std.ex4Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope right volume ramp",&ins->std.ex5Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope K1 ramp",&ins->std.ex6Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope K2 ramp",&ins->std.ex7Macro,-128,127,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506EnvelopeModes));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes));
|
||||
}
|
||||
|
||||
drawMacros(macroList);
|
||||
ImGui::EndTabItem();
|
||||
|
|
|
@ -31,6 +31,9 @@ const int _SIXTY_FOUR=64;
|
|||
const int _ONE_HUNDRED=100;
|
||||
const int _ONE_HUNDRED_TWENTY_SEVEN=127;
|
||||
const int _TWO_HUNDRED_FIFTY_FIVE=255;
|
||||
const int _FIVE_HUNDRED_ELEVEN=511;
|
||||
const int _TWO_THOUSAND_FORTY_SEVEN=2047;
|
||||
const int _FOUR_THOUSAND_NINETY_FIVE=4095;
|
||||
const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE=65535;
|
||||
const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN=-127;
|
||||
const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT=-128;
|
||||
|
|
|
@ -33,6 +33,9 @@ extern const int _SIXTY_FOUR;
|
|||
extern const int _ONE_HUNDRED;
|
||||
extern const int _ONE_HUNDRED_TWENTY_SEVEN;
|
||||
extern const int _TWO_HUNDRED_FIFTY_FIVE;
|
||||
extern const int _FIVE_HUNDRED_ELEVEN;
|
||||
extern const int _TWO_THOUSAND_FORTY_SEVEN;
|
||||
extern const int _FOUR_THOUSAND_NINETY_FIVE;
|
||||
extern const int _SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE;
|
||||
extern const int _MINUS_ONE_HUNDRED_TWENTY_SEVEN;
|
||||
extern const int _MINUS_ONE_HUNDRED_TWENTY_EIGHT;
|
||||
|
|
|
@ -1485,7 +1485,7 @@ void FurnaceGUI::drawSettings() {
|
|||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"Standard");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_GB,"Game Boy");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_C64,"C64");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Sample");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Generic Sample");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_PCE,"PC Engine");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY,"AY-3-8910/SSG");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY8930,"AY8930");
|
||||
|
@ -1517,6 +1517,15 @@ void FurnaceGUI::drawSettings() {
|
|||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SNES,"SNES");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_NAMCO,"Namco WSG");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL_DRUMS,"FM (OPL Drums)");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6258,"MSM6258");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_MSM6295,"MSM6295");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_ADPCMA,"ADPCM-A");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_ADPCMB,"ADPCM-B");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SEGAPCM,"Sega PCM");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_QSOUND,"QSound");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_YMZ280B,"YMZ280B");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_RF5C68,"RF5C68");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue