mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-30 08:23:01 +00:00
Merge pull request #653 from tildearrow/sample_macro
Improvement sample-related stuffs
This commit is contained in:
commit
185a37de3f
103 changed files with 4115 additions and 1596 deletions
|
@ -165,6 +165,7 @@ enum DivDispatchCmds {
|
||||||
DIV_CMD_X1_010_ENVELOPE_PERIOD,
|
DIV_CMD_X1_010_ENVELOPE_PERIOD,
|
||||||
DIV_CMD_X1_010_ENVELOPE_SLIDE,
|
DIV_CMD_X1_010_ENVELOPE_SLIDE,
|
||||||
DIV_CMD_X1_010_AUTO_ENVELOPE,
|
DIV_CMD_X1_010_AUTO_ENVELOPE,
|
||||||
|
DIV_CMD_X1_010_SAMPLE_BANK_SLOT,
|
||||||
|
|
||||||
DIV_CMD_WS_SWEEP_TIME,
|
DIV_CMD_WS_SWEEP_TIME,
|
||||||
DIV_CMD_WS_SWEEP_AMOUNT,
|
DIV_CMD_WS_SWEEP_AMOUNT,
|
||||||
|
@ -189,6 +190,8 @@ enum DivDispatchCmds {
|
||||||
DIV_CMD_SU_SYNC_PERIOD_LOW,
|
DIV_CMD_SU_SYNC_PERIOD_LOW,
|
||||||
DIV_CMD_SU_SYNC_PERIOD_HIGH,
|
DIV_CMD_SU_SYNC_PERIOD_HIGH,
|
||||||
|
|
||||||
|
DIV_CMD_ADPCMA_GLOBAL_VOLUME,
|
||||||
|
|
||||||
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
||||||
|
|
||||||
DIV_CMD_MAX
|
DIV_CMD_MAX
|
||||||
|
|
|
@ -1013,6 +1013,7 @@ void DivEngine::renderSamplesP() {
|
||||||
void DivEngine::renderSamples() {
|
void DivEngine::renderSamples() {
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
|
|
||||||
// step 1: render samples
|
// step 1: render samples
|
||||||
for (int i=0; i<song.sampleLen; i++) {
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
|
@ -1863,6 +1864,7 @@ void DivEngine::play() {
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.wave=-1;
|
sPreview.wave=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
if (stepPlay==0) {
|
if (stepPlay==0) {
|
||||||
freelance=false;
|
freelance=false;
|
||||||
playSub(false);
|
playSub(false);
|
||||||
|
@ -1885,6 +1887,7 @@ void DivEngine::playToRow(int row) {
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.wave=-1;
|
sPreview.wave=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
freelance=false;
|
freelance=false;
|
||||||
playSub(false,row);
|
playSub(false,row);
|
||||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||||
|
@ -1922,6 +1925,7 @@ void DivEngine::stop() {
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.wave=-1;
|
sPreview.wave=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
disCont[i].dispatch->notifyPlaybackStop();
|
disCont[i].dispatch->notifyPlaybackStop();
|
||||||
}
|
}
|
||||||
|
@ -2099,9 +2103,11 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) {
|
||||||
BUSY_BEGIN;
|
BUSY_BEGIN;
|
||||||
sPreview.pBegin=pStart;
|
sPreview.pBegin=pStart;
|
||||||
sPreview.pEnd=pEnd;
|
sPreview.pEnd=pEnd;
|
||||||
|
sPreview.dir=false;
|
||||||
if (sample<0 || sample>=(int)song.sample.size()) {
|
if (sample<0 || sample>=(int)song.sample.size()) {
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
BUSY_END;
|
BUSY_END;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2117,6 +2123,7 @@ void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) {
|
||||||
sPreview.pos=(sPreview.pBegin>=0)?sPreview.pBegin:0;
|
sPreview.pos=(sPreview.pBegin>=0)?sPreview.pBegin:0;
|
||||||
sPreview.sample=sample;
|
sPreview.sample=sample;
|
||||||
sPreview.wave=-1;
|
sPreview.wave=-1;
|
||||||
|
sPreview.dir=false;
|
||||||
BUSY_END;
|
BUSY_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2124,6 +2131,7 @@ void DivEngine::stopSamplePreview() {
|
||||||
BUSY_BEGIN;
|
BUSY_BEGIN;
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
BUSY_END;
|
BUSY_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2132,6 +2140,7 @@ void DivEngine::previewWave(int wave, int note) {
|
||||||
if (wave<0 || wave>=(int)song.wave.size()) {
|
if (wave<0 || wave>=(int)song.wave.size()) {
|
||||||
sPreview.wave=-1;
|
sPreview.wave=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
BUSY_END;
|
BUSY_END;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2147,6 +2156,7 @@ void DivEngine::previewWave(int wave, int note) {
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.wave=wave;
|
sPreview.wave=wave;
|
||||||
|
sPreview.dir=false;
|
||||||
BUSY_END;
|
BUSY_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2154,6 +2164,7 @@ void DivEngine::stopWavePreview() {
|
||||||
BUSY_BEGIN;
|
BUSY_BEGIN;
|
||||||
sPreview.wave=-1;
|
sPreview.wave=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
BUSY_END;
|
BUSY_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2580,6 +2591,7 @@ int DivEngine::addSample() {
|
||||||
song.sampleLen=sampleCount+1;
|
song.sampleLen=sampleCount+1;
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
saveLock.unlock();
|
saveLock.unlock();
|
||||||
renderSamples();
|
renderSamples();
|
||||||
BUSY_END;
|
BUSY_END;
|
||||||
|
@ -2809,13 +2821,17 @@ DivSample* DivEngine::sampleFromFile(const char* path) {
|
||||||
inst.detune = inst.detune - 100;
|
inst.detune = inst.detune - 100;
|
||||||
short pitch = ((0x3c-inst.basenote)*100) + inst.detune;
|
short pitch = ((0x3c-inst.basenote)*100) + inst.detune;
|
||||||
sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0));
|
sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0));
|
||||||
if(inst.loop_count && inst.loops[0].mode == SF_LOOP_FORWARD)
|
if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD)
|
||||||
{
|
{
|
||||||
|
sample->loop=true;
|
||||||
|
sample->loopMode=(DivSampleLoopMode)(inst.loops[0].mode-SF_LOOP_FORWARD);
|
||||||
sample->loopStart=inst.loops[0].start;
|
sample->loopStart=inst.loops[0].start;
|
||||||
sample->loopEnd=inst.loops[0].end;
|
sample->loopEnd=inst.loops[0].end;
|
||||||
if(inst.loops[0].end < (unsigned int)sampleCount)
|
if(inst.loops[0].end < (unsigned int)sampleCount)
|
||||||
sampleCount=inst.loops[0].end;
|
sampleCount=inst.loops[0].end;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
sample->loop=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sample->centerRate<4000) sample->centerRate=4000;
|
if (sample->centerRate<4000) sample->centerRate=4000;
|
||||||
|
@ -3000,6 +3016,7 @@ void DivEngine::delSample(int index) {
|
||||||
BUSY_BEGIN;
|
BUSY_BEGIN;
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
saveLock.lock();
|
saveLock.lock();
|
||||||
if (index>=0 && index<(int)song.sample.size()) {
|
if (index>=0 && index<(int)song.sample.size()) {
|
||||||
delete song.sample[index];
|
delete song.sample[index];
|
||||||
|
@ -3218,6 +3235,7 @@ bool DivEngine::moveSampleUp(int which) {
|
||||||
BUSY_BEGIN;
|
BUSY_BEGIN;
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
DivSample* prev=song.sample[which];
|
DivSample* prev=song.sample[which];
|
||||||
saveLock.lock();
|
saveLock.lock();
|
||||||
song.sample[which]=song.sample[which-1];
|
song.sample[which]=song.sample[which-1];
|
||||||
|
@ -3257,6 +3275,7 @@ bool DivEngine::moveSampleDown(int which) {
|
||||||
BUSY_BEGIN;
|
BUSY_BEGIN;
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
DivSample* prev=song.sample[which];
|
DivSample* prev=song.sample[which];
|
||||||
saveLock.lock();
|
saveLock.lock();
|
||||||
song.sample[which]=song.sample[which+1];
|
song.sample[which]=song.sample[which+1];
|
||||||
|
|
|
@ -46,8 +46,8 @@
|
||||||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||||
|
|
||||||
#define DIV_VERSION "0.6pre1.5"
|
#define DIV_VERSION "dev117"
|
||||||
#define DIV_ENGINE_VERSION 116
|
#define DIV_ENGINE_VERSION 117
|
||||||
// for imports
|
// for imports
|
||||||
#define DIV_VERSION_MOD 0xff01
|
#define DIV_VERSION_MOD 0xff01
|
||||||
#define DIV_VERSION_FC 0xff02
|
#define DIV_VERSION_FC 0xff02
|
||||||
|
@ -377,14 +377,16 @@ class DivEngine {
|
||||||
struct SamplePreview {
|
struct SamplePreview {
|
||||||
int sample;
|
int sample;
|
||||||
int wave;
|
int wave;
|
||||||
unsigned int pos;
|
int pos;
|
||||||
int pBegin, pEnd;
|
int pBegin, pEnd;
|
||||||
|
bool dir;
|
||||||
SamplePreview():
|
SamplePreview():
|
||||||
sample(-1),
|
sample(-1),
|
||||||
wave(-1),
|
wave(-1),
|
||||||
pos(0),
|
pos(0),
|
||||||
pBegin(-1),
|
pBegin(-1),
|
||||||
pEnd(-1) {}
|
pEnd(-1),
|
||||||
|
dir(false) {}
|
||||||
} sPreview;
|
} sPreview;
|
||||||
|
|
||||||
short vibTable[64];
|
short vibTable[64];
|
||||||
|
|
|
@ -178,6 +178,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
ds.e1e2StopOnSameNote=true;
|
ds.e1e2StopOnSameNote=true;
|
||||||
ds.brokenPortaArp=false;
|
ds.brokenPortaArp=false;
|
||||||
ds.snNoLowPeriods=true;
|
ds.snNoLowPeriods=true;
|
||||||
|
ds.disableSampleMacro=true;
|
||||||
ds.delayBehavior=0;
|
ds.delayBehavior=0;
|
||||||
ds.jumpTreatment=2;
|
ds.jumpTreatment=2;
|
||||||
|
|
||||||
|
@ -336,7 +337,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
}
|
}
|
||||||
logD("%d name: %s",i,ins->name.c_str());
|
logD("%d name: %s",i,ins->name.c_str());
|
||||||
if (ds.version<0x0b) {
|
if (ds.version<0x0b) {
|
||||||
// instruments in ancient versions were all FM or STD.
|
// instruments in ancient versions were all FM.
|
||||||
mode=1;
|
mode=1;
|
||||||
} else {
|
} else {
|
||||||
mode=reader.readC();
|
mode=reader.readC();
|
||||||
|
@ -365,6 +366,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
if (ds.system[0]==DIV_SYSTEM_YMU759) {
|
if (ds.system[0]==DIV_SYSTEM_YMU759) {
|
||||||
ins->type=DIV_INS_OPL;
|
ins->type=DIV_INS_OPL;
|
||||||
}
|
}
|
||||||
|
if (ds.system[0]==DIV_SYSTEM_ARCADE) {
|
||||||
|
ins->type=DIV_INS_OPM;
|
||||||
|
}
|
||||||
|
if ((ds.system[0]==DIV_SYSTEM_NES || ds.system[0]==DIV_SYSTEM_NES_VRC7 || ds.system[0]==DIV_SYSTEM_NES_FDS) && ins->type==DIV_INS_STD) {
|
||||||
|
ins->type=DIV_INS_NES;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode) { // FM
|
if (mode) { // FM
|
||||||
if (ds.version>0x05) {
|
if (ds.version>0x05) {
|
||||||
|
@ -1100,6 +1107,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
if (ds.version<115) {
|
if (ds.version<115) {
|
||||||
ds.autoSystem=false;
|
ds.autoSystem=false;
|
||||||
}
|
}
|
||||||
|
if (ds.version<117) {
|
||||||
|
ds.disableSampleMacro=true;
|
||||||
|
}
|
||||||
ds.isDMF=false;
|
ds.isDMF=false;
|
||||||
|
|
||||||
reader.readS(); // reserved
|
reader.readS(); // reserved
|
||||||
|
@ -1532,7 +1542,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
reader.readC();
|
reader.readC();
|
||||||
}
|
}
|
||||||
for (int i=0; i<3; i++) {
|
if (ds.version>=117) {
|
||||||
|
ds.disableSampleMacro=reader.readC();
|
||||||
|
} else {
|
||||||
|
reader.readC();
|
||||||
|
}
|
||||||
|
for (int i=0; i<2; i++) {
|
||||||
reader.readC();
|
reader.readC();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1741,6 +1756,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
|
|
||||||
sample->loopStart=reader.readI();
|
sample->loopStart=reader.readI();
|
||||||
sample->loopEnd=reader.readI();
|
sample->loopEnd=reader.readI();
|
||||||
|
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
||||||
|
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
reader.readI();
|
reader.readI();
|
||||||
|
@ -1766,6 +1782,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
|
|
||||||
if (ds.version>=19) {
|
if (ds.version>=19) {
|
||||||
sample->loopStart=reader.readI();
|
sample->loopStart=reader.readI();
|
||||||
|
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
||||||
} else {
|
} else {
|
||||||
reader.readI();
|
reader.readI();
|
||||||
}
|
}
|
||||||
|
@ -1908,6 +1925,57 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert OPM/NES instrument types
|
||||||
|
if (ds.version<117) {
|
||||||
|
int opnCount=0;
|
||||||
|
int opmCount=0;
|
||||||
|
int snCount=0;
|
||||||
|
int nesCount=0;
|
||||||
|
for (int i=0; i<ds.systemLen; i++) {
|
||||||
|
switch (ds.system[i]) {
|
||||||
|
case DIV_SYSTEM_NES:
|
||||||
|
case DIV_SYSTEM_MMC5:
|
||||||
|
nesCount++;
|
||||||
|
break;
|
||||||
|
case DIV_SYSTEM_SMS:
|
||||||
|
snCount++;
|
||||||
|
break;
|
||||||
|
case DIV_SYSTEM_YM2151:
|
||||||
|
case DIV_SYSTEM_OPZ:
|
||||||
|
opmCount++;
|
||||||
|
break;
|
||||||
|
case DIV_SYSTEM_YM2610:
|
||||||
|
case DIV_SYSTEM_YM2610_EXT:
|
||||||
|
case DIV_SYSTEM_YM2610_FULL:
|
||||||
|
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||||
|
case DIV_SYSTEM_YM2610B:
|
||||||
|
case DIV_SYSTEM_YM2610B_EXT:
|
||||||
|
case DIV_SYSTEM_OPN:
|
||||||
|
case DIV_SYSTEM_OPN_EXT:
|
||||||
|
case DIV_SYSTEM_PC98:
|
||||||
|
case DIV_SYSTEM_PC98_EXT:
|
||||||
|
case DIV_SYSTEM_YM2612:
|
||||||
|
case DIV_SYSTEM_YM2612_EXT:
|
||||||
|
case DIV_SYSTEM_YM2612_FRAC:
|
||||||
|
case DIV_SYSTEM_YM2612_FRAC_EXT:
|
||||||
|
opnCount++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opmCount>opnCount) {
|
||||||
|
for (DivInstrument* i: ds.ins) {
|
||||||
|
if (i->type==DIV_INS_FM) i->type=DIV_INS_OPM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nesCount>snCount) {
|
||||||
|
for (DivInstrument* i: ds.ins) {
|
||||||
|
if (i->type==DIV_INS_STD) i->type=DIV_INS_NES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
saveLock.lock();
|
saveLock.lock();
|
||||||
|
@ -2040,6 +2108,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
||||||
if (loopLen>=2) {
|
if (loopLen>=2) {
|
||||||
sample->loopStart=loopStart;
|
sample->loopStart=loopStart;
|
||||||
sample->loopEnd=loopEnd;
|
sample->loopEnd=loopEnd;
|
||||||
|
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
||||||
}
|
}
|
||||||
sample->init(slen);
|
sample->init(slen);
|
||||||
ds.sample.push_back(sample);
|
ds.sample.push_back(sample);
|
||||||
|
@ -2669,6 +2738,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
||||||
if (sample[i].loopLen>1) {
|
if (sample[i].loopLen>1) {
|
||||||
s->loopStart=sample[i].loopStart;
|
s->loopStart=sample[i].loopStart;
|
||||||
s->loopEnd=sample[i].loopStart+(sample[i].loopLen*2);
|
s->loopEnd=sample[i].loopStart+(sample[i].loopLen*2);
|
||||||
|
s->loop=(s->loopStart>=0)&&(s->loopEnd>=0);
|
||||||
}
|
}
|
||||||
reader.read(s->data8,sample[i].len*2);
|
reader.read(s->data8,sample[i].len*2);
|
||||||
ds.sample.push_back(s);
|
ds.sample.push_back(s);
|
||||||
|
@ -3224,7 +3294,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) {
|
||||||
unsigned char insType=reader.readC();
|
unsigned char insType=reader.readC();
|
||||||
switch (insType) {
|
switch (insType) {
|
||||||
case 1:
|
case 1:
|
||||||
ins->type=DIV_INS_STD;
|
ins->type=DIV_INS_NES;
|
||||||
break;
|
break;
|
||||||
case 2: // TODO: tell VRC6 and VRC6 saw instruments apart
|
case 2: // TODO: tell VRC6 and VRC6 saw instruments apart
|
||||||
ins->type=DIV_INS_VRC6;
|
ins->type=DIV_INS_VRC6;
|
||||||
|
@ -3251,7 +3321,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) {
|
||||||
|
|
||||||
// instrument data
|
// instrument data
|
||||||
switch (ins->type) {
|
switch (ins->type) {
|
||||||
case DIV_INS_STD: {
|
case DIV_INS_NES: {
|
||||||
unsigned int totalSeqs=reader.readI();
|
unsigned int totalSeqs=reader.readI();
|
||||||
if (totalSeqs>5) {
|
if (totalSeqs>5) {
|
||||||
logE("%d: too many sequences!",insIndex);
|
logE("%d: too many sequences!",insIndex);
|
||||||
|
@ -3773,7 +3843,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||||
w->writeC(song.delayBehavior);
|
w->writeC(song.delayBehavior);
|
||||||
w->writeC(song.jumpTreatment);
|
w->writeC(song.jumpTreatment);
|
||||||
w->writeC(song.autoSystem);
|
w->writeC(song.autoSystem);
|
||||||
for (int i=0; i<3; i++) {
|
w->writeC(song.disableSampleMacro);
|
||||||
|
for (int i=0; i<2; i++) {
|
||||||
w->writeC(0);
|
w->writeC(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3892,8 +3963,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||||
w->writeC(0); // reserved
|
w->writeC(0); // reserved
|
||||||
w->writeC(0);
|
w->writeC(0);
|
||||||
w->writeC(0);
|
w->writeC(0);
|
||||||
w->writeI(sample->loopStart);
|
w->writeI(sample->loop?sample->loopStart:-1);
|
||||||
w->writeI(sample->loopEnd);
|
w->writeI(sample->loop?sample->loopEnd:-1);
|
||||||
|
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
w->writeI(0xffffffff);
|
w->writeI(0xffffffff);
|
||||||
|
@ -4169,7 +4240,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (DivInstrument* i: song.ins) {
|
for (DivInstrument* i: song.ins) {
|
||||||
if (i->type==DIV_INS_FM) {
|
if (i->type==DIV_INS_FM || i->type==DIV_INS_OPM) {
|
||||||
addWarning("no FM macros in .dmf format");
|
addWarning("no FM macros in .dmf format");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4180,11 +4251,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
||||||
w->writeString(i->name,true);
|
w->writeString(i->name,true);
|
||||||
|
|
||||||
// safety check
|
// safety check
|
||||||
if (!isFMSystem(sys) && i->type!=DIV_INS_STD && i->type!=DIV_INS_FDS) {
|
if (!isFMSystem(sys) && i->type!=DIV_INS_STD && i->type!=DIV_INS_NES && i->type!=DIV_INS_FDS) {
|
||||||
switch (song.system[0]) {
|
switch (song.system[0]) {
|
||||||
case DIV_SYSTEM_GB:
|
case DIV_SYSTEM_GB:
|
||||||
i->type=DIV_INS_GB;
|
i->type=DIV_INS_GB;
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_NES:
|
||||||
|
i->type=DIV_INS_NES;
|
||||||
|
break;
|
||||||
case DIV_SYSTEM_C64_6581:
|
case DIV_SYSTEM_C64_6581:
|
||||||
case DIV_SYSTEM_C64_8580:
|
case DIV_SYSTEM_C64_8580:
|
||||||
i->type=DIV_INS_C64;
|
i->type=DIV_INS_C64;
|
||||||
|
@ -4201,12 +4275,16 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isSTDSystem(sys) && i->type!=DIV_INS_FM) {
|
if (!isSTDSystem(sys) && i->type!=DIV_INS_FM && i->type!=DIV_INS_OPM) {
|
||||||
i->type=DIV_INS_FM;
|
if (sys==DIV_SYSTEM_ARCADE) {
|
||||||
|
i->type=DIV_INS_OPM;
|
||||||
|
} else {
|
||||||
|
i->type=DIV_INS_FM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w->writeC((i->type==DIV_INS_FM || i->type==DIV_INS_OPLL)?1:0);
|
w->writeC((i->type==DIV_INS_FM || i->type==DIV_INS_OPM || i->type==DIV_INS_OPLL)?1:0);
|
||||||
if (i->type==DIV_INS_FM || i->type==DIV_INS_OPLL) { // FM
|
if (i->type==DIV_INS_FM || i->type==DIV_INS_OPM || i->type==DIV_INS_OPLL) { // FM
|
||||||
w->writeC(i->fm.alg);
|
w->writeC(i->fm.alg);
|
||||||
w->writeC(i->fm.fb);
|
w->writeC(i->fm.fb);
|
||||||
w->writeC(i->fm.fms);
|
w->writeC(i->fm.fms);
|
||||||
|
|
|
@ -532,7 +532,7 @@ void DivInstrument::putInsData(SafeWriter* w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sound Unit
|
// Sound Unit
|
||||||
w->writeC(su.useSample);
|
w->writeC(amiga.useSample);
|
||||||
w->writeC(su.switchRoles);
|
w->writeC(su.switchRoles);
|
||||||
|
|
||||||
// GB hardware sequence
|
// GB hardware sequence
|
||||||
|
@ -1222,7 +1222,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
||||||
|
|
||||||
// Sound Unit
|
// Sound Unit
|
||||||
if (version>=104) {
|
if (version>=104) {
|
||||||
su.useSample=reader.readC();
|
amiga.useSample=reader.readC();
|
||||||
su.switchRoles=reader.readC();
|
su.switchRoles=reader.readC();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,16 @@ enum DivInstrumentType: unsigned short {
|
||||||
DIV_INS_SU=30,
|
DIV_INS_SU=30,
|
||||||
DIV_INS_NAMCO=31,
|
DIV_INS_NAMCO=31,
|
||||||
DIV_INS_OPL_DRUMS=32,
|
DIV_INS_OPL_DRUMS=32,
|
||||||
|
DIV_INS_OPM=33,
|
||||||
|
DIV_INS_NES=34,
|
||||||
|
DIV_INS_MSM6258=35,
|
||||||
|
DIV_INS_MSM6295=36,
|
||||||
|
DIV_INS_ADPCMA=37,
|
||||||
|
DIV_INS_ADPCMB=38,
|
||||||
|
DIV_INS_SEGAPCM=39,
|
||||||
|
DIV_INS_QSOUND=40,
|
||||||
|
DIV_INS_YMZ280B=41,
|
||||||
|
DIV_INS_RF5C68=42,
|
||||||
DIV_INS_MAX,
|
DIV_INS_MAX,
|
||||||
DIV_INS_NULL
|
DIV_INS_NULL
|
||||||
};
|
};
|
||||||
|
@ -336,6 +346,7 @@ struct DivInstrumentAmiga {
|
||||||
};
|
};
|
||||||
short initSample;
|
short initSample;
|
||||||
bool useNoteMap;
|
bool useNoteMap;
|
||||||
|
bool useSample;
|
||||||
bool useWave;
|
bool useWave;
|
||||||
unsigned char waveLen;
|
unsigned char waveLen;
|
||||||
SampleMap noteMap[120];
|
SampleMap noteMap[120];
|
||||||
|
@ -369,6 +380,7 @@ struct DivInstrumentAmiga {
|
||||||
DivInstrumentAmiga():
|
DivInstrumentAmiga():
|
||||||
initSample(0),
|
initSample(0),
|
||||||
useNoteMap(false),
|
useNoteMap(false),
|
||||||
|
useSample(false),
|
||||||
useWave(false),
|
useWave(false),
|
||||||
waveLen(31) {
|
waveLen(31) {
|
||||||
for (SampleMap& elem: noteMap) {
|
for (SampleMap& elem: noteMap) {
|
||||||
|
@ -377,6 +389,13 @@ struct DivInstrumentAmiga {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DivInstrumentX1_010 {
|
||||||
|
int bankSlot;
|
||||||
|
|
||||||
|
DivInstrumentX1_010():
|
||||||
|
bankSlot(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct DivInstrumentN163 {
|
struct DivInstrumentN163 {
|
||||||
int wave, wavePos, waveLen;
|
int wave, wavePos, waveLen;
|
||||||
unsigned char waveMode;
|
unsigned char waveMode;
|
||||||
|
@ -459,10 +478,8 @@ struct DivInstrumentWaveSynth {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DivInstrumentSoundUnit {
|
struct DivInstrumentSoundUnit {
|
||||||
bool useSample;
|
|
||||||
bool switchRoles;
|
bool switchRoles;
|
||||||
DivInstrumentSoundUnit():
|
DivInstrumentSoundUnit():
|
||||||
useSample(false),
|
|
||||||
switchRoles(false) {}
|
switchRoles(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -533,6 +550,7 @@ struct DivInstrument {
|
||||||
DivInstrumentGB gb;
|
DivInstrumentGB gb;
|
||||||
DivInstrumentC64 c64;
|
DivInstrumentC64 c64;
|
||||||
DivInstrumentAmiga amiga;
|
DivInstrumentAmiga amiga;
|
||||||
|
DivInstrumentX1_010 x1_010;
|
||||||
DivInstrumentN163 n163;
|
DivInstrumentN163 n163;
|
||||||
DivInstrumentFDS fds;
|
DivInstrumentFDS fds;
|
||||||
DivInstrumentMultiPCM multipcm;
|
DivInstrumentMultiPCM multipcm;
|
||||||
|
|
|
@ -99,7 +99,7 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
|
||||||
if (chan[i].audPos<s->samples) {
|
if (chan[i].audPos<s->samples) {
|
||||||
writeAudDat(s->data8[chan[i].audPos++]);
|
writeAudDat(s->data8[chan[i].audPos++]);
|
||||||
}
|
}
|
||||||
if (s->isLoopable() && chan[i].audPos>=MIN(131071,s->getEndPosition())) {
|
if (s->isLoopable() && chan[i].audPos>=MIN(131071,(unsigned int)s->loopEnd)) {
|
||||||
chan[i].audPos=s->loopStart;
|
chan[i].audPos=s->loopStart;
|
||||||
} else if (chan[i].audPos>=MIN(131071,s->samples)) {
|
} else if (chan[i].audPos>=MIN(131071,s->samples)) {
|
||||||
chan[i].sample=-1;
|
chan[i].sample=-1;
|
||||||
|
|
|
@ -86,6 +86,7 @@ class DivPlatformAmiga: public DivDispatch {
|
||||||
|
|
||||||
int sep1, sep2;
|
int sep1, sep2;
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -833,9 +833,6 @@ void DivPlatformArcade::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBusy=60;
|
lastBusy=60;
|
||||||
pcmCycles=0;
|
|
||||||
pcmL=0;
|
|
||||||
pcmR=0;
|
|
||||||
delay=0;
|
delay=0;
|
||||||
amDepth=0x7f;
|
amDepth=0x7f;
|
||||||
pmDepth=0x7f;
|
pmDepth=0x7f;
|
||||||
|
@ -846,8 +843,6 @@ void DivPlatformArcade::reset() {
|
||||||
immWrite(0x19,amDepth);
|
immWrite(0x19,amDepth);
|
||||||
immWrite(0x19,0x80|pmDepth);
|
immWrite(0x19,0x80|pmDepth);
|
||||||
//rWrite(0x1b,0x00);
|
//rWrite(0x1b,0x00);
|
||||||
|
|
||||||
extMode=false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformArcade::setFlags(unsigned int flags) {
|
void DivPlatformArcade::setFlags(unsigned int flags) {
|
||||||
|
|
|
@ -79,14 +79,13 @@ class DivPlatformArcade: public DivPlatformOPM {
|
||||||
DivDispatchOscBuffer* oscBuf[8];
|
DivDispatchOscBuffer* oscBuf[8];
|
||||||
opm_t fm;
|
opm_t fm;
|
||||||
int baseFreqOff;
|
int baseFreqOff;
|
||||||
int pcmL, pcmR, pcmCycles;
|
|
||||||
unsigned char amDepth, pmDepth;
|
unsigned char amDepth, pmDepth;
|
||||||
|
|
||||||
ymfm::ym2151* fm_ymfm;
|
ymfm::ym2151* fm_ymfm;
|
||||||
ymfm::ym2151::output_data out_ymfm;
|
ymfm::ym2151::output_data out_ymfm;
|
||||||
DivArcadeInterface iface;
|
DivArcadeInterface iface;
|
||||||
|
|
||||||
bool extMode, useYMFM;
|
bool useYMFM;
|
||||||
|
|
||||||
bool isMuted[8];
|
bool isMuted[8];
|
||||||
|
|
||||||
|
@ -96,6 +95,7 @@ class DivPlatformArcade: public DivPlatformOPM {
|
||||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -81,14 +81,80 @@ const char** DivPlatformAY8910::getRegisterSheet() {
|
||||||
return intellivision?regCheatSheetAY8914:regCheatSheetAY;
|
return intellivision?regCheatSheetAY8914:regCheatSheetAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
/* C program to generate this table:
|
||||||
if (ayBufLen<len) {
|
|
||||||
ayBufLen=len;
|
#include <stdio.h>
|
||||||
for (int i=0; i<3; i++) {
|
#include <math.h>
|
||||||
delete[] ayBuf[i];
|
|
||||||
ayBuf[i]=new short[ayBufLen];
|
int main(int argc, char** argv) {
|
||||||
|
for (int i=0; i<256; i++) {
|
||||||
|
if ((i&15)==0) printf("\n ");
|
||||||
|
printf(" %d,",(int)round(pow((double)i/255.0,0.36)*15.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const unsigned char dacLogTableAY[256]={
|
||||||
|
0, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||||
|
8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
|
9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||||
|
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11,
|
||||||
|
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||||
|
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
|
||||||
|
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||||
|
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13,
|
||||||
|
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||||
|
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14,
|
||||||
|
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||||
|
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||||
|
14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15,
|
||||||
|
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15
|
||||||
|
};
|
||||||
|
|
||||||
|
void DivPlatformAY8910::runDAC() {
|
||||||
|
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 prevOut=chan[i].dac.out;
|
||||||
|
while (chan[i].dac.period>rate && !end) {
|
||||||
|
DivSample* s=parent->getSample(chan[i].dac.sample);
|
||||||
|
if (s->samples<=0) {
|
||||||
|
chan[i].dac.sample=-1;
|
||||||
|
immWrite(0x08+i,0);
|
||||||
|
end=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unsigned char dacData=dacLogTableAY[(unsigned char)s->data8[chan[i].dac.pos]^0x80];
|
||||||
|
chan[i].dac.out=MAX(0,dacData-(15-chan[i].outVol));
|
||||||
|
if (prevOut!=chan[i].dac.out) {
|
||||||
|
prevOut=chan[i].dac.out;
|
||||||
|
changed=true;
|
||||||
|
}
|
||||||
|
chan[i].dac.pos++;
|
||||||
|
if (s->isLoopable() && chan[i].dac.pos>=s->loopEnd) {
|
||||||
|
chan[i].dac.pos=s->loopStart;
|
||||||
|
} else if (chan[i].dac.pos>=(int)s->samples) {
|
||||||
|
chan[i].dac.sample=-1;
|
||||||
|
//immWrite(0x08+i,0);
|
||||||
|
end=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chan[i].dac.period-=rate;
|
||||||
|
}
|
||||||
|
if (changed && !end) {
|
||||||
|
if (!isMuted[i]) {
|
||||||
|
immWrite(0x08+i,chan[i].dac.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformAY8910::checkWrites() {
|
||||||
while (!writes.empty()) {
|
while (!writes.empty()) {
|
||||||
QueuedWrite w=writes.front();
|
QueuedWrite w=writes.front();
|
||||||
if (intellivision) {
|
if (intellivision) {
|
||||||
|
@ -101,8 +167,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
regPool[w.addr&0x0f]=w.val;
|
regPool[w.addr&0x0f]=w.val;
|
||||||
writes.pop();
|
writes.pop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
|
if (ayBufLen<len) {
|
||||||
|
ayBufLen=len;
|
||||||
|
for (int i=0; i<3; i++) {
|
||||||
|
delete[] ayBuf[i];
|
||||||
|
ayBuf[i]=new short[ayBufLen];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sunsoft) {
|
if (sunsoft) {
|
||||||
for (size_t i=0; i<len; i++) {
|
for (size_t i=0; i<len; i++) {
|
||||||
|
runDAC();
|
||||||
|
checkWrites();
|
||||||
|
|
||||||
ay->sound_stream_update(ayBuf,1);
|
ay->sound_stream_update(ayBuf,1);
|
||||||
bufL[i+start]=ayBuf[0][0];
|
bufL[i+start]=ayBuf[0][0];
|
||||||
bufR[i+start]=bufL[i+start];
|
bufR[i+start]=bufL[i+start];
|
||||||
|
@ -112,22 +192,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
oscBuf[2]->data[oscBuf[2]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>10)&31)]>>3;
|
oscBuf[2]->data[oscBuf[2]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>10)&31)]>>3;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ay->sound_stream_update(ayBuf,len);
|
for (size_t i=0; i<len; i++) {
|
||||||
if (stereo) {
|
runDAC();
|
||||||
for (size_t i=0; i<len; i++) {
|
checkWrites();
|
||||||
bufL[i+start]=ayBuf[0][i]+ayBuf[1][i]+((ayBuf[2][i]*stereoSep)>>8);
|
|
||||||
bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i];
|
ay->sound_stream_update(ayBuf,1);
|
||||||
}
|
if (stereo) {
|
||||||
} else {
|
bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+((ayBuf[2][0]*stereoSep)>>8);
|
||||||
for (size_t i=0; i<len; i++) {
|
bufR[i+start]=((ayBuf[0][0]*stereoSep)>>8)+ayBuf[1][0]+ayBuf[2][0];
|
||||||
bufL[i+start]=ayBuf[0][i]+ayBuf[1][i]+ayBuf[2][i];
|
} else {
|
||||||
|
bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+ayBuf[2][0];
|
||||||
bufR[i+start]=bufL[i+start];
|
bufR[i+start]=bufL[i+start];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (int ch=0; ch<3; ch++) {
|
oscBuf[0]->data[oscBuf[0]->needle++]=ayBuf[0][0]<<2;
|
||||||
for (size_t i=0; i<len; i++) {
|
oscBuf[1]->data[oscBuf[1]->needle++]=ayBuf[1][0]<<2;
|
||||||
oscBuf[ch]->data[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2;
|
oscBuf[2]->data[oscBuf[2]->needle++]=ayBuf[2][0]<<2;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,22 +215,22 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
void DivPlatformAY8910::updateOutSel(bool immediate) {
|
void DivPlatformAY8910::updateOutSel(bool immediate) {
|
||||||
if (immediate) {
|
if (immediate) {
|
||||||
immWrite(0x07,
|
immWrite(0x07,
|
||||||
~((chan[0].psgMode&1)|
|
~((chan[0].psgMode.getTone())|
|
||||||
((chan[1].psgMode&1)<<1)|
|
((chan[1].psgMode.getTone())<<1)|
|
||||||
((chan[2].psgMode&1)<<2)|
|
((chan[2].psgMode.getTone())<<2)|
|
||||||
((chan[0].psgMode&2)<<2)|
|
((chan[0].psgMode.getNoise())<<2)|
|
||||||
((chan[1].psgMode&2)<<3)|
|
((chan[1].psgMode.getNoise())<<3)|
|
||||||
((chan[2].psgMode&2)<<4)|
|
((chan[2].psgMode.getNoise())<<4)|
|
||||||
((!ioPortA)<<6)|
|
((!ioPortA)<<6)|
|
||||||
((!ioPortB)<<7)));
|
((!ioPortB)<<7)));
|
||||||
} else {
|
} else {
|
||||||
rWrite(0x07,
|
rWrite(0x07,
|
||||||
~((chan[0].psgMode&1)|
|
~((chan[0].psgMode.getTone())|
|
||||||
((chan[1].psgMode&1)<<1)|
|
((chan[1].psgMode.getTone())<<1)|
|
||||||
((chan[2].psgMode&1)<<2)|
|
((chan[2].psgMode.getTone())<<2)|
|
||||||
((chan[0].psgMode&2)<<2)|
|
((chan[0].psgMode.getNoise())<<2)|
|
||||||
((chan[1].psgMode&2)<<3)|
|
((chan[1].psgMode.getNoise())<<3)|
|
||||||
((chan[2].psgMode&2)<<4)|
|
((chan[2].psgMode.getNoise())<<4)|
|
||||||
((!ioPortA)<<6)|
|
((!ioPortA)<<6)|
|
||||||
((!ioPortB)<<7)));
|
((!ioPortB)<<7)));
|
||||||
}
|
}
|
||||||
|
@ -163,12 +243,14 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
if (chan[i].std.vol.had) {
|
if (chan[i].std.vol.had) {
|
||||||
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
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 (chan[i].outVol<0) chan[i].outVol=0;
|
||||||
if (isMuted[i]) {
|
if (!chan[i].psgMode.dac) {
|
||||||
rWrite(0x08+i,0);
|
if (isMuted[i]) {
|
||||||
} else if (intellivision && (chan[i].psgMode&4)) {
|
rWrite(0x08+i,0);
|
||||||
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
} else if (intellivision && (chan[i].psgMode.getEnvelope())) {
|
||||||
} else {
|
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
} else {
|
||||||
|
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
|
@ -181,13 +263,15 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
rWrite(0x06,31-chan[i].std.duty.val);
|
rWrite(0x06,31-chan[i].std.duty.val);
|
||||||
}
|
}
|
||||||
if (chan[i].std.wave.had) {
|
if (chan[i].std.wave.had) {
|
||||||
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
if (!chan[i].psgMode.dac) {
|
||||||
if (isMuted[i]) {
|
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
||||||
rWrite(0x08+i,0);
|
if (isMuted[i]) {
|
||||||
} else if (intellivision && (chan[i].psgMode&4)) {
|
rWrite(0x08+i,0);
|
||||||
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
} else if (intellivision && (chan[i].psgMode.getEnvelope())) {
|
||||||
} else {
|
rWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||||
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
} else {
|
||||||
|
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode.getEnvelope())<<2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].std.pitch.had) {
|
if (chan[i].std.pitch.had) {
|
||||||
|
@ -201,6 +285,20 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
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[0x08+i]=-1;
|
||||||
oldWrites[0x0d]=-1;
|
oldWrites[0x0d]=-1;
|
||||||
}
|
}
|
||||||
|
@ -221,6 +319,19 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
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);
|
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)rate*((sunsoft||clockSel)?8.0:16.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].freq>4095) chan[i].freq=4095;
|
||||||
if (chan[i].keyOn) {
|
if (chan[i].keyOn) {
|
||||||
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
|
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
|
||||||
|
@ -276,6 +387,62 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY);
|
||||||
|
if (!parent->song.disableSampleMacro && (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 (!parent->song.disableSampleMacro && (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*2048;
|
||||||
|
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) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
|
@ -287,16 +454,21 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
}
|
}
|
||||||
if (isMuted[c.chan]) {
|
if (!chan[c.chan].psgMode.dac) {
|
||||||
rWrite(0x08+c.chan,0);
|
if (isMuted[c.chan]) {
|
||||||
} else if (intellivision && (chan[c.chan].psgMode&4)) {
|
rWrite(0x08+c.chan,0);
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
} else if (intellivision && (chan[c.chan].psgMode.getEnvelope())) {
|
||||||
} else {
|
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
} else {
|
||||||
|
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_OFF:
|
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].keyOff=true;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
|
@ -310,14 +482,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
}
|
}
|
||||||
if (isMuted[c.chan]) {
|
if (!chan[c.chan].psgMode.dac) {
|
||||||
rWrite(0x08+c.chan,0);
|
if (isMuted[c.chan]) {
|
||||||
} else {
|
rWrite(0x08+c.chan,0);
|
||||||
if (chan[c.chan].active) {
|
} else {
|
||||||
if (intellivision && (chan[c.chan].psgMode&4)) {
|
if (chan[c.chan].active) {
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
if (intellivision && (chan[c.chan].psgMode.getEnvelope())) {
|
||||||
} else {
|
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
} else {
|
||||||
|
rWrite(0x08+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode.getEnvelope())<<2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,15 +541,17 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_STD_NOISE_MODE:
|
case DIV_CMD_STD_NOISE_MODE:
|
||||||
if (c.value<16) {
|
if (!chan[c.chan].psgMode.dac) {
|
||||||
chan[c.chan].psgMode=(c.value+1)&7;
|
if (c.value<16) {
|
||||||
if (isMuted[c.chan]) {
|
chan[c.chan].psgMode=(c.value+1)&7;
|
||||||
rWrite(0x08+c.chan,0);
|
if (isMuted[c.chan]) {
|
||||||
} else if (chan[c.chan].active) {
|
rWrite(0x08+c.chan,0);
|
||||||
if (intellivision && (chan[c.chan].psgMode&4)) {
|
} else if (chan[c.chan].active) {
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2);
|
if (intellivision && (chan[c.chan].psgMode.getEnvelope())) {
|
||||||
} else {
|
rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2);
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode&4)<<2));
|
} else {
|
||||||
|
rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].psgMode.getEnvelope())<<2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,16 +563,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
ayEnvMode=c.value>>4;
|
ayEnvMode=c.value>>4;
|
||||||
rWrite(0x0d,ayEnvMode);
|
rWrite(0x0d,ayEnvMode);
|
||||||
if (c.value&15) {
|
if (c.value&15) {
|
||||||
chan[c.chan].psgMode|=4;
|
chan[c.chan].psgMode.envelope|=1;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].psgMode&=~4;
|
chan[c.chan].psgMode.envelope&=~1;
|
||||||
}
|
}
|
||||||
if (isMuted[c.chan]) {
|
if (isMuted[c.chan]) {
|
||||||
rWrite(0x08+c.chan,0);
|
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);
|
rWrite(0x08+c.chan,(chan[c.chan].vol&0xc)<<2);
|
||||||
} else {
|
} 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;
|
break;
|
||||||
case DIV_CMD_AY_ENVELOPE_LOW:
|
case DIV_CMD_AY_ENVELOPE_LOW:
|
||||||
|
@ -433,6 +609,15 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
updateOutSel(true);
|
updateOutSel(true);
|
||||||
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
|
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
|
||||||
break;
|
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:
|
case DIV_ALWAYS_SET_VOLUME:
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
@ -461,10 +646,14 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) {
|
||||||
isMuted[ch]=mute;
|
isMuted[ch]=mute;
|
||||||
if (isMuted[ch]) {
|
if (isMuted[ch]) {
|
||||||
rWrite(0x08+ch,0);
|
rWrite(0x08+ch,0);
|
||||||
} else if (intellivision && (chan[ch].psgMode&4) && chan[ch].active) {
|
} else if (chan[ch].active && chan[ch].psgMode.dac) {
|
||||||
rWrite(0x08+ch,(chan[ch].vol&0xc)<<2);
|
rWrite(0x08+ch,chan[ch].dac.out);
|
||||||
} else if (chan[ch].active) {
|
} else {
|
||||||
rWrite(0x08+ch,(chan[ch].outVol&15)|((chan[ch].psgMode&4)<<2));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,12 +712,6 @@ void DivPlatformAY8910::reset() {
|
||||||
pendingWrites[i]=-1;
|
pendingWrites[i]=-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBusy=60;
|
|
||||||
dacMode=0;
|
|
||||||
dacPeriod=0;
|
|
||||||
dacPos=0;
|
|
||||||
dacRate=0;
|
|
||||||
dacSample=-1;
|
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
ayEnvPeriod=0;
|
ayEnvPeriod=0;
|
||||||
ayEnvMode=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; }
|
inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
|
||||||
struct Channel {
|
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 freq, baseFreq, note, pitch, pitch2;
|
||||||
int ins;
|
int ins;
|
||||||
unsigned char psgMode, autoEnvNum, autoEnvDen;
|
unsigned char autoEnvNum, autoEnvDen;
|
||||||
signed char konCycles;
|
signed char konCycles;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
unsigned char pan;
|
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
pitch2=0;
|
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];
|
Channel chan[3];
|
||||||
bool isMuted[3];
|
bool isMuted[3];
|
||||||
|
@ -60,11 +123,6 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
unsigned char regPool[16];
|
unsigned char regPool[16];
|
||||||
unsigned char lastBusy;
|
unsigned char lastBusy;
|
||||||
|
|
||||||
bool dacMode;
|
|
||||||
int dacPeriod;
|
|
||||||
int dacRate;
|
|
||||||
int dacPos;
|
|
||||||
int dacSample;
|
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
unsigned char stereoSep;
|
unsigned char stereoSep;
|
||||||
|
|
||||||
|
@ -87,8 +145,11 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
short* ayBuf[3];
|
short* ayBuf[3];
|
||||||
size_t ayBufLen;
|
size_t ayBufLen;
|
||||||
|
|
||||||
|
void runDAC();
|
||||||
|
void checkWrites();
|
||||||
void updateOutSel(bool immediate=false);
|
void updateOutSel(bool immediate=false);
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -77,14 +77,80 @@ const char** DivPlatformAY8930::getRegisterSheet() {
|
||||||
return regCheatSheetAY8930;
|
return regCheatSheetAY8930;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
/* C program to generate this table:
|
||||||
if (ayBufLen<len) {
|
|
||||||
ayBufLen=len;
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
for (int i=0; i<256; i++) {
|
||||||
|
if ((i&15)==0) printf("\n ");
|
||||||
|
printf(" %d,",(int)round(pow((double)i/255.0,0.3)*31.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const unsigned char dacLogTableAY8930[256]={
|
||||||
|
0, 6, 7, 8, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13,
|
||||||
|
14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16,
|
||||||
|
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19,
|
||||||
|
19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||||
|
20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
|
||||||
|
22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||||
|
23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||||
|
24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||||
|
25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||||
|
26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||||
|
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28,
|
||||||
|
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||||
|
28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||||
|
29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30,
|
||||||
|
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
||||||
|
30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31
|
||||||
|
};
|
||||||
|
|
||||||
|
void DivPlatformAY8930::runDAC() {
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
delete[] ayBuf[i];
|
if (chan[i].psgMode.dac && chan[i].dac.sample!=-1) {
|
||||||
ayBuf[i]=new short[ayBufLen];
|
chan[i].dac.period+=chan[i].dac.rate;
|
||||||
|
bool end=false;
|
||||||
|
bool changed=false;
|
||||||
|
int prevOut=chan[i].dac.out;
|
||||||
|
while (chan[i].dac.period>rate && !end) {
|
||||||
|
DivSample* s=parent->getSample(chan[i].dac.sample);
|
||||||
|
if (s->samples<=0) {
|
||||||
|
chan[i].dac.sample=-1;
|
||||||
|
immWrite(0x08+i,0);
|
||||||
|
end=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unsigned char dacData=dacLogTableAY8930[(unsigned char)s->data8[chan[i].dac.pos]^0x80];
|
||||||
|
chan[i].dac.out=MAX(0,dacData-(31-chan[i].outVol));
|
||||||
|
if (prevOut!=chan[i].dac.out) {
|
||||||
|
prevOut=chan[i].dac.out;
|
||||||
|
changed=true;
|
||||||
|
}
|
||||||
|
chan[i].dac.pos++;
|
||||||
|
if (s->isLoopable() && chan[i].dac.pos>=s->loopEnd) {
|
||||||
|
chan[i].dac.pos=s->loopStart;
|
||||||
|
} else if (chan[i].dac.pos>=(int)s->samples) {
|
||||||
|
chan[i].dac.sample=-1;
|
||||||
|
//immWrite(0x08+i,0);
|
||||||
|
end=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chan[i].dac.period-=rate;
|
||||||
|
}
|
||||||
|
if (changed && !end) {
|
||||||
|
if (!isMuted[i]) {
|
||||||
|
immWrite(0x08+i,chan[i].dac.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformAY8930::checkWrites() {
|
||||||
while (!writes.empty()) {
|
while (!writes.empty()) {
|
||||||
QueuedWrite w=writes.front();
|
QueuedWrite w=writes.front();
|
||||||
ay->address_w(w.addr);
|
ay->address_w(w.addr);
|
||||||
|
@ -96,45 +162,55 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
}
|
}
|
||||||
writes.pop();
|
writes.pop();
|
||||||
}
|
}
|
||||||
ay->sound_stream_update(ayBuf,len);
|
}
|
||||||
if (stereo) {
|
|
||||||
for (size_t i=0; i<len; i++) {
|
void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
bufL[i+start]=ayBuf[0][i]+ayBuf[1][i]+((ayBuf[2][i]*stereoSep)>>8);
|
if (ayBufLen<len) {
|
||||||
bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i];
|
ayBufLen=len;
|
||||||
}
|
for (int i=0; i<3; i++) {
|
||||||
} else {
|
delete[] ayBuf[i];
|
||||||
for (size_t i=0; i<len; i++) {
|
ayBuf[i]=new short[ayBufLen];
|
||||||
bufL[i+start]=ayBuf[0][i]+ayBuf[1][i]+ayBuf[2][i];
|
|
||||||
bufR[i+start]=bufL[i+start];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ch=0; ch<3; ch++) {
|
for (size_t i=0; i<len; i++) {
|
||||||
for (size_t i=0; i<len; i++) {
|
runDAC();
|
||||||
oscBuf[ch]->data[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2;
|
checkWrites();
|
||||||
|
|
||||||
|
ay->sound_stream_update(ayBuf,1);
|
||||||
|
if (stereo) {
|
||||||
|
bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+((ayBuf[2][0]*stereoSep)>>8);
|
||||||
|
bufR[i+start]=((ayBuf[0][0]*stereoSep)>>8)+ayBuf[1][0]+ayBuf[2][0];
|
||||||
|
} else {
|
||||||
|
bufL[i+start]=ayBuf[0][0]+ayBuf[1][0]+ayBuf[2][0];
|
||||||
|
bufR[i+start]=bufL[i+start];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oscBuf[0]->data[oscBuf[0]->needle++]=ayBuf[0][0]<<2;
|
||||||
|
oscBuf[1]->data[oscBuf[1]->needle++]=ayBuf[1][0]<<2;
|
||||||
|
oscBuf[2]->data[oscBuf[2]->needle++]=ayBuf[2][0]<<2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformAY8930::updateOutSel(bool immediate) {
|
void DivPlatformAY8930::updateOutSel(bool immediate) {
|
||||||
if (immediate) {
|
if (immediate) {
|
||||||
immWrite(0x07,
|
immWrite(0x07,
|
||||||
~((chan[0].psgMode&1)|
|
~((chan[0].psgMode.getTone())|
|
||||||
((chan[1].psgMode&1)<<1)|
|
((chan[1].psgMode.getTone())<<1)|
|
||||||
((chan[2].psgMode&1)<<2)|
|
((chan[2].psgMode.getTone())<<2)|
|
||||||
((chan[0].psgMode&2)<<2)|
|
((chan[0].psgMode.getNoise())<<2)|
|
||||||
((chan[1].psgMode&2)<<3)|
|
((chan[1].psgMode.getNoise())<<3)|
|
||||||
((chan[2].psgMode&2)<<4)|
|
((chan[2].psgMode.getNoise())<<4)|
|
||||||
((!ioPortA)<<6)|
|
((!ioPortA)<<6)|
|
||||||
((!ioPortB)<<7)));
|
((!ioPortB)<<7)));
|
||||||
} else {
|
} else {
|
||||||
rWrite(0x07,
|
rWrite(0x07,
|
||||||
~((chan[0].psgMode&1)|
|
~((chan[0].psgMode.getTone())|
|
||||||
((chan[1].psgMode&1)<<1)|
|
((chan[1].psgMode.getTone())<<1)|
|
||||||
((chan[2].psgMode&1)<<2)|
|
((chan[2].psgMode.getTone())<<2)|
|
||||||
((chan[0].psgMode&2)<<2)|
|
((chan[0].psgMode.getNoise())<<2)|
|
||||||
((chan[1].psgMode&2)<<3)|
|
((chan[1].psgMode.getNoise())<<3)|
|
||||||
((chan[2].psgMode&2)<<4)|
|
((chan[2].psgMode.getNoise())<<4)|
|
||||||
((!ioPortA)<<6)|
|
((!ioPortA)<<6)|
|
||||||
((!ioPortB)<<7)));
|
((!ioPortB)<<7)));
|
||||||
}
|
}
|
||||||
|
@ -159,10 +235,12 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
||||||
if (chan[i].std.vol.had) {
|
if (chan[i].std.vol.had) {
|
||||||
chan[i].outVol=MIN(31,chan[i].std.vol.val)-(31-(chan[i].vol&31));
|
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 (chan[i].outVol<0) chan[i].outVol=0;
|
||||||
if (isMuted[i]) {
|
if (!chan[i].psgMode.dac) {
|
||||||
rWrite(0x08+i,0);
|
if (isMuted[i]) {
|
||||||
} else {
|
rWrite(0x08+i,0);
|
||||||
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
|
} else {
|
||||||
|
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode.getEnvelope())<<3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
|
@ -175,11 +253,13 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
||||||
rWrite(0x06,chan[i].std.duty.val);
|
rWrite(0x06,chan[i].std.duty.val);
|
||||||
}
|
}
|
||||||
if (chan[i].std.wave.had) {
|
if (chan[i].std.wave.had) {
|
||||||
|
if (!chan[i].psgMode.dac) {
|
||||||
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
chan[i].psgMode=(chan[i].std.wave.val+1)&7;
|
||||||
if (isMuted[i]) {
|
if (isMuted[i]) {
|
||||||
rWrite(0x08+i,0);
|
rWrite(0x08+i,0);
|
||||||
} else {
|
} 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) {
|
if (chan[i].std.pitch.had) {
|
||||||
|
@ -193,6 +273,20 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
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[0x08+i]=-1;
|
||||||
oldWrites[regMode[i]]=-1;
|
oldWrites[regMode[i]]=-1;
|
||||||
}
|
}
|
||||||
|
@ -224,6 +318,19 @@ void DivPlatformAY8930::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
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);
|
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*4.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].freq>65535) chan[i].freq=65535;
|
||||||
if (chan[i].keyOn) {
|
if (chan[i].keyOn) {
|
||||||
if (chan[i].insChanged) {
|
if (chan[i].insChanged) {
|
||||||
|
@ -281,6 +388,62 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930);
|
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*4096;
|
||||||
|
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) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
|
@ -292,14 +455,19 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
}
|
}
|
||||||
if (isMuted[c.chan]) {
|
if (!chan[c.chan].psgMode.dac) {
|
||||||
rWrite(0x08+c.chan,0);
|
if (isMuted[c.chan]) {
|
||||||
} else {
|
rWrite(0x08+c.chan,0);
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3));
|
} else {
|
||||||
|
rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_OFF:
|
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].keyOff=true;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
|
@ -313,13 +481,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
}
|
}
|
||||||
if (isMuted[c.chan]) {
|
if (!chan[c.chan].psgMode.dac) {
|
||||||
rWrite(0x08+c.chan,0);
|
if (isMuted[c.chan]) {
|
||||||
} else {
|
rWrite(0x08+c.chan,0);
|
||||||
if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode&4)<<3));
|
} else {
|
||||||
|
if (chan[c.chan].active) rWrite(0x08+c.chan,(chan[c.chan].vol&31)|((chan[c.chan].psgMode.getEnvelope())<<3));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case DIV_CMD_GET_VOLUME: {
|
case DIV_CMD_GET_VOLUME: {
|
||||||
return chan[c.chan].vol;
|
return chan[c.chan].vol;
|
||||||
|
@ -366,11 +536,13 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
case DIV_CMD_STD_NOISE_MODE:
|
case DIV_CMD_STD_NOISE_MODE:
|
||||||
if (c.value<0x10) {
|
if (c.value<0x10) {
|
||||||
chan[c.chan].psgMode=(c.value+1)&7;
|
if (!chan[c.chan].psgMode.dac) {
|
||||||
if (isMuted[c.chan]) {
|
chan[c.chan].psgMode=(c.value+1)&7;
|
||||||
rWrite(0x08+c.chan,0);
|
if (isMuted[c.chan]) {
|
||||||
} else if (chan[c.chan].active) {
|
rWrite(0x08+c.chan,0);
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode&4)<<3));
|
} else if (chan[c.chan].active) {
|
||||||
|
rWrite(0x08+c.chan,(chan[c.chan].outVol&31)|((chan[c.chan].psgMode.getEnvelope())<<3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].duty=c.value&15;
|
chan[c.chan].duty=c.value&15;
|
||||||
|
@ -384,14 +556,14 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||||
chan[c.chan].envelope.mode=c.value>>4;
|
chan[c.chan].envelope.mode=c.value>>4;
|
||||||
rWrite(regMode[c.chan],chan[c.chan].envelope.mode);
|
rWrite(regMode[c.chan],chan[c.chan].envelope.mode);
|
||||||
if (c.value&15) {
|
if (c.value&15) {
|
||||||
chan[c.chan].psgMode|=4;
|
chan[c.chan].psgMode.envelope|=1;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].psgMode&=~4;
|
chan[c.chan].psgMode.envelope&=~1;
|
||||||
}
|
}
|
||||||
if (isMuted[c.chan]) {
|
if (isMuted[c.chan]) {
|
||||||
rWrite(0x08+c.chan,0);
|
rWrite(0x08+c.chan,0);
|
||||||
} else {
|
} 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;
|
break;
|
||||||
case DIV_CMD_AY_ENVELOPE_LOW:
|
case DIV_CMD_AY_ENVELOPE_LOW:
|
||||||
|
@ -439,6 +611,15 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
|
||||||
updateOutSel(true);
|
updateOutSel(true);
|
||||||
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
|
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
|
||||||
break;
|
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:
|
case DIV_ALWAYS_SET_VOLUME:
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
@ -466,7 +647,11 @@ void DivPlatformAY8930::muteChannel(int ch, bool mute) {
|
||||||
if (isMuted[ch]) {
|
if (isMuted[ch]) {
|
||||||
rWrite(0x08+ch,0);
|
rWrite(0x08+ch,0);
|
||||||
} else if (chan[ch].active) {
|
} 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,6 +706,7 @@ void DivPlatformAY8930::reset() {
|
||||||
pendingWrites[i]=-1;
|
pendingWrites[i]=-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sampleBank=0;
|
||||||
ayNoiseAnd=2;
|
ayNoiseAnd=2;
|
||||||
ayNoiseOr=0;
|
ayNoiseOr=0;
|
||||||
delay=0;
|
delay=0;
|
||||||
|
|
|
@ -38,20 +38,86 @@ class DivPlatformAY8930: public DivDispatch {
|
||||||
slideLow(0),
|
slideLow(0),
|
||||||
slide(0) {}
|
slide(0) {}
|
||||||
} envelope;
|
} 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 freq, baseFreq, note, pitch, pitch2;
|
||||||
int ins;
|
int ins;
|
||||||
unsigned char psgMode, autoEnvNum, autoEnvDen, duty;
|
unsigned char autoEnvNum, autoEnvDen, duty;
|
||||||
signed char konCycles;
|
signed char konCycles;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
unsigned char pan;
|
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
pitch2=0;
|
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];
|
Channel chan[3];
|
||||||
bool isMuted[3];
|
bool isMuted[3];
|
||||||
|
@ -69,6 +135,8 @@ class DivPlatformAY8930: public DivDispatch {
|
||||||
unsigned char stereoSep;
|
unsigned char stereoSep;
|
||||||
bool bank;
|
bool bank;
|
||||||
|
|
||||||
|
unsigned char sampleBank;
|
||||||
|
|
||||||
int delay;
|
int delay;
|
||||||
|
|
||||||
bool extMode, stereo, clockSel;
|
bool extMode, stereo, clockSel;
|
||||||
|
@ -80,9 +148,12 @@ class DivPlatformAY8930: public DivDispatch {
|
||||||
short* ayBuf[3];
|
short* ayBuf[3];
|
||||||
size_t ayBufLen;
|
size_t ayBufLen;
|
||||||
|
|
||||||
|
void runDAC();
|
||||||
|
void checkWrites();
|
||||||
void updateOutSel(bool immediate=false);
|
void updateOutSel(bool immediate=false);
|
||||||
void immWrite(unsigned char a, unsigned char v);
|
void immWrite(unsigned char a, unsigned char v);
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -62,7 +62,8 @@ class DivPlatformBubSysWSG: public DivDispatch {
|
||||||
|
|
||||||
k005289_core k005289;
|
k005289_core k005289;
|
||||||
unsigned short regPool[4];
|
unsigned short regPool[4];
|
||||||
void updateWave(int ch);
|
void updateWave(int ch);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -82,7 +82,8 @@ class DivPlatformC64: public DivDispatch {
|
||||||
SID sid;
|
SID sid;
|
||||||
reSIDfp::SID sid_fp;
|
reSIDfp::SID sid_fp;
|
||||||
unsigned char regPool[32];
|
unsigned char regPool[32];
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void acquire_classic(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_classic(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -33,7 +33,8 @@ class DivPlatformDummy: public DivDispatch {
|
||||||
Channel chan[128];
|
Channel chan[128];
|
||||||
DivDispatchOscBuffer* oscBuf[128];
|
DivDispatchOscBuffer* oscBuf[128];
|
||||||
bool isMuted[128];
|
bool isMuted[128];
|
||||||
unsigned char chans;
|
unsigned char chans;
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -77,7 +77,8 @@ class DivPlatformFDS: public DivDispatch {
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
|
|
||||||
void updateWave();
|
void updateWave();
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void doWrite(unsigned short addr, unsigned char data);
|
void doWrite(unsigned short addr, unsigned char data);
|
||||||
|
|
|
@ -92,7 +92,8 @@ class DivPlatformGB: public DivDispatch {
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
|
|
||||||
unsigned char procMute();
|
unsigned char procMute();
|
||||||
void updateWave();
|
void updateWave();
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -52,7 +52,7 @@ void DivPlatformGenesis::processDAC() {
|
||||||
if (s->samples>0) {
|
if (s->samples>0) {
|
||||||
while (chan[i].dacPeriod>=(chipClock/576)) {
|
while (chan[i].dacPeriod>=(chipClock/576)) {
|
||||||
++chan[i].dacPos;
|
++chan[i].dacPos;
|
||||||
if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=s->getEndPosition())) {
|
if (!chan[i].dacDirection && (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd)) {
|
||||||
chan[i].dacPos=s->loopStart;
|
chan[i].dacPos=s->loopStart;
|
||||||
} else if (chan[i].dacPos>=s->samples) {
|
} else if (chan[i].dacPos>=s->samples) {
|
||||||
chan[i].dacSample=-1;
|
chan[i].dacSample=-1;
|
||||||
|
@ -98,7 +98,7 @@ void DivPlatformGenesis::processDAC() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chan[5].dacPos++;
|
chan[5].dacPos++;
|
||||||
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=s->getEndPosition())) {
|
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) {
|
||||||
chan[5].dacPos=s->loopStart;
|
chan[5].dacPos=s->loopStart;
|
||||||
} else if (chan[5].dacPos>=s->samples) {
|
} else if (chan[5].dacPos>=s->samples) {
|
||||||
chan[5].dacSample=-1;
|
chan[5].dacSample=-1;
|
||||||
|
|
|
@ -115,7 +115,8 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
||||||
bool ladder;
|
bool ladder;
|
||||||
|
|
||||||
unsigned char dacVolTable[128];
|
unsigned char dacVolTable[128];
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
inline void processDAC();
|
inline void processDAC();
|
||||||
|
|
|
@ -52,6 +52,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
||||||
};
|
};
|
||||||
OpChannel opChan[4];
|
OpChannel opChan[4];
|
||||||
bool isOpMuted[4];
|
bool isOpMuted[4];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#define WRITE_STEREO(v) rWrite(0x50,(v))
|
#define WRITE_STEREO(v) rWrite(0x50,(v))
|
||||||
|
|
||||||
#define CHIP_DIVIDER 64
|
#define CHIP_DIVIDER 64
|
||||||
|
#define CHIP_FREQBASE 16000000
|
||||||
|
|
||||||
#if defined( _MSC_VER )
|
#if defined( _MSC_VER )
|
||||||
|
|
||||||
|
@ -140,12 +141,12 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
|
||||||
if (s!=NULL) {
|
if (s!=NULL) {
|
||||||
if (isMuted[i]) {
|
if (isMuted[i]) {
|
||||||
WRITE_OUTPUT(i,0);
|
WRITE_OUTPUT(i,0);
|
||||||
chan[i].samplePos++;
|
|
||||||
} else {
|
} 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));
|
||||||
}
|
}
|
||||||
|
chan[i].samplePos++;
|
||||||
|
|
||||||
if (s->isLoopable() && chan[i].samplePos>=(int)s->getEndPosition()) {
|
if (s->isLoopable() && chan[i].samplePos>=s->loopEnd) {
|
||||||
chan[i].samplePos=s->loopStart;
|
chan[i].samplePos=s->loopStart;
|
||||||
} else if (chan[i].samplePos>=(int)s->samples) {
|
} else if (chan[i].samplePos>=(int)s->samples) {
|
||||||
chan[i].sample=-1;
|
chan[i].sample=-1;
|
||||||
|
@ -164,7 +165,7 @@ void DivPlatformLynx::tick(bool sysTick) {
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
if (chan[i].std.vol.had) {
|
if (chan[i].std.vol.had) {
|
||||||
if (chan[i].pcm) {
|
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 {
|
} else {
|
||||||
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7;
|
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7;
|
||||||
}
|
}
|
||||||
|
@ -174,7 +175,7 @@ void DivPlatformLynx::tick(bool sysTick) {
|
||||||
if (!chan[i].inPorta) {
|
if (!chan[i].inPorta) {
|
||||||
chan[i].actualNote=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
chan[i].actualNote=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||||
chan[i].baseFreq=NOTE_PERIODIC(chan[i].actualNote);
|
chan[i].baseFreq=NOTE_PERIODIC(chan[i].actualNote);
|
||||||
if (chan[i].pcm) chan[i].sampleBaseFreq=parent->calcBaseFreq(1.0,1.0,chan[i].actualNote,false);
|
if (chan[i].pcm) chan[i].sampleBaseFreq=NOTE_FREQUENCY(chan[i].actualNote);
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,6 +206,10 @@ void DivPlatformLynx::tick(bool sysTick) {
|
||||||
|
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
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_LFSR(i, 0);
|
||||||
WRITE_OTHER(i, 0);
|
WRITE_OTHER(i, 0);
|
||||||
}
|
}
|
||||||
|
@ -221,7 +226,7 @@ void DivPlatformLynx::tick(bool sysTick) {
|
||||||
off=(double)s->centerRate/8363.0;
|
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 {
|
} else {
|
||||||
if (chan[i].lfsr >= 0) {
|
if (chan[i].lfsr >= 0) {
|
||||||
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
||||||
|
@ -251,11 +256,12 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY);
|
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) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||||
if (chan[c.chan].pcm) {
|
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].sample=ins->amiga.getSample(c.value);
|
||||||
chan[c.chan].sampleAccum=0;
|
chan[c.chan].sampleAccum=0;
|
||||||
chan[c.chan].samplePos=0;
|
chan[c.chan].samplePos=0;
|
||||||
|
@ -268,7 +274,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
chan[c.chan].active=true;
|
chan[c.chan].active=true;
|
||||||
WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
|
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) {
|
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
}
|
}
|
||||||
|
@ -348,7 +354,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));
|
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);
|
chan[c.chan].baseFreq=NOTE_PERIODIC(whatAMess);
|
||||||
if (chan[c.chan].pcm) {
|
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].freqChanged=true;
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
|
|
|
@ -48,6 +48,7 @@ class DivPlatformLynx: public DivDispatch {
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, pcm;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, pcm;
|
||||||
signed char vol, outVol;
|
signed char vol, outVol;
|
||||||
|
int macroVolMul;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
pitch2=0;
|
pitch2=0;
|
||||||
|
@ -77,12 +78,14 @@ class DivPlatformLynx: public DivDispatch {
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
pcm(false),
|
pcm(false),
|
||||||
vol(127),
|
vol(127),
|
||||||
outVol(127) {}
|
outVol(127),
|
||||||
|
macroVolMul(127) {}
|
||||||
};
|
};
|
||||||
Channel chan[4];
|
Channel chan[4];
|
||||||
DivDispatchOscBuffer* oscBuf[4];
|
DivDispatchOscBuffer* oscBuf[4];
|
||||||
bool isMuted[4];
|
bool isMuted[4];
|
||||||
std::unique_ptr<Lynx::Mikey> mikey;
|
std::unique_ptr<Lynx::Mikey> mikey;
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -54,7 +54,7 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
|
||||||
rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80));
|
rWrite(0x5011,((unsigned char)s->data8[dacPos]+0x80));
|
||||||
}
|
}
|
||||||
dacPos++;
|
dacPos++;
|
||||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) {
|
if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) {
|
||||||
dacPos=s->loopStart;
|
dacPos=s->loopStart;
|
||||||
} else if (dacPos>=s->samples) {
|
} else if (dacPos>=s->samples) {
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
|
|
@ -67,7 +67,8 @@ class DivPlatformMMC5: public DivDispatch {
|
||||||
unsigned char writeOscBuf;
|
unsigned char writeOscBuf;
|
||||||
struct _mmc5* mmc5;
|
struct _mmc5* mmc5;
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -90,14 +90,56 @@ void DivPlatformMSM6258::acquire(short* bufL, short* bufR, size_t start, size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformMSM6258::tick(bool sysTick) {
|
void DivPlatformMSM6258::tick(bool sysTick) {
|
||||||
// nothing
|
for (int i=0; i<1; i++) {
|
||||||
|
if (!parent->song.disableSampleMacro) {
|
||||||
|
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) {
|
int DivPlatformMSM6258::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
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;
|
chan[c.chan].furnacePCM=true;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].furnacePCM=false;
|
chan[c.chan].furnacePCM=false;
|
||||||
|
@ -118,8 +160,6 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
chan[c.chan].active=true;
|
chan[c.chan].active=true;
|
||||||
chan[c.chan].keyOn=true;
|
chan[c.chan].keyOn=true;
|
||||||
rWrite(0,1);
|
|
||||||
rWrite(0,2);
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -133,8 +173,8 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
|
||||||
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||||
sample=12*sampleBank+c.value%12;
|
sample=12*sampleBank+c.value%12;
|
||||||
samplePos=0;
|
samplePos=0;
|
||||||
rWrite(0,1);
|
chan[c.chan].active=true;
|
||||||
rWrite(0,2);
|
chan[c.chan].keyOn=true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -142,18 +182,12 @@ int DivPlatformMSM6258::dispatch(DivCommand c) {
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
rWrite(0,1); // turn off
|
|
||||||
sample=-1;
|
|
||||||
samplePos=0;
|
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
case DIV_CMD_NOTE_OFF_ENV:
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
rWrite(0,1); // turn off
|
|
||||||
sample=-1;
|
|
||||||
samplePos=0;
|
|
||||||
chan[c.chan].std.release();
|
chan[c.chan].std.release();
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_ENV_RELEASE:
|
case DIV_CMD_ENV_RELEASE:
|
||||||
|
|
|
@ -87,6 +87,7 @@ class DivPlatformMSM6258: public DivDispatch {
|
||||||
|
|
||||||
int delay, updateOsc, sample, samplePos;
|
int delay, updateOsc, sample, samplePos;
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -88,14 +88,47 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformMSM6295::tick(bool sysTick) {
|
void DivPlatformMSM6295::tick(bool sysTick) {
|
||||||
// nothing
|
for (int i=0; i<4; i++) {
|
||||||
|
if (!parent->song.disableSampleMacro) {
|
||||||
|
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) {
|
int DivPlatformMSM6295::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
if (ins->type==DIV_INS_AMIGA) {
|
if (ins->type==DIV_INS_MSM6295 || ins->type==DIV_INS_AMIGA) {
|
||||||
chan[c.chan].furnacePCM=true;
|
chan[c.chan].furnacePCM=true;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].furnacePCM=false;
|
chan[c.chan].furnacePCM=false;
|
||||||
|
|
|
@ -46,8 +46,8 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
keyOff(false),
|
keyOff(false),
|
||||||
furnacePCM(false),
|
furnacePCM(false),
|
||||||
hardReset(false),
|
hardReset(false),
|
||||||
vol(0),
|
vol(8),
|
||||||
outVol(15),
|
outVol(8),
|
||||||
sample(-1) {}
|
sample(-1) {}
|
||||||
};
|
};
|
||||||
Channel chan[4];
|
Channel chan[4];
|
||||||
|
@ -74,6 +74,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
|
|
||||||
bool rateSel=false, rateSelInit=false;
|
bool rateSel=false, rateSelInit=false;
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -89,6 +89,7 @@ class DivPlatformN163: public DivDispatch {
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
void updateWave(int ch, int wave, int pos, int len);
|
void updateWave(int ch, int wave, int pos, int len);
|
||||||
void updateWaveCh(int ch);
|
void updateWaveCh(int ch);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -74,6 +74,7 @@ class DivPlatformNamcoWSG: public DivDispatch {
|
||||||
int devType, chans;
|
int devType, chans;
|
||||||
unsigned char regPool[512];
|
unsigned char regPool[512];
|
||||||
void updateWave(int ch);
|
void updateWave(int ch);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -88,7 +88,7 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
dacPos++; \
|
dacPos++; \
|
||||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) { \
|
if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) { \
|
||||||
dacPos=s->loopStart; \
|
dacPos=s->loopStart; \
|
||||||
} else if (dacPos>=s->samples) { \
|
} else if (dacPos>=s->samples) { \
|
||||||
dacSample=-1; \
|
dacSample=-1; \
|
||||||
|
|
|
@ -79,6 +79,7 @@ class DivPlatformNES: public DivDispatch {
|
||||||
xgm::NES_DMC* nes2_NP;
|
xgm::NES_DMC* nes2_NP;
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void doWrite(unsigned short addr, unsigned char data);
|
void doWrite(unsigned short addr, unsigned char data);
|
||||||
|
|
|
@ -485,7 +485,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
||||||
chan[adpcmChan].std.next();
|
chan[adpcmChan].std.next();
|
||||||
|
|
||||||
if (chan[adpcmChan].std.vol.had) {
|
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);
|
immWrite(18,chan[adpcmChan].outVol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,16 +495,40 @@ void DivPlatformOPL::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
chan[adpcmChan].freqChanged=true;
|
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) {
|
if (chan[adpcmChan].sample>=0 && chan[adpcmChan].sample<parent->song.sampleLen) {
|
||||||
double off=65535.0*(double)(parent->getSample(chan[adpcmChan].sample)->centerRate)/8363.0;
|
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/144,off);
|
||||||
} else {
|
} else {
|
||||||
chan[adpcmChan].freq=0;
|
chan[adpcmChan].freq=0;
|
||||||
}
|
}
|
||||||
|
if (chan[adpcmChan].fixedFreq>0) chan[adpcmChan].freq=chan[adpcmChan].fixedFreq;
|
||||||
|
if (pretendYMU) { // YMU759 only does 4KHz or 8KHz
|
||||||
|
if (chan[adpcmChan].freq>7500) {
|
||||||
|
chan[adpcmChan].freq=10922; // 8KHz
|
||||||
|
} else {
|
||||||
|
chan[adpcmChan].freq=5461; // 4KHz
|
||||||
|
}
|
||||||
|
}
|
||||||
immWrite(16,chan[adpcmChan].freq&0xff);
|
immWrite(16,chan[adpcmChan].freq&0xff);
|
||||||
immWrite(17,(chan[adpcmChan].freq>>8)&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;
|
chan[adpcmChan].freqChanged=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -648,7 +672,8 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
if (c.chan==adpcmChan) { // ADPCM
|
if (c.chan==adpcmChan) { // ADPCM
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
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;
|
chan[c.chan].furnacePCM=true;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].furnacePCM=false;
|
chan[c.chan].furnacePCM=false;
|
||||||
|
@ -656,6 +681,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
if (skipRegisterWrites) break;
|
if (skipRegisterWrites) break;
|
||||||
if (chan[c.chan].furnacePCM) {
|
if (chan[c.chan].furnacePCM) {
|
||||||
chan[c.chan].macroInit(ins);
|
chan[c.chan].macroInit(ins);
|
||||||
|
chan[c.chan].fixedFreq=0;
|
||||||
if (!chan[c.chan].std.vol.will) {
|
if (!chan[c.chan].std.vol.will) {
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
immWrite(18,chan[c.chan].outVol);
|
immWrite(18,chan[c.chan].outVol);
|
||||||
|
@ -664,13 +690,11 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||||
immWrite(8,0);
|
immWrite(8,0);
|
||||||
immWrite(7,0x01); // reset
|
|
||||||
immWrite(9,(s->offB>>2)&0xff);
|
immWrite(9,(s->offB>>2)&0xff);
|
||||||
immWrite(10,(s->offB>>10)&0xff);
|
immWrite(10,(s->offB>>10)&0xff);
|
||||||
int end=s->offB+s->lengthB-1;
|
int end=s->offB+s->lengthB-1;
|
||||||
immWrite(11,(end>>2)&0xff);
|
immWrite(11,(end>>2)&0xff);
|
||||||
immWrite(12,(end>>10)&0xff);
|
immWrite(12,(end>>10)&0xff);
|
||||||
immWrite(7,(s->isLoopable())?0xb0:0xa0); // start/repeat
|
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||||
|
@ -691,25 +715,30 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
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;
|
||||||
|
chan[c.chan].fixedFreq=freq;
|
||||||
|
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(7,0x01); // reset
|
||||||
immWrite(9,0);
|
immWrite(9,0);
|
||||||
immWrite(10,0);
|
immWrite(10,0);
|
||||||
immWrite(11,0);
|
immWrite(11,0);
|
||||||
immWrite(12,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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -861,19 +890,11 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_OFF:
|
case DIV_CMD_NOTE_OFF:
|
||||||
if (c.chan==adpcmChan) {
|
|
||||||
immWrite(7,0x01); // reset
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
case DIV_CMD_NOTE_OFF_ENV:
|
||||||
if (c.chan==adpcmChan) {
|
|
||||||
immWrite(7,0x01); // reset
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=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;
|
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnacePCM, inPorta, fourOp, hardReset;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
|
int macroVolMul;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
pitch2=0;
|
pitch2=0;
|
||||||
|
@ -70,7 +71,8 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
fourOp(false),
|
fourOp(false),
|
||||||
hardReset(false),
|
hardReset(false),
|
||||||
vol(0),
|
vol(0),
|
||||||
pan(3) {
|
pan(3),
|
||||||
|
macroVolMul(64) {
|
||||||
state.ops=2;
|
state.ops=2;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -116,6 +118,7 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
double NOTE_ADPCMB(int note);
|
double NOTE_ADPCMB(int note);
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -93,6 +93,7 @@ class DivPlatformOPLL: public DivDispatch {
|
||||||
int octave(int freq);
|
int octave(int freq);
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -66,10 +66,17 @@ void DivPlatformPCE::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
chWrite(i,0x07,0);
|
chWrite(i,0x07,0);
|
||||||
chWrite(i,0x04,0xdf);
|
signed char dacData=((signed char)((unsigned char)s->data8[chan[i].dacPos]^0x80))>>3;
|
||||||
chWrite(i,0x06,(((unsigned char)s->data8[chan[i].dacPos]+0x80)>>3));
|
chan[i].dacOut=CLAMP(dacData,-16,15);
|
||||||
|
if (!isMuted[i]) {
|
||||||
|
chWrite(i,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].outVol));
|
||||||
|
chWrite(i,0x06,chan[i].dacOut&0x1f);
|
||||||
|
} else {
|
||||||
|
chWrite(i,0x04,0xc0);
|
||||||
|
chWrite(i,0x06,0x10);
|
||||||
|
}
|
||||||
chan[i].dacPos++;
|
chan[i].dacPos++;
|
||||||
if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) {
|
if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd) {
|
||||||
chan[i].dacPos=s->loopStart;
|
chan[i].dacPos=s->loopStart;
|
||||||
} else if (chan[i].dacPos>=s->samples) {
|
} else if (chan[i].dacPos>=s->samples) {
|
||||||
chan[i].dacSample=-1;
|
chan[i].dacSample=-1;
|
||||||
|
@ -197,6 +204,15 @@ void DivPlatformPCE::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
if (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1) {
|
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,parent->song.disableSampleMacro?0xdf:(0xc0|chan[i].vol));
|
||||||
|
addWrite(0xffff0000+(i<<8),chan[i].dacSample);
|
||||||
|
chan[i].keyOn=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
chan[i].antiClickWavePos=0;
|
chan[i].antiClickWavePos=0;
|
||||||
chan[i].antiClickPeriodCount=0;
|
chan[i].antiClickPeriodCount=0;
|
||||||
}
|
}
|
||||||
|
@ -242,13 +258,14 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE);
|
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;
|
chan[c.chan].pcm=true;
|
||||||
} else if (chan[c.chan].furnaceDac) {
|
} else if (chan[c.chan].furnaceDac) {
|
||||||
chan[c.chan].pcm=false;
|
chan[c.chan].pcm=false;
|
||||||
}
|
}
|
||||||
if (chan[c.chan].pcm) {
|
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;
|
chan[c.chan].furnaceDac=true;
|
||||||
if (skipRegisterWrites) break;
|
if (skipRegisterWrites) break;
|
||||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||||
|
@ -258,7 +275,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (dumpWrites) {
|
if (dumpWrites) {
|
||||||
chWrite(c.chan,0x04,0xdf);
|
chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol));
|
||||||
addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
|
addWrite(0xffff0000+(c.chan<<8),chan[c.chan].dacSample);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,6 +288,9 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
chan[c.chan].active=true;
|
chan[c.chan].active=true;
|
||||||
chan[c.chan].macroInit(ins);
|
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].keyOn=true;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].furnaceDac=false;
|
chan[c.chan].furnaceDac=false;
|
||||||
|
@ -290,7 +310,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
chan[c.chan].dacPeriod=0;
|
chan[c.chan].dacPeriod=0;
|
||||||
chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate;
|
chan[c.chan].dacRate=parent->getSample(chan[c.chan].dacSample)->rate;
|
||||||
if (dumpWrites) {
|
if (dumpWrites) {
|
||||||
chWrite(c.chan,0x04,0xdf);
|
chWrite(c.chan,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[c.chan].vol));
|
||||||
addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate);
|
addWrite(0xffff0001+(c.chan<<8),chan[c.chan].dacRate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,7 +362,9 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
chan[c.chan].vol=c.value;
|
chan[c.chan].vol=c.value;
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
if (chan[c.chan].active) chWrite(c.chan,0x04,0x80|chan[c.chan].outVol);
|
if (chan[c.chan].active && !chan[c.chan].pcm) {
|
||||||
|
chWrite(c.chan,0x04,0x80|chan[c.chan].outVol);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -443,6 +465,10 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
void DivPlatformPCE::muteChannel(int ch, bool mute) {
|
void DivPlatformPCE::muteChannel(int ch, bool mute) {
|
||||||
isMuted[ch]=mute;
|
isMuted[ch]=mute;
|
||||||
chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan);
|
chWrite(ch,0x05,isMuted[ch]?0:chan[ch].pan);
|
||||||
|
if (!isMuted[ch] && (chan[ch].pcm && chan[ch].dacSample!=-1)) {
|
||||||
|
chWrite(ch,0x04,parent->song.disableSampleMacro?0xdf:(0xc0|chan[ch].outVol));
|
||||||
|
chWrite(ch,0x06,chan[ch].dacOut&0x1f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformPCE::forceIns() {
|
void DivPlatformPCE::forceIns() {
|
||||||
|
|
|
@ -29,12 +29,13 @@
|
||||||
class DivPlatformPCE: public DivDispatch {
|
class DivPlatformPCE: public DivDispatch {
|
||||||
struct Channel {
|
struct Channel {
|
||||||
int freq, baseFreq, pitch, pitch2, note, antiClickPeriodCount, antiClickWavePos;
|
int freq, baseFreq, pitch, pitch2, note, antiClickPeriodCount, antiClickWavePos;
|
||||||
int dacPeriod, dacRate;
|
int dacPeriod, dacRate, dacOut;
|
||||||
unsigned int dacPos;
|
unsigned int dacPos;
|
||||||
int dacSample, ins;
|
int dacSample, ins;
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac, deferredWaveUpdate;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, noise, pcm, furnaceDac, deferredWaveUpdate;
|
||||||
signed char vol, outVol, wave;
|
signed char vol, outVol, wave;
|
||||||
|
int macroVolMul;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
DivWaveSynth ws;
|
DivWaveSynth ws;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
|
@ -51,6 +52,7 @@ class DivPlatformPCE: public DivDispatch {
|
||||||
antiClickWavePos(0),
|
antiClickWavePos(0),
|
||||||
dacPeriod(0),
|
dacPeriod(0),
|
||||||
dacRate(0),
|
dacRate(0),
|
||||||
|
dacOut(0),
|
||||||
dacPos(0),
|
dacPos(0),
|
||||||
dacSample(-1),
|
dacSample(-1),
|
||||||
ins(-1),
|
ins(-1),
|
||||||
|
@ -67,7 +69,8 @@ class DivPlatformPCE: public DivDispatch {
|
||||||
deferredWaveUpdate(false),
|
deferredWaveUpdate(false),
|
||||||
vol(31),
|
vol(31),
|
||||||
outVol(31),
|
outVol(31),
|
||||||
wave(-1) {}
|
wave(-1),
|
||||||
|
macroVolMul(31) {}
|
||||||
};
|
};
|
||||||
Channel chan[6];
|
Channel chan[6];
|
||||||
DivDispatchOscBuffer* oscBuf[6];
|
DivDispatchOscBuffer* oscBuf[6];
|
||||||
|
@ -88,6 +91,7 @@ class DivPlatformPCE: public DivDispatch {
|
||||||
PCE_PSG* pce;
|
PCE_PSG* pce;
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
void updateWave(int ch);
|
void updateWave(int ch);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -36,26 +36,73 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (chan.useWave || (chan.sample>=0 && chan.sample<parent->song.sampleLen)) {
|
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);
|
chan.audSub+=(chan.freq&0xffff);
|
||||||
if (chan.audSub>=0x10000) {
|
if (chan.audSub>=0x10000) {
|
||||||
chan.audSub-=0x10000;
|
chan.audSub-=0x10000;
|
||||||
chan.audPos+=1;
|
chan.audPos+=((!chan.useWave) && chan.audDir)?-1:1;
|
||||||
}
|
}
|
||||||
if (chan.useWave) {
|
if (chan.useWave) {
|
||||||
if (chan.audPos>=(unsigned int)(chan.audLen<<1)) {
|
if (chan.audPos>=(int)chan.audLen) {
|
||||||
chan.audPos=0;
|
chan.audPos%=chan.audLen;
|
||||||
|
chan.audDir=false;
|
||||||
}
|
}
|
||||||
output=(chan.ws.output[chan.audPos]^0x80)<<8;
|
output=(chan.ws.output[chan.audPos]^0x80)<<8;
|
||||||
} else {
|
} else {
|
||||||
DivSample* s=parent->getSample(chan.sample);
|
DivSample* s=parent->getSample(chan.sample);
|
||||||
if (s->samples>0) {
|
if (s->samples>0) {
|
||||||
if (s->isLoopable() && chan.audPos>=s->getEndPosition()) {
|
if (chan.audDir) {
|
||||||
chan.audPos=s->loopStart;
|
if (s->isLoopable()) {
|
||||||
} else if (chan.audPos>=s->samples) {
|
switch (s->loopMode) {
|
||||||
chan.sample=-1;
|
case DIV_SAMPLE_LOOP_FORWARD:
|
||||||
|
case DIV_SAMPLE_LOOP_PINGPONG:
|
||||||
|
if (chan.audPos<s->loopStart) {
|
||||||
|
chan.audPos=s->loopStart+(s->loopStart-chan.audPos);
|
||||||
|
chan.audDir=false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_LOOP_BACKWARD:
|
||||||
|
if (chan.audPos<s->loopStart) {
|
||||||
|
chan.audPos=s->loopEnd-1-(s->loopStart-chan.audPos);
|
||||||
|
chan.audDir=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (chan.audPos<0) {
|
||||||
|
chan.sample=-1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (chan.audPos>=(int)s->samples) {
|
||||||
|
chan.sample=-1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (s->isLoopable()) {
|
||||||
|
switch (s->loopMode) {
|
||||||
|
case DIV_SAMPLE_LOOP_FORWARD:
|
||||||
|
if (chan.audPos>=s->loopEnd) {
|
||||||
|
chan.audPos=(chan.audPos+s->loopStart)-s->loopEnd;
|
||||||
|
chan.audDir=false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_LOOP_BACKWARD:
|
||||||
|
case DIV_SAMPLE_LOOP_PINGPONG:
|
||||||
|
if (chan.audPos>=s->loopEnd) {
|
||||||
|
chan.audPos=s->loopEnd-1-(s->loopEnd-1-chan.audPos);
|
||||||
|
chan.audDir=true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (chan.audPos>=(int)s->samples) {
|
||||||
|
chan.sample=-1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (chan.audPos>=(int)s->samples) {
|
||||||
|
chan.sample=-1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (chan.audPos<s->samples) {
|
if (chan.audPos>=0 && chan.audPos<(int)s->samples) {
|
||||||
output=s->data16[chan.audPos];
|
output=s->data16[chan.audPos];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -116,6 +163,7 @@ void DivPlatformPCMDAC::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan.std.phaseReset.had) {
|
if (chan.std.phaseReset.had) {
|
||||||
if (chan.std.phaseReset.val==1) {
|
if (chan.std.phaseReset.val==1) {
|
||||||
|
chan.audDir=false;
|
||||||
chan.audPos=0;
|
chan.audPos=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,11 +195,11 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
||||||
DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_AMIGA);
|
DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_AMIGA);
|
||||||
if (ins->amiga.useWave) {
|
if (ins->amiga.useWave) {
|
||||||
chan.useWave=true;
|
chan.useWave=true;
|
||||||
chan.audLen=(ins->amiga.waveLen+1)>>1;
|
chan.audLen=ins->amiga.waveLen;
|
||||||
if (chan.insChanged) {
|
if (chan.insChanged) {
|
||||||
if (chan.wave<0) {
|
if (chan.wave<0) {
|
||||||
chan.wave=0;
|
chan.wave=0;
|
||||||
chan.ws.setWidth(chan.audLen<<1);
|
chan.ws.setWidth(chan.audLen);
|
||||||
chan.ws.changeWave1(chan.wave);
|
chan.ws.changeWave1(chan.wave);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +216,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
||||||
if (chan.setPos) {
|
if (chan.setPos) {
|
||||||
chan.setPos=false;
|
chan.setPos=false;
|
||||||
} else {
|
} else {
|
||||||
|
chan.audDir=false;
|
||||||
chan.audPos=0;
|
chan.audPos=0;
|
||||||
}
|
}
|
||||||
chan.audSub=0;
|
chan.audSub=0;
|
||||||
|
@ -182,7 +231,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) {
|
||||||
chan.envVol=64;
|
chan.envVol=64;
|
||||||
}
|
}
|
||||||
if (chan.useWave) {
|
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;
|
chan.insChanged=false;
|
||||||
break;
|
break;
|
||||||
|
@ -289,6 +338,7 @@ void DivPlatformPCMDAC::muteChannel(int ch, bool mute) {
|
||||||
void DivPlatformPCMDAC::forceIns() {
|
void DivPlatformPCMDAC::forceIns() {
|
||||||
chan.insChanged=true;
|
chan.insChanged=true;
|
||||||
chan.freqChanged=true;
|
chan.freqChanged=true;
|
||||||
|
chan.audDir=false;
|
||||||
chan.audPos=0;
|
chan.audPos=0;
|
||||||
chan.sample=-1;
|
chan.sample=-1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,10 @@
|
||||||
class DivPlatformPCMDAC: public DivDispatch {
|
class DivPlatformPCMDAC: public DivDispatch {
|
||||||
struct Channel {
|
struct Channel {
|
||||||
int freq, baseFreq, pitch, pitch2;
|
int freq, baseFreq, pitch, pitch2;
|
||||||
|
bool audDir;
|
||||||
unsigned int audLoc;
|
unsigned int audLoc;
|
||||||
unsigned short audLen;
|
unsigned short audLen;
|
||||||
unsigned int audPos;
|
int audPos;
|
||||||
int audSub;
|
int audSub;
|
||||||
int sample, wave, ins;
|
int sample, wave, ins;
|
||||||
int note;
|
int note;
|
||||||
|
@ -48,6 +49,7 @@ class DivPlatformPCMDAC: public DivDispatch {
|
||||||
baseFreq(0),
|
baseFreq(0),
|
||||||
pitch(0),
|
pitch(0),
|
||||||
pitch2(0),
|
pitch2(0),
|
||||||
|
audDir(false),
|
||||||
audLoc(0),
|
audLoc(0),
|
||||||
audLen(0),
|
audLen(0),
|
||||||
audPos(0),
|
audPos(0),
|
||||||
|
@ -75,6 +77,7 @@ class DivPlatformPCMDAC: public DivDispatch {
|
||||||
int outDepth;
|
int outDepth;
|
||||||
bool outStereo;
|
bool outStereo;
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -84,6 +84,7 @@ class DivPlatformPCSpeaker: public DivDispatch {
|
||||||
unsigned short freq, lastFreq;
|
unsigned short freq, lastFreq;
|
||||||
unsigned char regPool[2];
|
unsigned char regPool[2];
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void beepFreq(int freq, int delay=0);
|
void beepFreq(int freq, int delay=0);
|
||||||
|
|
|
@ -62,6 +62,7 @@ class DivPlatformPET: public DivDispatch {
|
||||||
bool isMuted;
|
bool isMuted;
|
||||||
|
|
||||||
unsigned char regPool[16];
|
unsigned char regPool[16];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -268,10 +268,16 @@ void DivPlatformQSound::tick(bool sysTick) {
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<16; i++) {
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
if (chan[i].std.vol.had) {
|
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
|
// Check if enabled and write volume
|
||||||
if (chan[i].active) {
|
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;
|
uint16_t qsound_bank = 0;
|
||||||
|
@ -283,16 +289,17 @@ void DivPlatformQSound::tick(bool sysTick) {
|
||||||
qsound_bank = 0x8000 | (s->offQSound >> 16);
|
qsound_bank = 0x8000 | (s->offQSound >> 16);
|
||||||
qsound_addr = s->offQSound & 0xffff;
|
qsound_addr = s->offQSound & 0xffff;
|
||||||
|
|
||||||
int length = s->getEndPosition();
|
int loopStart=s->loopStart;
|
||||||
|
int length = s->loopEnd;
|
||||||
if (length > 65536 - 16) {
|
if (length > 65536 - 16) {
|
||||||
length = 65536 - 16;
|
length = 65536 - 16;
|
||||||
}
|
}
|
||||||
if (s->loopStart == -1 || s->loopStart >= length) {
|
if (loopStart == -1 || loopStart >= length) {
|
||||||
qsound_end = s->offQSound + length + 15;
|
qsound_end = s->offQSound + length + 15;
|
||||||
qsound_loop = 15;
|
qsound_loop = 15;
|
||||||
} else {
|
} else {
|
||||||
qsound_end = s->offQSound + length;
|
qsound_end = s->offQSound + length;
|
||||||
qsound_loop = length - s->loopStart;
|
qsound_loop = length - loopStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
|
@ -301,6 +308,16 @@ void DivPlatformQSound::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
|
if (chan[i].isNewQSound && 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].isNewQSound && chan[i].std.ex1.had) {
|
||||||
|
immWrite(Q1_ECHO_FEEDBACK,chan[i].std.ex1.val&0x3fff);
|
||||||
|
}
|
||||||
|
if (chan[i].isNewQSound && 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.had) {
|
||||||
if (chan[i].std.pitch.mode) {
|
if (chan[i].std.pitch.mode) {
|
||||||
chan[i].pitch2+=chan[i].std.pitch.val;
|
chan[i].pitch2+=chan[i].std.pitch.val;
|
||||||
|
@ -319,6 +336,11 @@ void DivPlatformQSound::tick(bool sysTick) {
|
||||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||||
immWrite(Q1_PAN+i,chan[i].panning+0x110+(chan[i].surround?0:0x30));
|
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) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
|
//DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
|
||||||
double off=1.0;
|
double off=1.0;
|
||||||
|
@ -341,16 +363,21 @@ void DivPlatformQSound::tick(bool sysTick) {
|
||||||
//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
|
// Write sample address. Enable volume
|
||||||
if (!chan[i].std.vol.had) {
|
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) {
|
if (chan[i].keyOff) {
|
||||||
// Disable volume
|
// Disable volume
|
||||||
rWrite(q1_reg_map[Q1V_VOL][i], 0);
|
rWrite(q1_reg_map[Q1V_VOL][i],0);
|
||||||
rWrite(q1_reg_map[Q1V_FREQ][i], 0);
|
rWrite(q1_reg_map[Q1V_FREQ][i],0);
|
||||||
} else if (chan[i].active) {
|
} 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));
|
//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].keyOn) chan[i].keyOn=false;
|
||||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||||
|
@ -363,6 +390,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
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);
|
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(c.value);
|
chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(c.value);
|
||||||
|
@ -379,6 +407,11 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
||||||
chan[c.chan].macroInit(ins);
|
chan[c.chan].macroInit(ins);
|
||||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -403,8 +436,13 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
// Check if enabled and write volume
|
// Check if enabled and write volume
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
if (chan[c.chan].active && c.chan < 16) {
|
if (chan[c.chan].isNewQSound) {
|
||||||
rWrite(q1_reg_map[Q1V_VOL][c.chan], chan[c.chan].outVol << 4);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,7 +458,8 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
||||||
immWrite(Q1_PAN+c.chan,chan[c.chan].panning+0x110+(chan[c.chan].surround?0:0x30));
|
immWrite(Q1_PAN+c.chan,chan[c.chan].panning+0x110+(chan[c.chan].surround?0:0x30));
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_QSOUND_ECHO_LEVEL:
|
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;
|
break;
|
||||||
case DIV_CMD_QSOUND_ECHO_FEEDBACK:
|
case DIV_CMD_QSOUND_ECHO_FEEDBACK:
|
||||||
immWrite(Q1_ECHO_FEEDBACK, c.value << 6);
|
immWrite(Q1_ECHO_FEEDBACK, c.value << 6);
|
||||||
|
|
|
@ -28,13 +28,12 @@
|
||||||
class DivPlatformQSound: public DivDispatch {
|
class DivPlatformQSound: public DivDispatch {
|
||||||
struct Channel {
|
struct Channel {
|
||||||
int freq, baseFreq, pitch, pitch2;
|
int freq, baseFreq, pitch, pitch2;
|
||||||
unsigned short audLen;
|
|
||||||
unsigned int audPos;
|
|
||||||
int sample, wave, ins;
|
int sample, wave, ins;
|
||||||
int note;
|
int note;
|
||||||
int panning;
|
int panning;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround;
|
int echo;
|
||||||
int vol, outVol;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, surround, isNewQSound;
|
||||||
|
int vol, outVol, resVol;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
|
@ -45,12 +44,11 @@ class DivPlatformQSound: public DivDispatch {
|
||||||
baseFreq(0),
|
baseFreq(0),
|
||||||
pitch(0),
|
pitch(0),
|
||||||
pitch2(0),
|
pitch2(0),
|
||||||
audLen(0),
|
|
||||||
audPos(0),
|
|
||||||
sample(-1),
|
sample(-1),
|
||||||
ins(-1),
|
ins(-1),
|
||||||
note(0),
|
note(0),
|
||||||
panning(0x10),
|
panning(0x10),
|
||||||
|
echo(0),
|
||||||
active(false),
|
active(false),
|
||||||
insChanged(true),
|
insChanged(true),
|
||||||
freqChanged(false),
|
freqChanged(false),
|
||||||
|
@ -59,8 +57,10 @@ class DivPlatformQSound: public DivDispatch {
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
useWave(false),
|
useWave(false),
|
||||||
surround(true),
|
surround(true),
|
||||||
|
isNewQSound(false),
|
||||||
vol(255),
|
vol(255),
|
||||||
outVol(255) {}
|
outVol(255),
|
||||||
|
resVol(4096) {}
|
||||||
};
|
};
|
||||||
Channel chan[19];
|
Channel chan[19];
|
||||||
DivDispatchOscBuffer* oscBuf[19];
|
DivDispatchOscBuffer* oscBuf[19];
|
||||||
|
@ -72,6 +72,7 @@ class DivPlatformQSound: public DivDispatch {
|
||||||
struct qsound_chip chip;
|
struct qsound_chip chip;
|
||||||
unsigned short regPool[512];
|
unsigned short regPool[512];
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -79,7 +79,7 @@ void DivPlatformRF5C68::tick(bool sysTick) {
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
if (chan[i].std.vol.had) {
|
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);
|
chWrite(i,0,chan[i].outVol);
|
||||||
}
|
}
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
|
@ -109,6 +109,12 @@ void DivPlatformRF5C68::tick(bool sysTick) {
|
||||||
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
if (chan[i].std.panL.had || chan[i].std.panR.had) {
|
||||||
chWrite(i,1,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) {
|
if (chan[i].setPos) {
|
||||||
// force keyon
|
// force keyon
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
@ -162,6 +168,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
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);
|
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||||
|
@ -380,7 +387,7 @@ void DivPlatformRF5C68::renderSamples() {
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
int length=s->getEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
|
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
|
||||||
if (actualLength>0) {
|
if (actualLength>0) {
|
||||||
s->offRF5C68=memPos;
|
s->offRF5C68=memPos;
|
||||||
|
|
|
@ -34,6 +34,7 @@ class DivPlatformRF5C68: public DivDispatch {
|
||||||
int panning;
|
int panning;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
|
int macroVolMul;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
|
@ -57,7 +58,8 @@ class DivPlatformRF5C68: public DivDispatch {
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
setPos(false),
|
setPos(false),
|
||||||
vol(255),
|
vol(255),
|
||||||
outVol(255) {}
|
outVol(255),
|
||||||
|
macroVolMul(64) {}
|
||||||
};
|
};
|
||||||
Channel chan[8];
|
Channel chan[8];
|
||||||
DivDispatchOscBuffer* oscBuf[8];
|
DivDispatchOscBuffer* oscBuf[8];
|
||||||
|
@ -69,6 +71,7 @@ class DivPlatformRF5C68: public DivDispatch {
|
||||||
size_t sampleMemLen;
|
size_t sampleMemLen;
|
||||||
rf5c68_device rf5c68;
|
rf5c68_device rf5c68;
|
||||||
unsigned char regPool[144];
|
unsigned char regPool[144];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -72,6 +72,7 @@ class DivPlatformSAA1099: public DivDispatch {
|
||||||
size_t saaBufLen;
|
size_t saaBufLen;
|
||||||
unsigned char saaEnv[2];
|
unsigned char saaEnv[2];
|
||||||
unsigned char saaNoise[2];
|
unsigned char saaNoise[2];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void acquire_saaSound(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_saaSound(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -65,6 +65,7 @@ class DivPlatformSCC: public DivDispatch {
|
||||||
unsigned char regBase;
|
unsigned char regBase;
|
||||||
unsigned char regPool[225];
|
unsigned char regPool[225];
|
||||||
void updateWave(int ch);
|
void updateWave(int ch);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -47,7 +47,7 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t
|
||||||
pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR);
|
pcmR+=(s->data8[chan[i].pcm.pos>>8]*chan[i].chVolR);
|
||||||
}
|
}
|
||||||
chan[i].pcm.pos+=chan[i].pcm.freq;
|
chan[i].pcm.pos+=chan[i].pcm.freq;
|
||||||
if (s->isLoopable() && chan[i].pcm.pos>=(s->getEndPosition()<<8)) {
|
if (s->isLoopable() && chan[i].pcm.pos>=((unsigned int)s->loopEnd<<8)) {
|
||||||
chan[i].pcm.pos=s->loopStart<<8;
|
chan[i].pcm.pos=s->loopStart<<8;
|
||||||
} else if (chan[i].pcm.pos>=(s->samples<<8)) {
|
} else if (chan[i].pcm.pos>=(s->samples<<8)) {
|
||||||
chan[i].pcm.sample=-1;
|
chan[i].pcm.sample=-1;
|
||||||
|
@ -76,7 +76,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
||||||
|
|
||||||
if (parent->song.newSegaPCM) {
|
if (parent->song.newSegaPCM) {
|
||||||
if (chan[i].std.vol.had) {
|
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].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
|
||||||
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
|
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
|
||||||
if (dumpWrites) {
|
if (dumpWrites) {
|
||||||
|
@ -93,8 +93,8 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[i].std.panL.had) {
|
if (parent->song.newSegaPCM) 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].chPanL=chan[i].std.panL.val&127;
|
||||||
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
|
chan[i].chVolL=(chan[i].outVol*chan[i].chPanL)/127;
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,8 +105,8 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[i].std.panR.had) {
|
if (parent->song.newSegaPCM) 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].chPanR=chan[i].std.panR.val&127;
|
||||||
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
|
chan[i].chVolR=(chan[i].outVol*chan[i].chPanR)/127;
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,13 +126,14 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=true;
|
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].std.phaseReset.had) {
|
||||||
if (chan[i].freqChanged) {
|
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;
|
chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64;
|
||||||
if (chan[i].furnacePCM) {
|
if (chan[i].furnacePCM) {
|
||||||
double off=1.0;
|
double off=1.0;
|
||||||
|
@ -146,6 +147,56 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=false;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +210,9 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||||
if (skipRegisterWrites) break;
|
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);
|
||||||
chan[c.chan].pcm.sample=ins->amiga.getSample(c.value);
|
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) {
|
if (chan[c.chan].pcm.sample<0 || chan[c.chan].pcm.sample>=parent->song.sampleLen) {
|
||||||
chan[c.chan].pcm.sample=-1;
|
chan[c.chan].pcm.sample=-1;
|
||||||
|
@ -172,7 +225,6 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
chan[c.chan].pcm.pos=0;
|
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].baseFreq=(c.value<<6);
|
chan[c.chan].baseFreq=(c.value<<6);
|
||||||
|
@ -180,23 +232,8 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
chan[c.chan].furnacePCM=true;
|
chan[c.chan].furnacePCM=true;
|
||||||
chan[c.chan].macroInit(ins);
|
chan[c.chan].macroInit(ins);
|
||||||
if (dumpWrites) { // Sega PCM writes
|
chan[c.chan].active=true;
|
||||||
DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
|
chan[c.chan].keyOn=true;
|
||||||
int actualLength=(int)(s->getEndPosition(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 (s->loopStart<0 || s->loopStart>=actualLength) {
|
|
||||||
addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3));
|
|
||||||
} else {
|
|
||||||
int loopPos=(s->offSegaPCM&0xffff)+s->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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
|
@ -210,27 +247,10 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
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].pcm.freq=MIN(255,(parent->getSample(chan[c.chan].pcm.sample)->rate*255)/31250);
|
||||||
chan[c.chan].furnacePCM=false;
|
chan[c.chan].furnacePCM=false;
|
||||||
if (dumpWrites) { // Sega PCM writes
|
chan[c.chan].active=true;
|
||||||
DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
|
chan[c.chan].keyOn=true;
|
||||||
int actualLength=(int)(s->getEndPosition(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 (s->loopStart<0 || s->loopStart>=actualLength) {
|
|
||||||
addWrite(0x10086+(c.chan<<3),2+((s->offSegaPCM>>16)<<3));
|
|
||||||
} else {
|
|
||||||
int loopPos=(s->offSegaPCM&0xffff)+s->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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -258,7 +278,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
}
|
}
|
||||||
if (parent->song.newSegaPCM) {
|
if (parent->song.newSegaPCM && chan[c.chan].isNewSegaPCM) {
|
||||||
chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127;
|
chan[c.chan].chVolL=(c.value*chan[c.chan].chPanL)/127;
|
||||||
chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127;
|
chan[c.chan].chVolR=(c.value*chan[c.chan].chPanR)/127;
|
||||||
} else {
|
} else {
|
||||||
|
@ -282,7 +302,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
||||||
chan[c.chan].ins=c.value;
|
chan[c.chan].ins=c.value;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PANNING: {
|
case DIV_CMD_PANNING: {
|
||||||
if (parent->song.newSegaPCM) {
|
if (parent->song.newSegaPCM && chan[c.chan].isNewSegaPCM) {
|
||||||
chan[c.chan].chPanL=c.value>>1;
|
chan[c.chan].chPanL=c.value>>1;
|
||||||
chan[c.chan].chPanR=c.value2>>1;
|
chan[c.chan].chPanR=c.value2>>1;
|
||||||
chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127;
|
chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127;
|
||||||
|
@ -421,8 +441,6 @@ void DivPlatformSegaPCM::reset() {
|
||||||
pcmR=0;
|
pcmR=0;
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
delay=0;
|
delay=0;
|
||||||
amDepth=0x7f;
|
|
||||||
pmDepth=0x7f;
|
|
||||||
|
|
||||||
if (dumpWrites) {
|
if (dumpWrites) {
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<16; i++) {
|
||||||
|
@ -431,8 +449,6 @@ void DivPlatformSegaPCM::reset() {
|
||||||
addWrite(0x10003+(i<<3),0x7f);
|
addWrite(0x10003+(i<<3),0x7f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extMode=false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSegaPCM::setFlags(unsigned int flags) {
|
void DivPlatformSegaPCM::setFlags(unsigned int flags) {
|
||||||
|
|
|
@ -28,13 +28,12 @@ class DivPlatformSegaPCM: public DivDispatch {
|
||||||
protected:
|
protected:
|
||||||
struct Channel {
|
struct Channel {
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
unsigned char freqH, freqL;
|
|
||||||
int freq, baseFreq, pitch, pitch2, note, ins;
|
int freq, baseFreq, pitch, pitch2, note, ins;
|
||||||
signed char konCycles;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, isNewSegaPCM;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
|
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
unsigned char chVolL, chVolR;
|
unsigned char chVolL, chVolR;
|
||||||
unsigned char chPanL, chPanR;
|
unsigned char chPanL, chPanR;
|
||||||
|
int macroVolMul;
|
||||||
|
|
||||||
struct PCMChannel {
|
struct PCMChannel {
|
||||||
int sample;
|
int sample;
|
||||||
|
@ -48,8 +47,6 @@ class DivPlatformSegaPCM: public DivDispatch {
|
||||||
pitch2=0;
|
pitch2=0;
|
||||||
}
|
}
|
||||||
Channel():
|
Channel():
|
||||||
freqH(0),
|
|
||||||
freqL(0),
|
|
||||||
freq(0),
|
freq(0),
|
||||||
baseFreq(0),
|
baseFreq(0),
|
||||||
pitch(0),
|
pitch(0),
|
||||||
|
@ -64,12 +61,15 @@ class DivPlatformSegaPCM: public DivDispatch {
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
portaPause(false),
|
portaPause(false),
|
||||||
furnacePCM(false),
|
furnacePCM(false),
|
||||||
|
isNewSegaPCM(false),
|
||||||
vol(0),
|
vol(0),
|
||||||
outVol(0),
|
outVol(0),
|
||||||
chVolL(127),
|
chVolL(127),
|
||||||
chVolR(127),
|
chVolR(127),
|
||||||
chPanL(127),
|
chPanL(127),
|
||||||
chPanR(127) {}
|
chPanR(127),
|
||||||
|
macroVolMul(64),
|
||||||
|
pcm(PCMChannel()) {}
|
||||||
};
|
};
|
||||||
Channel chan[16];
|
Channel chan[16];
|
||||||
DivDispatchOscBuffer* oscBuf[16];
|
DivDispatchOscBuffer* oscBuf[16];
|
||||||
|
@ -80,21 +80,19 @@ class DivPlatformSegaPCM: public DivDispatch {
|
||||||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
||||||
};
|
};
|
||||||
std::queue<QueuedWrite> writes;
|
std::queue<QueuedWrite> writes;
|
||||||
int delay, baseFreqOff;
|
int delay;
|
||||||
int pcmL, pcmR, pcmCycles;
|
int pcmL, pcmR, pcmCycles;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
unsigned char lastBusy;
|
unsigned char lastBusy;
|
||||||
unsigned char amDepth, pmDepth;
|
|
||||||
|
|
||||||
unsigned char regPool[256];
|
unsigned char regPool[256];
|
||||||
|
|
||||||
bool extMode, useYMFM;
|
|
||||||
|
|
||||||
bool isMuted[16];
|
bool isMuted[16];
|
||||||
|
|
||||||
short oldWrites[256];
|
short oldWrites[256];
|
||||||
short pendingWrites[256];
|
short pendingWrites[256];
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -78,6 +78,7 @@ class DivPlatformSMS: public DivDispatch {
|
||||||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
||||||
};
|
};
|
||||||
std::queue<QueuedWrite> writes;
|
std::queue<QueuedWrite> writes;
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -163,7 +163,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
||||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
|
||||||
DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note));
|
DivSample* sample=parent->getSample(ins->amiga.getSample(chan[i].note));
|
||||||
if (sample!=NULL) {
|
if (sample!=NULL) {
|
||||||
unsigned int sampleEnd=sample->offSU+(sample->getEndPosition());
|
unsigned int sampleEnd=sample->offSU+(sample->getLoopEndPosition());
|
||||||
unsigned int off=sample->offSU+chan[i].hasOffset;
|
unsigned int off=sample->offSU+chan[i].hasOffset;
|
||||||
chan[i].hasOffset=0;
|
chan[i].hasOffset=0;
|
||||||
if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1;
|
if (sampleEnd>=getSampleMemCapacity(0)) sampleEnd=getSampleMemCapacity(0)-1;
|
||||||
|
@ -172,7 +172,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
|
||||||
chWrite(i,0x0c,sampleEnd&0xff);
|
chWrite(i,0x0c,sampleEnd&0xff);
|
||||||
chWrite(i,0x0d,sampleEnd>>8);
|
chWrite(i,0x0d,sampleEnd>>8);
|
||||||
if (sample->isLoopable()) {
|
if (sample->isLoopable()) {
|
||||||
unsigned int sampleLoop=sample->offSU+sample->loopStart;
|
unsigned int sampleLoop=sample->offSU+sample->getLoopStartPosition();
|
||||||
if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1;
|
if (sampleLoop>=getSampleMemCapacity(0)) sampleLoop=getSampleMemCapacity(0)-1;
|
||||||
chWrite(i,0x0e,sampleLoop&0xff);
|
chWrite(i,0x0e,sampleLoop&0xff);
|
||||||
chWrite(i,0x0f,sampleLoop>>8);
|
chWrite(i,0x0f,sampleLoop>>8);
|
||||||
|
@ -200,12 +200,12 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SU);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SU);
|
||||||
chan[c.chan].switchRoles=ins->su.switchRoles;
|
chan[c.chan].switchRoles=ins->su.switchRoles;
|
||||||
if (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->su.useSample);
|
chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample);
|
||||||
writeControl(c.chan);
|
writeControl(c.chan);
|
||||||
writeControlUpper(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) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_SU(c.chan,c.value);
|
chan[c.chan].baseFreq=NOTE_SU(c.chan,c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
|
@ -552,7 +552,7 @@ void DivPlatformSoundUnit::renderSamples() {
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
if (s->data8==NULL) continue;
|
if (s->data8==NULL) continue;
|
||||||
int paddedLen=s->samples;
|
int paddedLen=s->length8;
|
||||||
if (memPos>=getSampleMemCapacity(0)) {
|
if (memPos>=getSampleMemCapacity(0)) {
|
||||||
logW("out of PCM memory for sample %d!",i);
|
logW("out of PCM memory for sample %d!",i);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -113,6 +113,7 @@ class DivPlatformSoundUnit: public DivDispatch {
|
||||||
void writeControl(int ch);
|
void writeControl(int ch);
|
||||||
void writeControlUpper(int ch);
|
void writeControlUpper(int ch);
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -63,7 +63,7 @@ void DivPlatformSwan::acquire(short* bufL, short* bufR, size_t start, size_t len
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80);
|
rWrite(0x09,(unsigned char)s->data8[dacPos++]+0x80);
|
||||||
if (s->isLoopable() && dacPos>=s->getEndPosition()) {
|
if (s->isLoopable() && dacPos>=(unsigned int)s->loopEnd) {
|
||||||
dacPos=s->loopStart;
|
dacPos=s->loopStart;
|
||||||
} else if (dacPos>=s->samples) {
|
} else if (dacPos>=s->samples) {
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
@ -222,7 +222,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SWAN);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SWAN);
|
||||||
if (c.chan==1) {
|
if (c.chan==1) {
|
||||||
if (ins->type==DIV_INS_AMIGA) {
|
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||||
pcm=true;
|
pcm=true;
|
||||||
} else if (furnaceDac) {
|
} else if (furnaceDac) {
|
||||||
pcm=false;
|
pcm=false;
|
||||||
|
@ -231,7 +231,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
||||||
if (skipRegisterWrites) break;
|
if (skipRegisterWrites) break;
|
||||||
dacPos=0;
|
dacPos=0;
|
||||||
dacPeriod=0;
|
dacPeriod=0;
|
||||||
if (ins->type==DIV_INS_AMIGA) {
|
if (ins->type==DIV_INS_AMIGA || ins->amiga.useSample) {
|
||||||
dacSample=ins->amiga.getSample(c.value);
|
dacSample=ins->amiga.getSample(c.value);
|
||||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
|
|
@ -74,6 +74,7 @@ class DivPlatformSwan: public DivDispatch {
|
||||||
std::queue<QueuedWrite> writes;
|
std::queue<QueuedWrite> writes;
|
||||||
WSwan* ws;
|
WSwan* ws;
|
||||||
void updateWave(int ch);
|
void updateWave(int ch);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -46,6 +46,7 @@ class DivPlatformTIA: public DivDispatch {
|
||||||
unsigned char chanOscCounter;
|
unsigned char chanOscCounter;
|
||||||
TIA::Audio tia;
|
TIA::Audio tia;
|
||||||
unsigned char regPool[16];
|
unsigned char regPool[16];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
unsigned char dealWithFreq(unsigned char shape, int base, int pitch);
|
unsigned char dealWithFreq(unsigned char shape, int base, int pitch);
|
||||||
|
|
|
@ -88,6 +88,7 @@ class DivPlatformTX81Z: public DivPlatformOPM {
|
||||||
int octave(int freq);
|
int octave(int freq);
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -84,7 +84,7 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len
|
||||||
rWritePCMData(tmp_r&0xff);
|
rWritePCMData(tmp_r&0xff);
|
||||||
}
|
}
|
||||||
chan[16].pcm.pos++;
|
chan[16].pcm.pos++;
|
||||||
if (s->isLoopable() && chan[16].pcm.pos>=s->getEndPosition()) {
|
if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->loopEnd) {
|
||||||
chan[16].pcm.pos=s->loopStart;
|
chan[16].pcm.pos=s->loopStart;
|
||||||
} else if (chan[16].pcm.pos>=s->samples) {
|
} else if (chan[16].pcm.pos>=s->samples) {
|
||||||
chan[16].pcm.sample=-1;
|
chan[16].pcm.sample=-1;
|
||||||
|
|
|
@ -60,6 +60,7 @@ class DivPlatformVERA: public DivDispatch {
|
||||||
struct VERA_PCM* pcm;
|
struct VERA_PCM* pcm;
|
||||||
|
|
||||||
int calcNoteFreq(int ch, int note);
|
int calcNoteFreq(int ch, int note);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -63,6 +63,7 @@ class DivPlatformVIC20: public DivDispatch {
|
||||||
unsigned char regPool[16];
|
unsigned char regPool[16];
|
||||||
sound_vic20_t* vic;
|
sound_vic20_t* vic;
|
||||||
void updateWave(int ch);
|
void updateWave(int ch);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -65,7 +65,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len
|
||||||
chWrite(i,0,0x80|chan[i].dacOut);
|
chWrite(i,0,0x80|chan[i].dacOut);
|
||||||
}
|
}
|
||||||
chan[i].dacPos++;
|
chan[i].dacPos++;
|
||||||
if (s->isLoopable() && chan[i].dacPos>=s->getEndPosition()) {
|
if (s->isLoopable() && chan[i].dacPos>=(unsigned int)s->loopEnd) {
|
||||||
chan[i].dacPos=s->loopStart;
|
chan[i].dacPos=s->loopStart;
|
||||||
} else if (chan[i].dacPos>=s->samples) {
|
} else if (chan[i].dacPos>=s->samples) {
|
||||||
chan[i].dacSample=-1;
|
chan[i].dacSample=-1;
|
||||||
|
@ -173,6 +173,25 @@ void DivPlatformVRC6::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=true;
|
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 (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
if (i==2) { // sawtooth
|
if (i==2) { // sawtooth
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,14)-1;
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,14)-1;
|
||||||
|
@ -213,14 +232,14 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_ON:
|
case DIV_CMD_NOTE_ON:
|
||||||
if (c.chan!=2) { // pulse wave
|
if (c.chan!=2) { // pulse wave
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VRC6);
|
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;
|
chan[c.chan].pcm=true;
|
||||||
} else if (chan[c.chan].furnaceDac) {
|
} else if (chan[c.chan].furnaceDac) {
|
||||||
chan[c.chan].pcm=false;
|
chan[c.chan].pcm=false;
|
||||||
}
|
}
|
||||||
if (chan[c.chan].pcm) {
|
if (chan[c.chan].pcm) {
|
||||||
if (skipRegisterWrites) break;
|
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);
|
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||||
chan[c.chan].dacSample=-1;
|
chan[c.chan].dacSample=-1;
|
||||||
|
|
|
@ -78,6 +78,7 @@ class DivPlatformVRC6: public DivDispatch, public vrcvi_intf {
|
||||||
vrcvi_core vrc6;
|
vrcvi_core vrc6;
|
||||||
unsigned char regPool[13];
|
unsigned char regPool[13];
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -229,6 +229,11 @@ void DivPlatformX1_010::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
|
|
||||||
u8 DivPlatformX1_010::read_byte(u32 address) {
|
u8 DivPlatformX1_010::read_byte(u32 address) {
|
||||||
if ((sampleMem!=NULL) && (address<getSampleMemCapacity())) {
|
if ((sampleMem!=NULL) && (address<getSampleMemCapacity())) {
|
||||||
|
if (isBanked) {
|
||||||
|
address=((bankSlot[(address>>17)&7]<<17)|(address&0x1ffff))&0xffffff;
|
||||||
|
} else {
|
||||||
|
address&=0xfffff;
|
||||||
|
}
|
||||||
return sampleMem[address];
|
return sampleMem[address];
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -319,7 +324,7 @@ void DivPlatformX1_010::tick(bool sysTick) {
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<16; i++) {
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
if (chan[i].std.vol.had) {
|
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)) {
|
if ((!isMuted[i]) && (macroVol!=chan[i].outVol)) {
|
||||||
chan[i].outVol=macroVol;
|
chan[i].outVol=macroVol;
|
||||||
chan[i].envChanged=true;
|
chan[i].envChanged=true;
|
||||||
|
@ -440,6 +445,12 @@ void DivPlatformX1_010::tick(bool sysTick) {
|
||||||
if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1;
|
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].active) {
|
||||||
if (chan[i].ws.tick()) {
|
if (chan[i].ws.tick()) {
|
||||||
updateWave(i);
|
updateWave(i);
|
||||||
|
@ -514,8 +525,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
chWrite(c.chan,0,0); // reset previous note
|
chWrite(c.chan,0,0); // reset previous note
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_X1_010);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_X1_010);
|
||||||
if ((ins->type==DIV_INS_AMIGA) || chan[c.chan].pcm) {
|
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:15;
|
||||||
if (ins->type==DIV_INS_AMIGA) {
|
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;
|
chan[c.chan].furnacePCM=true;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].furnacePCM=false;
|
chan[c.chan].furnacePCM=false;
|
||||||
|
@ -527,9 +539,18 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
||||||
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||||
chWrite(c.chan,4,(s->offX1_010>>12)&0xff);
|
if (isBanked) {
|
||||||
int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded
|
chan[c.chan].bankSlot=ins->x1_010.bankSlot;
|
||||||
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
|
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) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note);
|
chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note);
|
||||||
|
@ -559,9 +580,17 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||||
chWrite(c.chan,4,(s->offX1_010>>12)&0xff);
|
if (isBanked) {
|
||||||
int end=(s->offX1_010+s->length8+0xfff)&~0xfff; // padded
|
bankSlot[chan[c.chan].bankSlot]=s->offX1_010>>17;
|
||||||
chWrite(c.chan,5,(0x100-(end>>12))&0xff);
|
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].baseFreq=(((unsigned int)s->rate)<<4)/(chipClock/512);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -778,6 +807,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
||||||
chan[c.chan].autoEnvDen=c.value&15;
|
chan[c.chan].autoEnvDen=c.value&15;
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
|
case DIV_CMD_X1_010_SAMPLE_BANK_SLOT:
|
||||||
|
chan[c.chan].bankSlot=c.value&7;
|
||||||
|
break;
|
||||||
case DIV_CMD_GET_VOLMAX:
|
case DIV_CMD_GET_VOLMAX:
|
||||||
return 15;
|
return 15;
|
||||||
break;
|
break;
|
||||||
|
@ -842,6 +874,10 @@ void DivPlatformX1_010::reset() {
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<16; i++) {
|
||||||
chWrite(i,0,0);
|
chWrite(i,0,0);
|
||||||
}
|
}
|
||||||
|
// set initial bank
|
||||||
|
for (int b=0; b<8; b++) {
|
||||||
|
bankSlot[b]=b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformX1_010::isStereo() {
|
bool DivPlatformX1_010::isStereo() {
|
||||||
|
@ -896,15 +932,15 @@ void DivPlatformX1_010::poke(std::vector<DivRegWrite>& wlist) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* DivPlatformX1_010::getSampleMem(int index) {
|
const void* DivPlatformX1_010::getSampleMem(int index) {
|
||||||
return index == 0 ? sampleMem : 0;
|
return index >= 0 ? sampleMem : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DivPlatformX1_010::getSampleMemCapacity(int index) {
|
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) {
|
size_t DivPlatformX1_010::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? sampleMemLen : 0;
|
return index >= 0 ? sampleMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformX1_010::renderSamples() {
|
void DivPlatformX1_010::renderSamples() {
|
||||||
|
@ -914,12 +950,14 @@ void DivPlatformX1_010::renderSamples() {
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
int paddedLen=(s->length8+4095)&(~0xfff);
|
int paddedLen=(s->length8+4095)&(~0xfff);
|
||||||
|
if (isBanked) {
|
||||||
// fit sample bank size to 128KB for Seta 2 external bankswitching logic (not emulated yet!)
|
// fit sample bank size to 128KB for Seta 2 external bankswitching logic (not emulated yet!)
|
||||||
if (paddedLen>131072) {
|
if (paddedLen>131072) {
|
||||||
paddedLen=131072;
|
paddedLen=131072;
|
||||||
}
|
}
|
||||||
if ((memPos&0xfe0000)!=((memPos+paddedLen)&0xfe0000)) {
|
if ((memPos&0xfe0000)!=((memPos+paddedLen)&0xfe0000)) {
|
||||||
memPos=(memPos+0x1ffff)&0xfe0000;
|
memPos=(memPos+0x1ffff)&0xfe0000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (memPos>=getSampleMemCapacity()) {
|
if (memPos>=getSampleMemCapacity()) {
|
||||||
logW("out of X1-010 memory for sample %d!",i);
|
logW("out of X1-010 memory for sample %d!",i);
|
||||||
|
@ -937,6 +975,10 @@ void DivPlatformX1_010::renderSamples() {
|
||||||
sampleMemLen=memPos+256;
|
sampleMemLen=memPos+256;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformX1_010::setBanked(bool banked) {
|
||||||
|
isBanked=banked;
|
||||||
|
}
|
||||||
|
|
||||||
int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
int DivPlatformX1_010::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||||
parent=p;
|
parent=p;
|
||||||
dumpWrites=false;
|
dumpWrites=false;
|
||||||
|
|
|
@ -73,7 +73,9 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
unsigned char pan, autoEnvNum, autoEnvDen;
|
unsigned char pan, autoEnvNum, autoEnvDen;
|
||||||
bool active, insChanged, envChanged, freqChanged, keyOn, keyOff, inPorta, furnacePCM, pcm;
|
bool active, insChanged, envChanged, freqChanged, keyOn, keyOff, inPorta, furnacePCM, pcm;
|
||||||
int vol, outVol, lvol, rvol;
|
int vol, outVol, lvol, rvol;
|
||||||
|
int macroVolMul;
|
||||||
unsigned char waveBank;
|
unsigned char waveBank;
|
||||||
|
unsigned int bankSlot;
|
||||||
Envelope env;
|
Envelope env;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
DivWaveSynth ws;
|
DivWaveSynth ws;
|
||||||
|
@ -98,7 +100,9 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
pan(255), autoEnvNum(0), autoEnvDen(0),
|
pan(255), autoEnvNum(0), autoEnvDen(0),
|
||||||
active(false), insChanged(true), envChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), furnacePCM(false), pcm(false),
|
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),
|
vol(15), outVol(15), lvol(15), rvol(15),
|
||||||
waveBank(0) {}
|
macroVolMul(15),
|
||||||
|
waveBank(0),
|
||||||
|
bankSlot(0) {}
|
||||||
};
|
};
|
||||||
Channel chan[16];
|
Channel chan[16];
|
||||||
DivDispatchOscBuffer* oscBuf[16];
|
DivDispatchOscBuffer* oscBuf[16];
|
||||||
|
@ -108,10 +112,15 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
size_t sampleMemLen;
|
size_t sampleMemLen;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
x1_010_core x1_010;
|
x1_010_core x1_010;
|
||||||
|
|
||||||
|
bool isBanked=false;
|
||||||
|
unsigned int bankSlot[8];
|
||||||
|
|
||||||
unsigned char regPool[0x2000];
|
unsigned char regPool[0x2000];
|
||||||
double NoteX1_010(int ch, int note);
|
double NoteX1_010(int ch, int note);
|
||||||
void updateWave(int ch);
|
void updateWave(int ch);
|
||||||
void updateEnvelope(int ch);
|
void updateEnvelope(int ch);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
u8 read_byte(u32 address);
|
u8 read_byte(u32 address);
|
||||||
|
@ -138,6 +147,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
size_t getSampleMemUsage(int index = 0);
|
size_t getSampleMemUsage(int index = 0);
|
||||||
void renderSamples();
|
void renderSamples();
|
||||||
const char** getRegisterSheet();
|
const char** getRegisterSheet();
|
||||||
|
void setBanked(bool banked);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||||
void quit();
|
void quit();
|
||||||
DivPlatformX1_010():
|
DivPlatformX1_010():
|
||||||
|
|
|
@ -94,6 +94,7 @@ class DivPlatformYM2203: public DivPlatformOPN {
|
||||||
bool extMode;
|
bool extMode;
|
||||||
unsigned char prescale;
|
unsigned char prescale;
|
||||||
|
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -63,7 +63,6 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
if (opChan[ch].insChanged) { // TODO how does this work?
|
if (opChan[ch].insChanged) { // TODO how does this work?
|
||||||
rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
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));
|
|
||||||
}
|
}
|
||||||
opChan[ch].insChanged=false;
|
opChan[ch].insChanged=false;
|
||||||
|
|
||||||
|
@ -103,22 +102,6 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
opChan[ch].ins=c.value;
|
opChan[ch].ins=c.value;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PANNING: {
|
|
||||||
if (c.value==0 && c.value2==0) {
|
|
||||||
opChan[ch].pan=3;
|
|
||||||
} else {
|
|
||||||
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
|
|
||||||
}
|
|
||||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
|
||||||
if (parent->song.sharedExtStat) {
|
|
||||||
for (int i=0; i<4; i++) {
|
|
||||||
if (ch==i) continue;
|
|
||||||
opChan[i].pan=opChan[ch].pan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DIV_CMD_PITCH: {
|
case DIV_CMD_PITCH: {
|
||||||
opChan[ch].pitch=c.value;
|
opChan[ch].pitch=c.value;
|
||||||
opChan[ch].freqChanged=true;
|
opChan[ch].freqChanged=true;
|
||||||
|
|
|
@ -29,13 +29,29 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 {
|
||||||
signed char konCycles;
|
signed char konCycles;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask;
|
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask;
|
||||||
int vol;
|
int vol;
|
||||||
unsigned char pan;
|
|
||||||
// UGLY
|
// 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),
|
OpChannel():
|
||||||
inPorta(false), mask(true), vol(0), pan(3) {}
|
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),
|
||||||
|
mask(true),
|
||||||
|
vol(0) {}
|
||||||
};
|
};
|
||||||
OpChannel opChan[4];
|
OpChannel opChan[4];
|
||||||
bool isOpMuted[4];
|
bool isOpMuted[4];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
|
|
|
@ -358,14 +358,6 @@ void DivPlatformYM2608::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2608::tick(bool sysTick) {
|
void DivPlatformYM2608::tick(bool sysTick) {
|
||||||
// PSG
|
|
||||||
ay->tick(sysTick);
|
|
||||||
ay->flushWrites();
|
|
||||||
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
|
||||||
immWrite(i.addr&15,i.val);
|
|
||||||
}
|
|
||||||
ay->getRegisterWrites().clear();
|
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<6; i++) {
|
||||||
if (i==2 && extMode) continue;
|
if (i==2 && extMode) continue;
|
||||||
|
@ -522,38 +514,6 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
||||||
chan[i].keyOff=false;
|
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(0x10b,chan[15].outVol);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chan[15].std.arp.had) {
|
|
||||||
if (!chan[15].inPorta) {
|
|
||||||
chan[15].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[15].note,chan[15].std.arp.val));
|
|
||||||
}
|
|
||||||
chan[15].freqChanged=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;
|
|
||||||
}
|
|
||||||
immWrite(0x109,chan[15].freq&0xff);
|
|
||||||
immWrite(0x10a,(chan[15].freq>>8)&0xff);
|
|
||||||
chan[15].freqChanged=false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writeRSSOff) {
|
|
||||||
immWrite(0x10,0x80|writeRSSOff);
|
|
||||||
writeRSSOff=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=16; i<512; i++) {
|
for (int i=16; i<512; i++) {
|
||||||
if (pendingWrites[i]!=oldWrites[i]) {
|
if (pendingWrites[i]!=oldWrites[i]) {
|
||||||
|
@ -592,10 +552,111 @@ void DivPlatformYM2608::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(chan[15].macroVolMul,chan[15].std.vol.val))/chan[15].macroVolMul;
|
||||||
|
immWrite(0x10b,chan[15].outVol);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan[15].std.arp.had) {
|
||||||
|
if (!chan[15].inPorta) {
|
||||||
|
chan[15].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[15].note,chan[15].std.arp.val));
|
||||||
|
}
|
||||||
|
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 || 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeRSSOff) {
|
||||||
|
immWrite(0x10,0x80|writeRSSOff);
|
||||||
|
writeRSSOff=0;
|
||||||
|
}
|
||||||
|
|
||||||
if (writeRSSOn) {
|
if (writeRSSOn) {
|
||||||
immWrite(0x10,writeRSSOn);
|
immWrite(0x10,writeRSSOn);
|
||||||
writeRSSOn=0;
|
writeRSSOn=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PSG
|
||||||
|
ay->tick(sysTick);
|
||||||
|
ay->flushWrites();
|
||||||
|
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
||||||
|
immWrite(i.addr&15,i.val);
|
||||||
|
}
|
||||||
|
ay->getRegisterWrites().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformYM2608::dispatch(DivCommand c) {
|
int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
|
@ -607,7 +668,8 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
if (c.chan>14) { // ADPCM-B
|
if (c.chan>14) { // ADPCM-B
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
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;
|
chan[c.chan].furnacePCM=true;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].furnacePCM=false;
|
chan[c.chan].furnacePCM=false;
|
||||||
|
@ -628,7 +690,6 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
immWrite(0x104,(end>>5)&0xff);
|
immWrite(0x104,(end>>5)&0xff);
|
||||||
immWrite(0x105,(end>>13)&0xff);
|
immWrite(0x105,(end>>13)&0xff);
|
||||||
immWrite(0x101,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|2);
|
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) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||||
|
@ -649,6 +710,24 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
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(0x100,0x01); // reset
|
||||||
immWrite(0x102,0);
|
immWrite(0x102,0);
|
||||||
immWrite(0x103,0);
|
immWrite(0x103,0);
|
||||||
|
@ -656,26 +735,31 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
immWrite(0x105,0);
|
immWrite(0x105,0);
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>8) { // RSS
|
if (c.chan>8) { // RSS
|
||||||
if (skipRegisterWrites) break;
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
if (!isMuted[c.chan]) {
|
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31;
|
||||||
writeRSSOn|=(1<<(c.chan-9));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
|
@ -733,28 +817,12 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_OFF:
|
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].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
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].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
|
@ -773,7 +841,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>8) { // ADPCM-A
|
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;
|
break;
|
||||||
}
|
}
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
|
@ -787,6 +855,13 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DIV_CMD_ADPCMA_GLOBAL_VOLUME: {
|
||||||
|
if (globalRSSVolume!=(c.value&0x3f)) {
|
||||||
|
globalRSSVolume=c.value&0x3f;
|
||||||
|
immWrite(0x11,globalRSSVolume&0x3f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DIV_CMD_GET_VOLUME: {
|
case DIV_CMD_GET_VOLUME: {
|
||||||
return chan[c.chan].vol;
|
return chan[c.chan].vol;
|
||||||
break;
|
break;
|
||||||
|
@ -808,7 +883,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>8) {
|
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;
|
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));
|
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));
|
||||||
|
@ -1077,7 +1152,7 @@ void DivPlatformYM2608::muteChannel(int ch, bool mute) {
|
||||||
immWrite(0x101,(isMuted[ch]?0:(chan[ch].pan<<6))|2);
|
immWrite(0x101,(isMuted[ch]?0:(chan[ch].pan<<6))|2);
|
||||||
}
|
}
|
||||||
if (ch>8) { // ADPCM-A
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (ch>5) { // PSG
|
if (ch>5) { // PSG
|
||||||
|
@ -1117,7 +1192,7 @@ void DivPlatformYM2608::forceIns() {
|
||||||
if (i>14) { // ADPCM-B
|
if (i>14) { // ADPCM-B
|
||||||
immWrite(0x10b,chan[i].outVol);
|
immWrite(0x10b,chan[i].outVol);
|
||||||
} else {
|
} else {
|
||||||
immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol));
|
immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,6 +1265,7 @@ void DivPlatformYM2608::reset() {
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
writeRSSOff=0;
|
writeRSSOff=0;
|
||||||
writeRSSOn=0;
|
writeRSSOn=0;
|
||||||
|
globalRSSVolume=0x3f;
|
||||||
|
|
||||||
delay=0;
|
delay=0;
|
||||||
|
|
||||||
|
@ -1199,7 +1275,7 @@ void DivPlatformYM2608::reset() {
|
||||||
immWrite(0x22,0x08);
|
immWrite(0x22,0x08);
|
||||||
|
|
||||||
// PCM volume
|
// PCM volume
|
||||||
immWrite(0x11,0x3f); // A
|
immWrite(0x11,globalRSSVolume); // A
|
||||||
immWrite(0x10b,0xff); // B
|
immWrite(0x10b,0xff); // B
|
||||||
|
|
||||||
// ADPCM limit
|
// ADPCM limit
|
||||||
|
|
|
@ -54,6 +54,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
int sample;
|
int sample;
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
|
int macroVolMul;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
|
@ -86,7 +87,8 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
||||||
vol(0),
|
vol(0),
|
||||||
outVol(15),
|
outVol(15),
|
||||||
sample(-1),
|
sample(-1),
|
||||||
pan(3) {}
|
pan(3),
|
||||||
|
macroVolMul(255) {}
|
||||||
};
|
};
|
||||||
Channel chan[16];
|
Channel chan[16];
|
||||||
DivDispatchOscBuffer* oscBuf[16];
|
DivDispatchOscBuffer* oscBuf[16];
|
||||||
|
@ -101,12 +103,14 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
||||||
DivPlatformAY8910* ay;
|
DivPlatformAY8910* ay;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
unsigned char writeRSSOff, writeRSSOn;
|
unsigned char writeRSSOff, writeRSSOn;
|
||||||
|
int globalRSSVolume;
|
||||||
|
|
||||||
bool extMode;
|
bool extMode;
|
||||||
unsigned char prescale;
|
unsigned char prescale;
|
||||||
|
|
||||||
double NOTE_OPNB(int ch, int note);
|
double NOTE_OPNB(int ch, int note);
|
||||||
double NOTE_ADPCMB(int note);
|
double NOTE_ADPCMB(int note);
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -477,7 +477,7 @@ void DivPlatformYM2608Ext::forceIns() {
|
||||||
if (i>14) { // ADPCM-B
|
if (i>14) { // ADPCM-B
|
||||||
immWrite(0x10b,chan[i].outVol);
|
immWrite(0x10b,chan[i].outVol);
|
||||||
} else {
|
} else {
|
||||||
immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol));
|
immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].outVol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ay->forceIns();
|
ay->forceIns();
|
||||||
|
|
|
@ -31,11 +31,29 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 {
|
||||||
int vol;
|
int vol;
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
// UGLY
|
// 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),
|
OpChannel():
|
||||||
inPorta(false), mask(true), vol(0), pan(3) {}
|
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),
|
||||||
|
mask(true),
|
||||||
|
vol(0),
|
||||||
|
pan(3) {}
|
||||||
};
|
};
|
||||||
OpChannel opChan[4];
|
OpChannel opChan[4];
|
||||||
bool isOpMuted[4];
|
bool isOpMuted[4];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
|
|
|
@ -18,15 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ym2610.h"
|
#include "ym2610.h"
|
||||||
#include "sound/ymfm/ymfm.h"
|
|
||||||
#include "../engine.h"
|
|
||||||
#include "../../ta-log.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define CHIP_FREQBASE fmFreqBase
|
|
||||||
#define CHIP_DIVIDER fmDivBase
|
|
||||||
|
|
||||||
const char* regCheatSheetYM2610[]={
|
const char* regCheatSheetYM2610[]={
|
||||||
// SSG
|
// SSG
|
||||||
"SSG_FreqL_A", "000",
|
"SSG_FreqL_A", "000",
|
||||||
|
@ -235,107 +228,10 @@ const char* regCheatSheetYM2610[]={
|
||||||
NULL
|
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() {
|
const char** DivPlatformYM2610::getRegisterSheet() {
|
||||||
return regCheatSheetYM2610;
|
return regCheatSheetYM2610;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
static int os[2];
|
static int os[2];
|
||||||
|
|
||||||
|
@ -346,7 +242,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
|
|
||||||
ymfm::ssg_engine::output_data ssgOut;
|
ymfm::ssg_engine::output_data ssgOut;
|
||||||
|
|
||||||
ymfm::fm_channel<ymfm::opn_registers_base<true>>* fmChan[6];
|
ymfm::fm_channel<ymfm::opn_registers_base<true>>* fmChan[4];
|
||||||
ymfm::adpcm_a_channel* adpcmAChan[6];
|
ymfm::adpcm_a_channel* adpcmAChan[6];
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
fmChan[i]=fme->debug_channel(bchOffs[i]);
|
fmChan[i]=fme->debug_channel(bchOffs[i]);
|
||||||
|
@ -381,34 +277,26 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l
|
||||||
bufL[h]=os[0];
|
bufL[h]=os[0];
|
||||||
bufR[h]=os[1];
|
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));
|
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
ssge->get_last_out(ssgOut);
|
ssge->get_last_out(ssgOut);
|
||||||
for (int i=4; i<7; i++) {
|
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-4];
|
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=7; i<13; i++) {
|
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-7]->get_last_out(0)+adpcmAChan[i-7]->get_last_out(1);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610::tick(bool sysTick) {
|
void DivPlatformYM2610::tick(bool sysTick) {
|
||||||
// PSG
|
|
||||||
ay->tick(sysTick);
|
|
||||||
ay->flushWrites();
|
|
||||||
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
|
||||||
immWrite(i.addr&15,i.val);
|
|
||||||
}
|
|
||||||
ay->getRegisterWrites().clear();
|
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
if (i==1 && extMode) continue;
|
if (i==1 && extMode) continue;
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
|
|
||||||
|
@ -564,34 +452,6 @@ 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) {
|
|
||||||
chan[13].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[13].note,chan[13].std.arp.val));
|
|
||||||
}
|
|
||||||
chan[13].freqChanged=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
immWrite(0x19,chan[13].freq&0xff);
|
|
||||||
immWrite(0x1a,(chan[13].freq>>8)&0xff);
|
|
||||||
chan[13].freqChanged=false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=16; i<512; i++) {
|
for (int i=16; i<512; i++) {
|
||||||
if (pendingWrites[i]!=oldWrites[i]) {
|
if (pendingWrites[i]!=oldWrites[i]) {
|
||||||
immWrite(i,pendingWrites[i]&0xff);
|
immWrite(i,pendingWrites[i]&0xff);
|
||||||
|
@ -599,7 +459,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 (i==1 && extMode) continue;
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
if (parent->song.linearPitch==2) {
|
if (parent->song.linearPitch==2) {
|
||||||
|
@ -628,18 +488,127 @@ void DivPlatformYM2610::tick(bool sysTick) {
|
||||||
chan[i].keyOn=false;
|
chan[i].keyOn=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan[adpcmBChanOffs].std.arp.had) {
|
||||||
|
if (!chan[adpcmBChanOffs].inPorta) {
|
||||||
|
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmBChanOffs].note,chan[adpcmBChanOffs].std.arp.val));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeADPCMAOn) {
|
||||||
|
immWrite(0x100,writeADPCMAOn);
|
||||||
|
writeADPCMAOn=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSG
|
||||||
|
ay->tick(sysTick);
|
||||||
|
ay->flushWrites();
|
||||||
|
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
||||||
|
immWrite(i.addr&15,i.val);
|
||||||
|
}
|
||||||
|
ay->getRegisterWrites().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformYM2610::dispatch(DivCommand c) {
|
int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
if (c.chan>3 && c.chan<7) {
|
if (c.chan>=psgChanOffs && c.chan<7) {
|
||||||
c.chan-=4;
|
c.chan-=psgChanOffs;
|
||||||
return ay->dispatch(c);
|
return ay->dispatch(c);
|
||||||
}
|
}
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
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);
|
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;
|
chan[c.chan].furnacePCM=true;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].furnacePCM=false;
|
chan[c.chan].furnacePCM=false;
|
||||||
|
@ -660,7 +629,6 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
immWrite(0x14,(end>>8)&0xff);
|
immWrite(0x14,(end>>8)&0xff);
|
||||||
immWrite(0x15,end>>16);
|
immWrite(0x15,end>>16);
|
||||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
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) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||||
|
@ -681,50 +649,104 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||||
immWrite(0x12,(s->offB>>8)&0xff);
|
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||||
immWrite(0x13,s->offB>>16);
|
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||||
int end=s->offB+s->lengthB-1;
|
immWrite(0x12,(s->offB>>8)&0xff);
|
||||||
immWrite(0x14,(end>>8)&0xff);
|
immWrite(0x13,s->offB>>16);
|
||||||
immWrite(0x15,end>>16);
|
int end=s->offB+s->lengthB-1;
|
||||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
immWrite(0x14,(end>>8)&0xff);
|
||||||
immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
|
immWrite(0x15,end>>16);
|
||||||
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||||
immWrite(0x19,freq&0xff);
|
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
||||||
immWrite(0x1a,(freq>>8)&0xff);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>6) { // ADPCM-A
|
if (c.chan>=adpcmAChanOffs) { // ADPCM-A
|
||||||
if (skipRegisterWrites) break;
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31;
|
||||||
immWrite(0x100,0x80|(1<<(c.chan-7)));
|
if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA)) {
|
||||||
immWrite(0x110+c.chan-7,0);
|
chan[c.chan].furnacePCM=true;
|
||||||
immWrite(0x118+c.chan-7,0);
|
} else {
|
||||||
immWrite(0x120+c.chan-7,0);
|
chan[c.chan].furnacePCM=false;
|
||||||
immWrite(0x128+c.chan-7,0);
|
}
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
chan[c.chan].macroInit(ins);
|
chan[c.chan].macroInit(ins);
|
||||||
if (c.chan<4) {
|
if (c.chan<psgChanOffs) {
|
||||||
if (!chan[c.chan].std.vol.will) {
|
if (!chan[c.chan].std.vol.will) {
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
}
|
}
|
||||||
|
@ -777,28 +799,12 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_OFF:
|
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].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
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].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
|
@ -812,12 +818,12 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
}
|
}
|
||||||
if (c.chan>12) { // ADPCM-B
|
if (c.chan>=adpcmBChanOffs) { // ADPCM-B
|
||||||
immWrite(0x1b,chan[c.chan].outVol);
|
immWrite(0x1b,chan[c.chan].outVol);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>6) { // ADPCM-A
|
if (c.chan>=adpcmAChanOffs) { // ADPCM-A
|
||||||
immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
|
@ -831,6 +837,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case DIV_CMD_GET_VOLUME: {
|
||||||
return chan[c.chan].vol;
|
return chan[c.chan].vol;
|
||||||
break;
|
break;
|
||||||
|
@ -847,25 +860,25 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
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));
|
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>6) {
|
if (c.chan>=adpcmAChanOffs) {
|
||||||
immWrite(0x108+(c.chan-7),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||||
break;
|
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));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_PITCH: {
|
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].pitch=c.value;
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
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);
|
int destFreq=NOTE_OPNB(c.chan,c.value2);
|
||||||
bool return2=false;
|
bool return2=false;
|
||||||
if (destFreq>chan[c.chan].baseFreq) {
|
if (destFreq>chan[c.chan].baseFreq) {
|
||||||
|
@ -899,7 +912,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
iface.sampleBank=sampleBank;
|
iface.sampleBank=sampleBank;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_LEGATO: {
|
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].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
|
@ -916,13 +929,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_FB: {
|
case DIV_CMD_FM_FB: {
|
||||||
if (c.chan>3) break;
|
if (c.chan>=psgChanOffs) break;
|
||||||
chan[c.chan].state.fb=c.value&7;
|
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));
|
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_MULT: {
|
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]];
|
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||||
op.mult=c.value2&15;
|
op.mult=c.value2&15;
|
||||||
|
@ -930,7 +943,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_TL: {
|
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]];
|
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||||
op.tl=c.value2;
|
op.tl=c.value2;
|
||||||
|
@ -942,7 +955,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_AR: {
|
case DIV_CMD_FM_AR: {
|
||||||
if (c.chan>3) break;
|
if (c.chan>=psgChanOffs) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -1093,13 +1106,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_GET_VOLMAX:
|
case DIV_CMD_GET_VOLMAX:
|
||||||
if (c.chan>12) return 255;
|
if (c.chan>=adpcmBChanOffs) return 255;
|
||||||
if (c.chan>6) return 31;
|
if (c.chan>=adpcmAChanOffs) return 31;
|
||||||
if (c.chan>3) return 15;
|
if (c.chan>=psgChanOffs) return 15;
|
||||||
return 127;
|
return 127;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PRE_PORTA:
|
case DIV_CMD_PRE_PORTA:
|
||||||
if (c.chan>3) {
|
if (c.chan>=psgChanOffs) {
|
||||||
if (chan[c.chan].active && c.value2) {
|
if (chan[c.chan].active && c.value2) {
|
||||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
|
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
|
||||||
}
|
}
|
||||||
|
@ -1117,15 +1130,8 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
|
|
||||||
void DivPlatformYM2610::muteChannel(int ch, bool mute) {
|
void DivPlatformYM2610::muteChannel(int ch, bool mute) {
|
||||||
isMuted[ch]=mute;
|
isMuted[ch]=mute;
|
||||||
if (ch>12) { // ADPCM-B
|
if (ch>=psgChanOffs) { // PSG
|
||||||
immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6));
|
DivPlatformYM2610Base::muteChannel(ch,mute);
|
||||||
}
|
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// FM
|
// FM
|
||||||
|
@ -1133,7 +1139,7 @@ void DivPlatformYM2610::muteChannel(int ch, bool mute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610::forceIns() {
|
void DivPlatformYM2610::forceIns() {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<4; j++) {
|
||||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||||
|
@ -1156,7 +1162,7 @@ void DivPlatformYM2610::forceIns() {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i=7; i<14; i++) {
|
for (int i=adpcmAChanOffs; i<=adpcmBChanOffs; i++) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1173,7 +1179,7 @@ void* DivPlatformYM2610::getChanState(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DivMacroInt* DivPlatformYM2610::getChanMacroInt(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;
|
return &chan[ch].std;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1208,17 +1214,20 @@ void DivPlatformYM2610::reset() {
|
||||||
chan[i]=DivPlatformYM2610::Channel();
|
chan[i]=DivPlatformYM2610::Channel();
|
||||||
chan[i].std.setEngine(parent);
|
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].vol=0x7f;
|
||||||
chan[i].outVol=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].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].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++) {
|
for (int i=0; i<512; i++) {
|
||||||
oldWrites[i]=-1;
|
oldWrites[i]=-1;
|
||||||
|
@ -1227,6 +1236,7 @@ void DivPlatformYM2610::reset() {
|
||||||
|
|
||||||
lastBusy=60;
|
lastBusy=60;
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
|
DivPlatformYM2610Base::reset();
|
||||||
|
|
||||||
delay=0;
|
delay=0;
|
||||||
|
|
||||||
|
@ -1236,12 +1246,8 @@ void DivPlatformYM2610::reset() {
|
||||||
immWrite(0x22,0x08);
|
immWrite(0x22,0x08);
|
||||||
|
|
||||||
// PCM volume
|
// PCM volume
|
||||||
immWrite(0x101,0x3f); // A
|
immWrite(0x101,globalADPCMAVolume); // A
|
||||||
immWrite(0x1b,0xff); // B
|
immWrite(0x1b,0xff); // B
|
||||||
|
|
||||||
ay->reset();
|
|
||||||
ay->getRegisterWrites().clear();
|
|
||||||
ay->flushWrites();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformYM2610::isStereo() {
|
bool DivPlatformYM2610::isStereo() {
|
||||||
|
@ -1249,11 +1255,11 @@ bool DivPlatformYM2610::isStereo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformYM2610::keyOffAffectsArp(int ch) {
|
bool DivPlatformYM2610::keyOffAffectsArp(int ch) {
|
||||||
return (ch>3);
|
return (ch>=psgChanOffs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610::notifyInsChange(int ins) {
|
void DivPlatformYM2610::notifyInsChange(int ins) {
|
||||||
for (int i=0; i<14; i++) {
|
for (int i=0; i<chanNum; i++) {
|
||||||
if (chan[i].ins==ins) {
|
if (chan[i].ins==ins) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -1270,46 +1276,13 @@ void DivPlatformYM2610::setSkipRegisterWrites(bool value) {
|
||||||
ay->setSkipRegisterWrites(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) {
|
int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||||
DivPlatformYM2610Base::init(p, channels, sugRate, 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();
|
reset();
|
||||||
return 14;
|
return 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610::quit() {
|
void DivPlatformYM2610::quit() {
|
||||||
for (int i=0; i<14; i++) {
|
|
||||||
delete oscBuf[i];
|
|
||||||
}
|
|
||||||
ay->quit();
|
|
||||||
delete ay;
|
|
||||||
delete fm;
|
delete fm;
|
||||||
DivPlatformYM2610Base::quit();
|
DivPlatformYM2610Base::quit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,41 +19,9 @@
|
||||||
|
|
||||||
#ifndef _YM2610_H
|
#ifndef _YM2610_H
|
||||||
#define _YM2610_H
|
#define _YM2610_H
|
||||||
#include "fmshared_OPN.h"
|
#include "ym2610shared.h"
|
||||||
#include "../macroInt.h"
|
|
||||||
#include "ay.h"
|
|
||||||
#include "sound/ymfm/ymfm_opn.h"
|
|
||||||
|
|
||||||
class DivYM2610Interface: public ymfm::ymfm_interface {
|
class DivPlatformYM2610: public DivPlatformYM2610Base<14> {
|
||||||
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 {
|
|
||||||
protected:
|
protected:
|
||||||
const unsigned short chanOffs[4]={
|
const unsigned short chanOffs[4]={
|
||||||
0x01, 0x02, 0x101, 0x102
|
0x01, 0x02, 0x101, 0x102
|
||||||
|
@ -67,66 +35,9 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
|
||||||
1, 2, 4, 5
|
1, 2, 4, 5
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Channel {
|
friend void putDispatchChip(void*,int);
|
||||||
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, opMaskChanged;
|
|
||||||
int vol, outVol;
|
|
||||||
int sample;
|
|
||||||
unsigned char pan, opMask;
|
|
||||||
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),
|
|
||||||
opMaskChanged(false),
|
|
||||||
vol(0),
|
|
||||||
outVol(15),
|
|
||||||
sample(-1),
|
|
||||||
pan(3),
|
|
||||||
opMask(15) {}
|
|
||||||
};
|
|
||||||
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);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
|
@ -147,9 +58,10 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
const char** getRegisterSheet();
|
const char** getRegisterSheet();
|
||||||
void setFlags(unsigned int flags);
|
|
||||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||||
void quit();
|
void quit();
|
||||||
|
DivPlatformYM2610():
|
||||||
|
DivPlatformYM2610Base<14>(1,4,7,13) {}
|
||||||
~DivPlatformYM2610();
|
~DivPlatformYM2610();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,9 +17,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sound/ymfm/ymfm.h"
|
#include "ym2610shared.h"
|
||||||
#include "ym2610.h"
|
|
||||||
#include "../engine.h"
|
|
||||||
|
|
||||||
uint8_t DivYM2610Interface::ymfm_external_read(ymfm::access_class type, uint32_t address) {
|
uint8_t DivYM2610Interface::ymfm_external_read(ymfm::access_class type, uint32_t address) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
|
@ -18,14 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ym2610b.h"
|
#include "ym2610b.h"
|
||||||
#include "sound/ymfm/ymfm.h"
|
|
||||||
#include "../engine.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define CHIP_FREQBASE fmFreqBase
|
|
||||||
#define CHIP_DIVIDER fmDivBase
|
|
||||||
|
|
||||||
const char* regCheatSheetYM2610B[]={
|
const char* regCheatSheetYM2610B[]={
|
||||||
// SSG
|
// SSG
|
||||||
"SSG_FreqL_A", "000",
|
"SSG_FreqL_A", "000",
|
||||||
|
@ -302,24 +296,6 @@ const char** DivPlatformYM2610B::getRegisterSheet() {
|
||||||
return regCheatSheetYM2610B;
|
return regCheatSheetYM2610B;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
static int os[2];
|
static int os[2];
|
||||||
|
|
||||||
|
@ -364,34 +340,26 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t
|
||||||
bufR[h]=os[1];
|
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));
|
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
ssge->get_last_out(ssgOut);
|
ssge->get_last_out(ssgOut);
|
||||||
for (int i=6; i<9; i++) {
|
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6];
|
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=9; i<15; i++) {
|
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610B::tick(bool sysTick) {
|
void DivPlatformYM2610B::tick(bool sysTick) {
|
||||||
// PSG
|
|
||||||
ay->tick(sysTick);
|
|
||||||
ay->flushWrites();
|
|
||||||
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
|
||||||
immWrite(i.addr&15,i.val);
|
|
||||||
}
|
|
||||||
ay->getRegisterWrites().clear();
|
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
if (i==2 && extMode) continue;
|
if (i==2 && extMode) continue;
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
|
|
||||||
|
@ -546,33 +514,6 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
||||||
chan[i].keyOff=false;
|
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) {
|
|
||||||
chan[15].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[15].note,chan[15].std.arp.val));
|
|
||||||
}
|
|
||||||
chan[15].freqChanged=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;
|
|
||||||
}
|
|
||||||
immWrite(0x19,chan[15].freq&0xff);
|
|
||||||
immWrite(0x1a,(chan[15].freq>>8)&0xff);
|
|
||||||
chan[15].freqChanged=false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=16; i<512; i++) {
|
for (int i=16; i<512; i++) {
|
||||||
if (pendingWrites[i]!=oldWrites[i]) {
|
if (pendingWrites[i]!=oldWrites[i]) {
|
||||||
|
@ -581,7 +522,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 (i==2 && extMode) continue;
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
if (parent->song.linearPitch==2) {
|
if (parent->song.linearPitch==2) {
|
||||||
|
@ -610,18 +551,127 @@ void DivPlatformYM2610B::tick(bool sysTick) {
|
||||||
chan[i].keyOn=false;
|
chan[i].keyOn=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan[adpcmBChanOffs].std.arp.had) {
|
||||||
|
if (!chan[adpcmBChanOffs].inPorta) {
|
||||||
|
chan[adpcmBChanOffs].baseFreq=NOTE_ADPCMB(parent->calcArp(chan[adpcmBChanOffs].note,chan[adpcmBChanOffs].std.arp.val));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeADPCMAOn) {
|
||||||
|
immWrite(0x100,writeADPCMAOn);
|
||||||
|
writeADPCMAOn=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSG
|
||||||
|
ay->tick(sysTick);
|
||||||
|
ay->flushWrites();
|
||||||
|
for (DivRegWrite& i: ay->getRegisterWrites()) {
|
||||||
|
immWrite(i.addr&15,i.val);
|
||||||
|
}
|
||||||
|
ay->getRegisterWrites().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformYM2610B::dispatch(DivCommand c) {
|
int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
if (c.chan>5 && c.chan<9) {
|
if (c.chan>=psgChanOffs && c.chan<adpcmAChanOffs) {
|
||||||
c.chan-=6;
|
c.chan-=psgChanOffs;
|
||||||
return ay->dispatch(c);
|
return ay->dispatch(c);
|
||||||
}
|
}
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
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);
|
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;
|
chan[c.chan].furnacePCM=true;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].furnacePCM=false;
|
chan[c.chan].furnacePCM=false;
|
||||||
|
@ -642,7 +692,6 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
immWrite(0x14,(end>>8)&0xff);
|
immWrite(0x14,(end>>8)&0xff);
|
||||||
immWrite(0x15,end>>16);
|
immWrite(0x15,end>>16);
|
||||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
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) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||||
|
@ -663,45 +712,99 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||||
immWrite(0x12,(s->offB>>8)&0xff);
|
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||||
immWrite(0x13,s->offB>>16);
|
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||||
int end=s->offB+s->lengthB-1;
|
immWrite(0x12,(s->offB>>8)&0xff);
|
||||||
immWrite(0x14,(end>>8)&0xff);
|
immWrite(0x13,s->offB>>16);
|
||||||
immWrite(0x15,end>>16);
|
int end=s->offB+s->lengthB-1;
|
||||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
immWrite(0x14,(end>>8)&0xff);
|
||||||
immWrite(0x10,(s->isLoopable())?0x90:0x80); // start/repeat
|
immWrite(0x15,end>>16);
|
||||||
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||||
immWrite(0x19,freq&0xff);
|
int freq=(65536.0*(double)s->rate)/((double)chipClock/144.0);
|
||||||
immWrite(0x1a,(freq>>8)&0xff);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>8) { // ADPCM-A
|
if (c.chan>=adpcmAChanOffs) { // ADPCM-A
|
||||||
if (skipRegisterWrites) break;
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
|
chan[c.chan].macroVolMul=(ins->type==DIV_INS_AMIGA)?64:31;
|
||||||
immWrite(0x100,0x80|(1<<(c.chan-9)));
|
if (!parent->song.disableSampleMacro && (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMA)) {
|
||||||
immWrite(0x110+c.chan-9,0);
|
chan[c.chan].furnacePCM=true;
|
||||||
immWrite(0x118+c.chan-9,0);
|
} else {
|
||||||
immWrite(0x120+c.chan-9,0);
|
chan[c.chan].furnacePCM=false;
|
||||||
immWrite(0x128+c.chan-9,0);
|
}
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
|
@ -759,28 +862,12 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_OFF:
|
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].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
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].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
|
@ -794,12 +881,12 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
}
|
}
|
||||||
if (c.chan>14) { // ADPCM-B
|
if (c.chan>=adpcmBChanOffs) { // ADPCM-B
|
||||||
immWrite(0x1b,chan[c.chan].outVol);
|
immWrite(0x1b,chan[c.chan].outVol);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>8) { // ADPCM-A
|
if (c.chan>=adpcmAChanOffs) { // ADPCM-A
|
||||||
immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
|
@ -813,6 +900,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case DIV_CMD_GET_VOLUME: {
|
||||||
return chan[c.chan].vol;
|
return chan[c.chan].vol;
|
||||||
break;
|
break;
|
||||||
|
@ -829,25 +923,25 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
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));
|
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan>8) {
|
if (c.chan>=adpcmAChanOffs) {
|
||||||
immWrite(0x108+(c.chan-9),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].vol));
|
immWrite(0x108+(c.chan-adpcmAChanOffs),isMuted[c.chan]?0:((chan[c.chan].pan<<6)|chan[c.chan].outVol));
|
||||||
break;
|
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));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_PITCH: {
|
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].pitch=c.value;
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
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);
|
int destFreq=NOTE_OPNB(c.chan,c.value2);
|
||||||
bool return2=false;
|
bool return2=false;
|
||||||
if (destFreq>chan[c.chan].baseFreq) {
|
if (destFreq>chan[c.chan].baseFreq) {
|
||||||
|
@ -881,7 +975,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
iface.sampleBank=sampleBank;
|
iface.sampleBank=sampleBank;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_LEGATO: {
|
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].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
|
@ -898,13 +992,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_FB: {
|
case DIV_CMD_FM_FB: {
|
||||||
if (c.chan>5) break;
|
if (c.chan>=psgChanOffs) break;
|
||||||
chan[c.chan].state.fb=c.value&7;
|
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));
|
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_MULT: {
|
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]];
|
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||||
op.mult=c.value2&15;
|
op.mult=c.value2&15;
|
||||||
|
@ -912,7 +1006,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_TL: {
|
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]];
|
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||||
op.tl=c.value2;
|
op.tl=c.value2;
|
||||||
|
@ -924,7 +1018,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_AR: {
|
case DIV_CMD_FM_AR: {
|
||||||
if (c.chan>5) break;
|
if (c.chan>=psgChanOffs) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -1075,13 +1169,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_GET_VOLMAX:
|
case DIV_CMD_GET_VOLMAX:
|
||||||
if (c.chan>14) return 255;
|
if (c.chan>=adpcmBChanOffs) return 255;
|
||||||
if (c.chan>8) return 31;
|
if (c.chan>=adpcmAChanOffs) return 31;
|
||||||
if (c.chan>5) return 15;
|
if (c.chan>=psgChanOffs) return 15;
|
||||||
return 127;
|
return 127;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PRE_PORTA:
|
case DIV_CMD_PRE_PORTA:
|
||||||
if (c.chan>5) {
|
if (c.chan>=psgChanOffs) {
|
||||||
if (chan[c.chan].active && c.value2) {
|
if (chan[c.chan].active && c.value2) {
|
||||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
|
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
|
||||||
}
|
}
|
||||||
|
@ -1099,15 +1193,8 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
|
|
||||||
void DivPlatformYM2610B::muteChannel(int ch, bool mute) {
|
void DivPlatformYM2610B::muteChannel(int ch, bool mute) {
|
||||||
isMuted[ch]=mute;
|
isMuted[ch]=mute;
|
||||||
if (ch>14) { // ADPCM-B
|
if (ch>=psgChanOffs) { // PSG
|
||||||
immWrite(0x11,isMuted[ch]?0:(chan[ch].pan<<6));
|
DivPlatformYM2610Base::muteChannel(ch,mute);
|
||||||
}
|
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// FM
|
// FM
|
||||||
|
@ -1115,7 +1202,7 @@ void DivPlatformYM2610B::muteChannel(int ch, bool mute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610B::forceIns() {
|
void DivPlatformYM2610B::forceIns() {
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<4; j++) {
|
||||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||||
|
@ -1138,7 +1225,7 @@ void DivPlatformYM2610B::forceIns() {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i=9; i<16; i++) {
|
for (int i=adpcmAChanOffs; i<=adpcmBChanOffs; i++) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1155,7 +1242,7 @@ void* DivPlatformYM2610B::getChanState(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DivMacroInt* DivPlatformYM2610B::getChanMacroInt(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;
|
return &chan[ch].std;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,17 +1277,20 @@ void DivPlatformYM2610B::reset() {
|
||||||
chan[i]=DivPlatformYM2610B::Channel();
|
chan[i]=DivPlatformYM2610B::Channel();
|
||||||
chan[i].std.setEngine(parent);
|
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].vol=0x7f;
|
||||||
chan[i].outVol=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].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].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++) {
|
for (int i=0; i<512; i++) {
|
||||||
oldWrites[i]=-1;
|
oldWrites[i]=-1;
|
||||||
|
@ -1209,6 +1299,7 @@ void DivPlatformYM2610B::reset() {
|
||||||
|
|
||||||
lastBusy=60;
|
lastBusy=60;
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
|
DivPlatformYM2610Base::reset();
|
||||||
|
|
||||||
delay=0;
|
delay=0;
|
||||||
|
|
||||||
|
@ -1231,11 +1322,11 @@ bool DivPlatformYM2610B::isStereo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformYM2610B::keyOffAffectsArp(int ch) {
|
bool DivPlatformYM2610B::keyOffAffectsArp(int ch) {
|
||||||
return (ch>5);
|
return (ch>=psgChanOffs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610B::notifyInsChange(int ins) {
|
void DivPlatformYM2610B::notifyInsChange(int ins) {
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<chanNum; i++) {
|
||||||
if (chan[i].ins==ins) {
|
if (chan[i].ins==ins) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -1252,46 +1343,13 @@ void DivPlatformYM2610B::setSkipRegisterWrites(bool value) {
|
||||||
ay->setSkipRegisterWrites(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) {
|
int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||||
DivPlatformYM2610Base::init(p, channels, sugRate, 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();
|
reset();
|
||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610B::quit() {
|
void DivPlatformYM2610B::quit() {
|
||||||
for (int i=0; i<16; i++) {
|
|
||||||
delete oscBuf[i];
|
|
||||||
}
|
|
||||||
ay->quit();
|
|
||||||
delete ay;
|
|
||||||
delete fm;
|
delete fm;
|
||||||
DivPlatformYM2610Base::quit();
|
DivPlatformYM2610Base::quit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,9 @@
|
||||||
|
|
||||||
#ifndef _YM2610B_H
|
#ifndef _YM2610B_H
|
||||||
#define _YM2610B_H
|
#define _YM2610B_H
|
||||||
#include "ym2610.h"
|
#include "ym2610shared.h"
|
||||||
#include "../macroInt.h"
|
|
||||||
#include "sound/ymfm/ymfm_opn.h"
|
|
||||||
|
|
||||||
|
class DivPlatformYM2610B: public DivPlatformYM2610Base<16> {
|
||||||
class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
|
||||||
protected:
|
protected:
|
||||||
const unsigned short chanOffs[6]={
|
const unsigned short chanOffs[6]={
|
||||||
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
|
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
|
||||||
|
@ -34,67 +31,9 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
||||||
0, 1, 2, 4, 5, 6
|
0, 1, 2, 4, 5, 6
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Channel {
|
friend void putDispatchChip(void*,int);
|
||||||
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, opMaskChanged;
|
|
||||||
int vol, outVol;
|
|
||||||
int sample;
|
|
||||||
unsigned char pan, opMask;
|
|
||||||
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),
|
|
||||||
opMaskChanged(false),
|
|
||||||
vol(0),
|
|
||||||
outVol(15),
|
|
||||||
sample(-1),
|
|
||||||
pan(3),
|
|
||||||
opMask(15) {}
|
|
||||||
};
|
|
||||||
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);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
|
@ -115,9 +54,10 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
const char** getRegisterSheet();
|
const char** getRegisterSheet();
|
||||||
void setFlags(unsigned int flags);
|
|
||||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||||
void quit();
|
void quit();
|
||||||
|
DivPlatformYM2610B():
|
||||||
|
DivPlatformYM2610Base<16>(2,6,9,15) {}
|
||||||
~DivPlatformYM2610B();
|
~DivPlatformYM2610B();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,31 +18,27 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ym2610bext.h"
|
#include "ym2610bext.h"
|
||||||
#include "../engine.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define CHIP_FREQBASE fmFreqBase
|
|
||||||
#define CHIP_DIVIDER fmDivBase
|
|
||||||
|
|
||||||
int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
if (c.chan<2) {
|
if (c.chan<extChanOffs) {
|
||||||
return DivPlatformYM2610B::dispatch(c);
|
return DivPlatformYM2610B::dispatch(c);
|
||||||
}
|
}
|
||||||
if (c.chan>5) {
|
if (c.chan>(extChanOffs+3)) {
|
||||||
c.chan-=3;
|
c.chan-=3;
|
||||||
return DivPlatformYM2610B::dispatch(c);
|
return DivPlatformYM2610B::dispatch(c);
|
||||||
}
|
}
|
||||||
int ch=c.chan-2;
|
int ch=c.chan-extChanOffs;
|
||||||
int ordch=orderedOps[ch];
|
int ordch=orderedOps[ch];
|
||||||
if (!extMode) {
|
if (!extMode) {
|
||||||
c.chan=2;
|
c.chan=extChanOffs;
|
||||||
return DivPlatformYM2610B::dispatch(c);
|
return DivPlatformYM2610B::dispatch(c);
|
||||||
}
|
}
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
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];
|
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||||
// TODO: how does this work?!
|
// TODO: how does this work?!
|
||||||
if (isOpMuted[ch]) {
|
if (isOpMuted[ch]) {
|
||||||
|
@ -62,8 +58,8 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
opChan[ch].mask=op.enable;
|
opChan[ch].mask=op.enable;
|
||||||
}
|
}
|
||||||
if (opChan[ch].insChanged) { // TODO how does this work?
|
if (opChan[ch].insChanged) { // TODO how does this work?
|
||||||
rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
rWrite(chanOffs[extChanOffs]+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]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||||
}
|
}
|
||||||
opChan[ch].insChanged=false;
|
opChan[ch].insChanged=false;
|
||||||
|
|
||||||
|
@ -84,7 +80,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_VOLUME: {
|
case DIV_CMD_VOLUME: {
|
||||||
opChan[ch].vol=c.value;
|
opChan[ch].vol=c.value;
|
||||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
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];
|
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||||
if (isOpMuted[ch]) {
|
if (isOpMuted[ch]) {
|
||||||
rWrite(baseAddr+0x40,127);
|
rWrite(baseAddr+0x40,127);
|
||||||
|
@ -116,7 +112,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
opChan[i].pan=opChan[ch].pan;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_PITCH: {
|
case DIV_CMD_PITCH: {
|
||||||
|
@ -166,19 +162,19 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_FB: {
|
case DIV_CMD_FM_FB: {
|
||||||
chan[2].state.fb=c.value&7;
|
chan[extChanOffs].state.fb=c.value&7;
|
||||||
rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
|
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_MULT: { // TODO
|
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);
|
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||||
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_TL: { // TODO
|
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);
|
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||||
if (isOutput[ins->fm.alg][c.value]) {
|
if (isOutput[ins->fm.alg][c.value]) {
|
||||||
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
||||||
|
@ -190,15 +186,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_AR: {
|
case DIV_CMD_FM_AR: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
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));
|
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -206,15 +202,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_RS: {
|
case DIV_CMD_FM_RS: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||||
}
|
}
|
||||||
} else if (c.value<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.rs=c.value2&3;
|
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));
|
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -222,15 +218,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_AM: {
|
case DIV_CMD_FM_AM: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||||
}
|
}
|
||||||
} else if (c.value<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.am=c.value2&1;
|
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));
|
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -238,15 +234,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_DR: {
|
case DIV_CMD_FM_DR: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||||
}
|
}
|
||||||
} else if (c.value<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.dr=c.value2&31;
|
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));
|
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -254,15 +250,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_SL: {
|
case DIV_CMD_FM_SL: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||||
}
|
}
|
||||||
} else if (c.value<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;
|
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));
|
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -270,15 +266,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_RR: {
|
case DIV_CMD_FM_RR: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||||
}
|
}
|
||||||
} else if (c.value<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;
|
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));
|
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -286,15 +282,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_D2R: {
|
case DIV_CMD_FM_D2R: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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);
|
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||||
}
|
}
|
||||||
} else if (c.value<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.d2r=c.value2&31;
|
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);
|
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -302,15 +298,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_DT: {
|
case DIV_CMD_FM_DT: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||||
}
|
}
|
||||||
} else if (c.value<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;
|
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));
|
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -318,15 +314,15 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_SSG: {
|
case DIV_CMD_FM_SSG: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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);
|
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);
|
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||||
}
|
}
|
||||||
} else if (c.value<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.ssgEnv=8^(c.value2&15);
|
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);
|
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -411,31 +407,31 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) {
|
void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) {
|
||||||
if (ch<2) {
|
if (ch<extChanOffs) {
|
||||||
DivPlatformYM2610B::muteChannel(ch,mute);
|
DivPlatformYM2610B::muteChannel(ch,mute);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ch>5) {
|
if (ch>(extChanOffs+3)) {
|
||||||
DivPlatformYM2610B::muteChannel(ch-3,mute);
|
DivPlatformYM2610B::muteChannel(ch-3,mute);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isOpMuted[ch-2]=mute;
|
isOpMuted[ch-extChanOffs]=mute;
|
||||||
|
|
||||||
int ordch=orderedOps[ch-2];
|
int ordch=orderedOps[ch-extChanOffs];
|
||||||
DivInstrument* ins=parent->getIns(opChan[ch-2].ins,DIV_INS_FM);
|
DivInstrument* ins=parent->getIns(opChan[ch-extChanOffs].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];
|
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||||
if (isOpMuted[ch-2]) {
|
if (isOpMuted[ch-extChanOffs]) {
|
||||||
rWrite(baseAddr+0x40,127);
|
rWrite(baseAddr+0x40,127);
|
||||||
} else if (isOutput[ins->fm.alg][ordch]) {
|
} 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 {
|
} else {
|
||||||
rWrite(baseAddr+0x40,op.tl);
|
rWrite(baseAddr+0x40,op.tl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610BExt::forceIns() {
|
void DivPlatformYM2610BExt::forceIns() {
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<4; j++) {
|
||||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||||
|
@ -472,7 +468,7 @@ void DivPlatformYM2610BExt::forceIns() {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i=6; i<16; i++) {
|
for (int i=adpcmAChanOffs; i<=adpcmBChanOffs; i++) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
ay->forceIns();
|
ay->forceIns();
|
||||||
|
@ -491,21 +487,21 @@ void DivPlatformYM2610BExt::forceIns() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DivPlatformYM2610BExt::getChanState(int ch) {
|
void* DivPlatformYM2610BExt::getChanState(int ch) {
|
||||||
if (ch>=6) return &chan[ch-3];
|
if (ch>=(extChanOffs+4)) return &chan[ch-3];
|
||||||
if (ch>=2) return &opChan[ch-2];
|
if (ch>=extChanOffs) return &opChan[ch-extChanOffs];
|
||||||
return &chan[ch];
|
return &chan[ch];
|
||||||
}
|
}
|
||||||
|
|
||||||
DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) {
|
DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) {
|
||||||
if (ch>=9 && ch<12) return ay->getChanMacroInt(ch-9);
|
if (ch>=(psgChanOffs+3) && ch<(adpcmAChanOffs+3)) return ay->getChanMacroInt(ch-psgChanOffs-3);
|
||||||
if (ch>=6) return &chan[ch-3].std;
|
if (ch>=(extChanOffs+4)) return &chan[ch-3].std;
|
||||||
if (ch>=2) return NULL; // currently not implemented
|
if (ch>=extChanOffs) return NULL; // currently not implemented
|
||||||
return &chan[ch].std;
|
return &chan[ch].std;
|
||||||
}
|
}
|
||||||
|
|
||||||
DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) {
|
DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) {
|
||||||
if (ch>=6) return oscBuf[ch-3];
|
if (ch>=(extChanOffs+4)) return oscBuf[ch-3];
|
||||||
if (ch<3) return oscBuf[ch];
|
if (ch<(extChanOffs+1)) return oscBuf[ch];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,7 +519,7 @@ void DivPlatformYM2610BExt::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformYM2610BExt::keyOffAffectsArp(int ch) {
|
bool DivPlatformYM2610BExt::keyOffAffectsArp(int ch) {
|
||||||
return (ch>8);
|
return (ch>=(psgChanOffs+3));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610BExt::notifyInsChange(int ins) {
|
void DivPlatformYM2610BExt::notifyInsChange(int ins) {
|
||||||
|
|
|
@ -22,20 +22,9 @@
|
||||||
#include "ym2610b.h"
|
#include "ym2610b.h"
|
||||||
|
|
||||||
class DivPlatformYM2610BExt: public DivPlatformYM2610B {
|
class DivPlatformYM2610BExt: public DivPlatformYM2610B {
|
||||||
struct OpChannel {
|
DivPlatformYM2610Base::OpChannel opChan[4];
|
||||||
DivMacroInt std;
|
|
||||||
unsigned char freqH, freqL;
|
|
||||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
|
|
||||||
signed char konCycles;
|
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask;
|
|
||||||
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), mask(true), vol(0), pan(3) {}
|
|
||||||
};
|
|
||||||
OpChannel opChan[4];
|
|
||||||
bool isOpMuted[4];
|
bool isOpMuted[4];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
|
|
|
@ -18,31 +18,27 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ym2610ext.h"
|
#include "ym2610ext.h"
|
||||||
#include "../engine.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define CHIP_FREQBASE fmFreqBase
|
|
||||||
#define CHIP_DIVIDER fmDivBase
|
|
||||||
|
|
||||||
int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
if (c.chan<1) {
|
if (c.chan<extChanOffs) {
|
||||||
return DivPlatformYM2610::dispatch(c);
|
return DivPlatformYM2610::dispatch(c);
|
||||||
}
|
}
|
||||||
if (c.chan>4) {
|
if (c.chan>(extChanOffs+3)) {
|
||||||
c.chan-=3;
|
c.chan-=3;
|
||||||
return DivPlatformYM2610::dispatch(c);
|
return DivPlatformYM2610::dispatch(c);
|
||||||
}
|
}
|
||||||
int ch=c.chan-1;
|
int ch=c.chan-extChanOffs;
|
||||||
int ordch=orderedOps[ch];
|
int ordch=orderedOps[ch];
|
||||||
if (!extMode) {
|
if (!extMode) {
|
||||||
c.chan=2;
|
c.chan=extChanOffs;
|
||||||
return DivPlatformYM2610::dispatch(c);
|
return DivPlatformYM2610::dispatch(c);
|
||||||
}
|
}
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
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];
|
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||||
// TODO: how does this work?!
|
// TODO: how does this work?!
|
||||||
if (isOpMuted[ch]) {
|
if (isOpMuted[ch]) {
|
||||||
|
@ -62,8 +58,8 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
opChan[ch].mask=op.enable;
|
opChan[ch].mask=op.enable;
|
||||||
}
|
}
|
||||||
if (opChan[ch].insChanged) { // TODO how does this work?
|
if (opChan[ch].insChanged) { // TODO how does this work?
|
||||||
rWrite(chanOffs[1]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
rWrite(chanOffs[extChanOffs]+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]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||||
}
|
}
|
||||||
opChan[ch].insChanged=false;
|
opChan[ch].insChanged=false;
|
||||||
|
|
||||||
|
@ -84,7 +80,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_VOLUME: {
|
case DIV_CMD_VOLUME: {
|
||||||
opChan[ch].vol=c.value;
|
opChan[ch].vol=c.value;
|
||||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
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];
|
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||||
if (isOpMuted[ch]) {
|
if (isOpMuted[ch]) {
|
||||||
rWrite(baseAddr+0x40,127);
|
rWrite(baseAddr+0x40,127);
|
||||||
|
@ -116,7 +112,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
opChan[i].pan=opChan[ch].pan;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_PITCH: {
|
case DIV_CMD_PITCH: {
|
||||||
|
@ -166,19 +162,19 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_FB: {
|
case DIV_CMD_FM_FB: {
|
||||||
chan[1].state.fb=c.value&7;
|
chan[extChanOffs].state.fb=c.value&7;
|
||||||
rWrite(chanOffs[1]+ADDR_FB_ALG,(chan[1].state.alg&7)|(chan[1].state.fb<<3));
|
rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_MULT: { // TODO
|
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);
|
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||||
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_TL: { // TODO
|
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);
|
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||||
if (isOutput[ins->fm.alg][c.value]) {
|
if (isOutput[ins->fm.alg][c.value]) {
|
||||||
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
||||||
|
@ -190,15 +186,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_AR: {
|
case DIV_CMD_FM_AR: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
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));
|
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -206,15 +202,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_RS: {
|
case DIV_CMD_FM_RS: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||||
}
|
}
|
||||||
} else if (c.value<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.rs=c.value2&3;
|
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));
|
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -222,15 +218,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_AM: {
|
case DIV_CMD_FM_AM: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||||
}
|
}
|
||||||
} else if (c.value<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.am=c.value2&1;
|
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));
|
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -238,15 +234,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_DR: {
|
case DIV_CMD_FM_DR: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||||
}
|
}
|
||||||
} else if (c.value<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.dr=c.value2&31;
|
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));
|
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -254,15 +250,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_SL: {
|
case DIV_CMD_FM_SL: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||||
}
|
}
|
||||||
} else if (c.value<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;
|
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));
|
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -270,15 +266,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_RR: {
|
case DIV_CMD_FM_RR: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||||
}
|
}
|
||||||
} else if (c.value<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;
|
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));
|
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -286,15 +282,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_D2R: {
|
case DIV_CMD_FM_D2R: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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);
|
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||||
}
|
}
|
||||||
} else if (c.value<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.d2r=c.value2&31;
|
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);
|
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -302,15 +298,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_DT: {
|
case DIV_CMD_FM_DT: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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;
|
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));
|
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||||
}
|
}
|
||||||
} else if (c.value<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;
|
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));
|
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -318,15 +314,15 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_FM_SSG: {
|
case DIV_CMD_FM_SSG: {
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
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);
|
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);
|
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||||
}
|
}
|
||||||
} else if (c.value<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.ssgEnv=8^(c.value2&15);
|
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);
|
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -411,31 +407,31 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) {
|
void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) {
|
||||||
if (ch<1) {
|
if (ch<extChanOffs) {
|
||||||
DivPlatformYM2610::muteChannel(ch,mute);
|
DivPlatformYM2610::muteChannel(ch,mute);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ch>4) {
|
if (ch>(extChanOffs+3)) {
|
||||||
DivPlatformYM2610::muteChannel(ch-3,mute);
|
DivPlatformYM2610::muteChannel(ch-3,mute);
|
||||||
return;
|
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);
|
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];
|
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||||
if (isOpMuted[ch]) {
|
if (isOpMuted[ch]) {
|
||||||
rWrite(baseAddr+0x40,127);
|
rWrite(baseAddr+0x40,127);
|
||||||
} else if (isOutput[ins->fm.alg][ordch]) {
|
} 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 {
|
} else {
|
||||||
rWrite(baseAddr+0x40,op.tl);
|
rWrite(baseAddr+0x40,op.tl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610Ext::forceIns() {
|
void DivPlatformYM2610Ext::forceIns() {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<psgChanOffs; i++) {
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<4; j++) {
|
||||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||||
|
@ -472,7 +468,7 @@ void DivPlatformYM2610Ext::forceIns() {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i=4; i<14; i++) {
|
for (int i=adpcmAChanOffs; i<=adpcmBChanOffs; i++) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
ay->forceIns();
|
ay->forceIns();
|
||||||
|
@ -491,21 +487,21 @@ void DivPlatformYM2610Ext::forceIns() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DivPlatformYM2610Ext::getChanState(int ch) {
|
void* DivPlatformYM2610Ext::getChanState(int ch) {
|
||||||
if (ch>=5) return &chan[ch-3];
|
if (ch>=(extChanOffs+4)) return &chan[ch-3];
|
||||||
if (ch>=1) return &opChan[ch-1];
|
if (ch>=extChanOffs) return &opChan[ch-extChanOffs];
|
||||||
return &chan[ch];
|
return &chan[ch];
|
||||||
}
|
}
|
||||||
|
|
||||||
DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) {
|
DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) {
|
||||||
if (ch>=7 && ch<10) return ay->getChanMacroInt(ch-7);
|
if (ch>=(psgChanOffs+3) && ch<(adpcmAChanOffs+3)) return ay->getChanMacroInt(ch-psgChanOffs-3);
|
||||||
if (ch>=5) return &chan[ch-3].std;
|
if (ch>=(extChanOffs+4)) return &chan[ch-3].std;
|
||||||
if (ch>=1) return NULL; // currently not implemented
|
if (ch>=extChanOffs) return NULL; // currently not implemented
|
||||||
return &chan[ch].std;
|
return &chan[ch].std;
|
||||||
}
|
}
|
||||||
|
|
||||||
DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) {
|
DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) {
|
||||||
if (ch>=5) return oscBuf[ch-3];
|
if (ch>=(extChanOffs+4)) return oscBuf[ch-3];
|
||||||
if (ch<2) return oscBuf[ch];
|
if (ch<(extChanOffs+1)) return oscBuf[ch];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,7 +519,7 @@ void DivPlatformYM2610Ext::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformYM2610Ext::keyOffAffectsArp(int ch) {
|
bool DivPlatformYM2610Ext::keyOffAffectsArp(int ch) {
|
||||||
return (ch>7);
|
return (ch>=(psgChanOffs+3));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2610Ext::notifyInsChange(int ins) {
|
void DivPlatformYM2610Ext::notifyInsChange(int ins) {
|
||||||
|
|
|
@ -22,20 +22,9 @@
|
||||||
#include "ym2610.h"
|
#include "ym2610.h"
|
||||||
|
|
||||||
class DivPlatformYM2610Ext: public DivPlatformYM2610 {
|
class DivPlatformYM2610Ext: public DivPlatformYM2610 {
|
||||||
struct OpChannel {
|
DivPlatformYM2610Base::OpChannel opChan[4];
|
||||||
DivMacroInt std;
|
|
||||||
unsigned char freqH, freqL;
|
|
||||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
|
|
||||||
signed char konCycles;
|
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask;
|
|
||||||
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), mask(true), vol(0), pan(3) {}
|
|
||||||
};
|
|
||||||
OpChannel opChan[4];
|
|
||||||
bool isOpMuted[4];
|
bool isOpMuted[4];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
|
|
317
src/engine/platform/ym2610shared.h
Normal file
317
src/engine/platform/ym2610shared.h
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
/**
|
||||||
|
* 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, opMaskChanged;
|
||||||
|
int vol, outVol;
|
||||||
|
int sample;
|
||||||
|
unsigned char pan, opMask;
|
||||||
|
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),
|
||||||
|
opMaskChanged(false),
|
||||||
|
vol(0),
|
||||||
|
outVol(15),
|
||||||
|
sample(-1),
|
||||||
|
pan(3),
|
||||||
|
opMask(15),
|
||||||
|
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, mask;
|
||||||
|
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),
|
||||||
|
mask(true),
|
||||||
|
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=chipClock/16;
|
||||||
|
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_MAX);
|
||||||
|
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
|
|
@ -90,7 +90,7 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
if (chan[i].std.vol.had) {
|
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);
|
writeOutVol(i);
|
||||||
}
|
}
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
|
@ -109,9 +109,19 @@ void DivPlatformYMZ280B::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
if (chan[i].std.panL.had) { // panning
|
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);
|
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) {
|
if (chan[i].setPos) {
|
||||||
// force keyon
|
// force keyon
|
||||||
chan[i].keyOn=true;
|
chan[i].keyOn=true;
|
||||||
|
@ -194,6 +204,8 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
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);
|
chan[c.chan].sample=ins->amiga.getSample(c.value);
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||||
|
|
|
@ -32,8 +32,9 @@ class DivPlatformYMZ280B: public DivDispatch {
|
||||||
int sample, wave, ins;
|
int sample, wave, ins;
|
||||||
int note;
|
int note;
|
||||||
int panning;
|
int panning;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, setPos, isNewYMZ;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
|
int macroVolMul;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
|
@ -56,8 +57,10 @@ class DivPlatformYMZ280B: public DivDispatch {
|
||||||
keyOff(false),
|
keyOff(false),
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
setPos(false),
|
setPos(false),
|
||||||
|
isNewYMZ(false),
|
||||||
vol(255),
|
vol(255),
|
||||||
outVol(255) {}
|
outVol(255),
|
||||||
|
macroVolMul(64) {}
|
||||||
};
|
};
|
||||||
Channel chan[8];
|
Channel chan[8];
|
||||||
DivDispatchOscBuffer* oscBuf[8];
|
DivDispatchOscBuffer* oscBuf[8];
|
||||||
|
@ -68,6 +71,7 @@ class DivPlatformYMZ280B: public DivDispatch {
|
||||||
size_t sampleMemLen;
|
size_t sampleMemLen;
|
||||||
ymz280b_device ymz280b;
|
ymz280b_device ymz280b;
|
||||||
unsigned char regPool[256];
|
unsigned char regPool[256];
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -72,6 +72,7 @@ class DivPlatformZXBeeper: public DivDispatch {
|
||||||
int tempR[32];
|
int tempR[32];
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
bool sampleOut;
|
bool sampleOut;
|
||||||
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -167,6 +167,7 @@ const char* cmdName[]={
|
||||||
"X1_010_ENVELOPE_PERIOD",
|
"X1_010_ENVELOPE_PERIOD",
|
||||||
"X1_010_ENVELOPE_SLIDE",
|
"X1_010_ENVELOPE_SLIDE",
|
||||||
"X1_010_AUTO_ENVELOPE",
|
"X1_010_AUTO_ENVELOPE",
|
||||||
|
"X1_010_SAMPLE_BANK_SLOT",
|
||||||
|
|
||||||
"WS_SWEEP_TIME",
|
"WS_SWEEP_TIME",
|
||||||
"WS_SWEEP_AMOUNT",
|
"WS_SWEEP_AMOUNT",
|
||||||
|
@ -191,6 +192,8 @@ const char* cmdName[]={
|
||||||
"DIV_CMD_SU_SYNC_PERIOD_LOW",
|
"DIV_CMD_SU_SYNC_PERIOD_LOW",
|
||||||
"DIV_CMD_SU_SYNC_PERIOD_HIGH",
|
"DIV_CMD_SU_SYNC_PERIOD_HIGH",
|
||||||
|
|
||||||
|
"ADPCMA_GLOBAL_VOLUME",
|
||||||
|
|
||||||
"ALWAYS_SET_VOLUME"
|
"ALWAYS_SET_VOLUME"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -806,6 +809,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
||||||
sPreview.sample=-1;
|
sPreview.sample=-1;
|
||||||
sPreview.wave=-1;
|
sPreview.wave=-1;
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
|
sPreview.dir=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1345,26 +1349,109 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
||||||
DivSample* s=song.sample[sPreview.sample];
|
DivSample* s=song.sample[sPreview.sample];
|
||||||
|
|
||||||
for (size_t i=0; i<prevtotal; i++) {
|
for (size_t i=0; i<prevtotal; i++) {
|
||||||
if (sPreview.pos>=s->samples || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
|
if (sPreview.pos>=(int)s->samples || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) {
|
||||||
samp_temp=0;
|
samp_temp=0;
|
||||||
} else {
|
} else {
|
||||||
samp_temp=s->data16[sPreview.pos++];
|
samp_temp=s->data16[sPreview.pos];
|
||||||
|
if (sPreview.dir) {
|
||||||
|
sPreview.pos--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sPreview.pos++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
blip_add_delta(samp_bb,i,samp_temp-samp_prevSample);
|
blip_add_delta(samp_bb,i,samp_temp-samp_prevSample);
|
||||||
samp_prevSample=samp_temp;
|
samp_prevSample=samp_temp;
|
||||||
|
|
||||||
if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
|
if (sPreview.dir) { // backward
|
||||||
if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) {
|
if (sPreview.pos<s->loopStart || (sPreview.pBegin>=0 && sPreview.pos<sPreview.pBegin)) {
|
||||||
sPreview.pos=s->loopStart;
|
if (s->isLoopable() && sPreview.pos<s->loopEnd) {
|
||||||
|
switch (s->loopMode) {
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD:
|
||||||
|
sPreview.pos=s->loopStart;
|
||||||
|
sPreview.dir=false;
|
||||||
|
break;
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD:
|
||||||
|
sPreview.pos=s->loopEnd-1;
|
||||||
|
sPreview.dir=true;
|
||||||
|
break;
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG:
|
||||||
|
sPreview.pos=s->loopStart;
|
||||||
|
sPreview.dir=false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // forward
|
||||||
|
if (sPreview.pos>=s->loopEnd || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) {
|
||||||
|
if (s->isLoopable() && sPreview.pos>=s->loopStart) {
|
||||||
|
switch (s->loopMode) {
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD:
|
||||||
|
sPreview.pos=s->loopStart;
|
||||||
|
sPreview.dir=false;
|
||||||
|
break;
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD:
|
||||||
|
sPreview.pos=s->loopEnd-1;
|
||||||
|
sPreview.dir=true;
|
||||||
|
break;
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG:
|
||||||
|
sPreview.pos=s->loopEnd-1;
|
||||||
|
sPreview.dir=true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sPreview.dir) { // backward
|
||||||
if (sPreview.pos>=s->getEndPosition() || (sPreview.pEnd>=0 && (int)sPreview.pos>=sPreview.pEnd)) {
|
if (sPreview.pos<=s->loopStart || (sPreview.pBegin>=0 && sPreview.pos<=sPreview.pBegin)) {
|
||||||
if (s->isLoopable() && (int)sPreview.pos>=s->loopStart) {
|
if (s->isLoopable() && sPreview.pos>=s->loopStart) {
|
||||||
sPreview.pos=s->loopStart;
|
switch (s->loopMode) {
|
||||||
} else if (sPreview.pos>=s->samples) {
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD:
|
||||||
sPreview.sample=-1;
|
sPreview.pos=s->loopStart;
|
||||||
|
sPreview.dir=false;
|
||||||
|
break;
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD:
|
||||||
|
sPreview.pos=s->loopEnd-1;
|
||||||
|
sPreview.dir=true;
|
||||||
|
break;
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG:
|
||||||
|
sPreview.pos=s->loopStart;
|
||||||
|
sPreview.dir=false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (sPreview.pos<0) {
|
||||||
|
sPreview.sample=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // forward
|
||||||
|
if (sPreview.pos>=s->loopEnd || (sPreview.pEnd>=0 && sPreview.pos>=sPreview.pEnd)) {
|
||||||
|
if (s->isLoopable() && sPreview.pos>=s->loopStart) {
|
||||||
|
switch (s->loopMode) {
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_FORWARD:
|
||||||
|
sPreview.pos=s->loopStart;
|
||||||
|
sPreview.dir=false;
|
||||||
|
break;
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_BACKWARD:
|
||||||
|
sPreview.pos=s->loopEnd-1;
|
||||||
|
sPreview.dir=true;
|
||||||
|
break;
|
||||||
|
case DivSampleLoopMode::DIV_SAMPLE_LOOP_PINGPONG:
|
||||||
|
sPreview.pos=s->loopEnd-1;
|
||||||
|
sPreview.dir=true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (sPreview.pos>=(int)s->samples) {
|
||||||
|
sPreview.sample=-1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size()) {
|
} else if (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size()) {
|
||||||
|
@ -1375,7 +1462,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
||||||
} else {
|
} else {
|
||||||
samp_temp=((MIN(wave->data[sPreview.pos],wave->max)<<14)/wave->max)-8192;
|
samp_temp=((MIN(wave->data[sPreview.pos],wave->max)<<14)/wave->max)-8192;
|
||||||
}
|
}
|
||||||
if (++sPreview.pos>=(unsigned int)wave->len) {
|
if (++sPreview.pos>=wave->len) {
|
||||||
sPreview.pos=0;
|
sPreview.pos=0;
|
||||||
}
|
}
|
||||||
blip_add_delta(samp_bb,i,samp_temp-samp_prevSample);
|
blip_add_delta(samp_bb,i,samp_temp-samp_prevSample);
|
||||||
|
|
|
@ -39,57 +39,143 @@ DivSampleHistory::~DivSampleHistory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivSample::isLoopable() {
|
bool DivSample::isLoopable() {
|
||||||
return (loopStart>=0 && loopStart<loopEnd) && (loopEnd>loopStart && loopEnd<=(int)samples);
|
return loop && ((loopStart>=0 && loopStart<loopEnd) && (loopEnd>loopStart && loopEnd<=(int)samples));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int DivSample::getEndPosition(DivSampleDepth depth) {
|
int DivSample::getSampleOffset(int offset, int length, DivSampleDepth depth) {
|
||||||
int end=loopEnd;
|
if ((length==0) || (offset==length)) {
|
||||||
unsigned int len=samples;
|
int off=offset;
|
||||||
|
switch (depth) {
|
||||||
|
case DIV_SAMPLE_DEPTH_1BIT:
|
||||||
|
off=(offset+7)/8;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||||
|
off=(offset+7)/8;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_8BIT:
|
||||||
|
off=offset;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_BRR:
|
||||||
|
off=9*((offset+15)/16);
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_VOX:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_16BIT:
|
||||||
|
off=offset*2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return off;
|
||||||
|
} else {
|
||||||
|
int off=offset;
|
||||||
|
int len=length;
|
||||||
|
switch (depth) {
|
||||||
|
case DIV_SAMPLE_DEPTH_1BIT:
|
||||||
|
off=(offset+7)/8;
|
||||||
|
len=(length+7)/8;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||||
|
off=(offset+7)/8;
|
||||||
|
len=(length+7)/8;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
len=(length+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
len=(length+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
len=(length+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
len=(length+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_8BIT:
|
||||||
|
off=offset;
|
||||||
|
len=length;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_BRR:
|
||||||
|
off=9*((offset+15)/16);
|
||||||
|
len=9*((length+15)/16);
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_VOX:
|
||||||
|
off=(offset+1)/2;
|
||||||
|
len=(length+1)/2;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_16BIT:
|
||||||
|
off=offset*2;
|
||||||
|
len=length*2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return isLoopable()?off:len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DivSample::getLoopStartPosition(DivSampleDepth depth) {
|
||||||
|
return getSampleOffset(loopStart,0,depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DivSample::getLoopEndPosition(DivSampleDepth depth) {
|
||||||
|
return getSampleOffset(loopEnd,samples,depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DivSample::getEndPosition(DivSampleDepth depth) {
|
||||||
|
int off=samples;
|
||||||
switch (depth) {
|
switch (depth) {
|
||||||
case DIV_SAMPLE_DEPTH_1BIT:
|
case DIV_SAMPLE_DEPTH_1BIT:
|
||||||
end=(loopEnd+7)/8;
|
off=length1;
|
||||||
len=length1;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
case DIV_SAMPLE_DEPTH_1BIT_DPCM:
|
||||||
end=(loopEnd+7)/8;
|
off=lengthDPCM;
|
||||||
len=lengthDPCM;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
case DIV_SAMPLE_DEPTH_YMZ_ADPCM:
|
||||||
end=(loopEnd+1)/2;
|
off=lengthZ;
|
||||||
len=lengthZ;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
case DIV_SAMPLE_DEPTH_QSOUND_ADPCM:
|
||||||
end=(loopEnd+1)/2;
|
off=lengthQSoundA;
|
||||||
len=lengthQSoundA;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
case DIV_SAMPLE_DEPTH_ADPCM_A:
|
||||||
end=(loopEnd+1)/2;
|
off=lengthA;
|
||||||
len=lengthA;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
case DIV_SAMPLE_DEPTH_ADPCM_B:
|
||||||
end=(loopEnd+1)/2;
|
off=lengthB;
|
||||||
len=lengthB;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_8BIT:
|
case DIV_SAMPLE_DEPTH_8BIT:
|
||||||
end=loopEnd;
|
off=length8;
|
||||||
len=length8;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_BRR:
|
case DIV_SAMPLE_DEPTH_BRR:
|
||||||
end=9*((loopEnd+15)/16);
|
off=lengthBRR;
|
||||||
len=lengthBRR;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_VOX:
|
case DIV_SAMPLE_DEPTH_VOX:
|
||||||
end=(loopEnd+1)/2;
|
off=lengthVOX;
|
||||||
len=lengthVOX;
|
|
||||||
break;
|
break;
|
||||||
case DIV_SAMPLE_DEPTH_16BIT:
|
case DIV_SAMPLE_DEPTH_16BIT:
|
||||||
end=loopEnd*2;
|
off=length16;
|
||||||
len=length16;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return isLoopable()?end:len;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivSample::setSampleCount(unsigned int count) {
|
void DivSample::setSampleCount(unsigned int count) {
|
||||||
|
@ -138,7 +224,7 @@ bool DivSample::save(const char* path) {
|
||||||
if(isLoopable())
|
if(isLoopable())
|
||||||
{
|
{
|
||||||
inst.loop_count = 1;
|
inst.loop_count = 1;
|
||||||
inst.loops[0].mode = SF_LOOP_FORWARD;
|
inst.loops[0].mode = (int)loopMode+SF_LOOP_FORWARD;
|
||||||
inst.loops[0].start = loopStart;
|
inst.loops[0].start = loopStart;
|
||||||
inst.loops[0].end = loopEnd;
|
inst.loops[0].end = loopEnd;
|
||||||
}
|
}
|
||||||
|
@ -895,9 +981,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
|
||||||
duplicate=new unsigned char[getCurBufLen()];
|
duplicate=new unsigned char[getCurBufLen()];
|
||||||
memcpy(duplicate,getCurBuf(),getCurBufLen());
|
memcpy(duplicate,getCurBuf(),getCurBufLen());
|
||||||
}
|
}
|
||||||
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd);
|
h=new DivSampleHistory(duplicate,getCurBufLen(),samples,depth,rate,centerRate,loopStart,loopEnd,loop,loopMode);
|
||||||
} else {
|
} else {
|
||||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd);
|
h=new DivSampleHistory(depth,rate,centerRate,loopStart,loopEnd,loop,loopMode);
|
||||||
}
|
}
|
||||||
if (!doNotPush) {
|
if (!doNotPush) {
|
||||||
while (!redoHist.empty()) {
|
while (!redoHist.empty()) {
|
||||||
|
@ -928,7 +1014,9 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
|
||||||
rate=h->rate; \
|
rate=h->rate; \
|
||||||
centerRate=h->centerRate; \
|
centerRate=h->centerRate; \
|
||||||
loopStart=h->loopStart; \
|
loopStart=h->loopStart; \
|
||||||
loopEnd=h->loopEnd;
|
loopEnd=h->loopEnd; \
|
||||||
|
loop=h->loop; \
|
||||||
|
loopMode=h->loopMode;
|
||||||
|
|
||||||
|
|
||||||
int DivSample::undo() {
|
int DivSample::undo() {
|
||||||
|
|
|
@ -25,6 +25,13 @@
|
||||||
#include "../ta-utils.h"
|
#include "../ta-utils.h"
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
|
enum DivSampleLoopMode: unsigned char {
|
||||||
|
DIV_SAMPLE_LOOP_FORWARD=0,
|
||||||
|
DIV_SAMPLE_LOOP_BACKWARD,
|
||||||
|
DIV_SAMPLE_LOOP_PINGPONG,
|
||||||
|
DIV_SAMPLE_LOOP_MAX // boundary for loop mode
|
||||||
|
};
|
||||||
|
|
||||||
enum DivSampleDepth: unsigned char {
|
enum DivSampleDepth: unsigned char {
|
||||||
DIV_SAMPLE_DEPTH_1BIT=0,
|
DIV_SAMPLE_DEPTH_1BIT=0,
|
||||||
DIV_SAMPLE_DEPTH_1BIT_DPCM=1,
|
DIV_SAMPLE_DEPTH_1BIT_DPCM=1,
|
||||||
|
@ -53,8 +60,10 @@ struct DivSampleHistory {
|
||||||
unsigned int length, samples;
|
unsigned int length, samples;
|
||||||
DivSampleDepth depth;
|
DivSampleDepth depth;
|
||||||
int rate, centerRate, loopStart, loopEnd;
|
int rate, centerRate, loopStart, loopEnd;
|
||||||
|
bool loop;
|
||||||
|
DivSampleLoopMode loopMode;
|
||||||
bool hasSample;
|
bool hasSample;
|
||||||
DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le):
|
DivSampleHistory(void* d, unsigned int l, unsigned int s, DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm):
|
||||||
data((unsigned char*)d),
|
data((unsigned char*)d),
|
||||||
length(l),
|
length(l),
|
||||||
samples(s),
|
samples(s),
|
||||||
|
@ -63,8 +72,10 @@ struct DivSampleHistory {
|
||||||
centerRate(cr),
|
centerRate(cr),
|
||||||
loopStart(ls),
|
loopStart(ls),
|
||||||
loopEnd(le),
|
loopEnd(le),
|
||||||
|
loop(lp),
|
||||||
|
loopMode(lm),
|
||||||
hasSample(true) {}
|
hasSample(true) {}
|
||||||
DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le):
|
DivSampleHistory(DivSampleDepth de, int r, int cr, int ls, int le, bool lp, DivSampleLoopMode lm):
|
||||||
data(NULL),
|
data(NULL),
|
||||||
length(0),
|
length(0),
|
||||||
samples(0),
|
samples(0),
|
||||||
|
@ -73,6 +84,8 @@ struct DivSampleHistory {
|
||||||
centerRate(cr),
|
centerRate(cr),
|
||||||
loopStart(ls),
|
loopStart(ls),
|
||||||
loopEnd(le),
|
loopEnd(le),
|
||||||
|
loop(lp),
|
||||||
|
loopMode(lm),
|
||||||
hasSample(false) {}
|
hasSample(false) {}
|
||||||
~DivSampleHistory();
|
~DivSampleHistory();
|
||||||
};
|
};
|
||||||
|
@ -92,6 +105,13 @@ struct DivSample {
|
||||||
// - 10: VOX ADPCM
|
// - 10: VOX ADPCM
|
||||||
// - 16: 16-bit PCM
|
// - 16: 16-bit PCM
|
||||||
DivSampleDepth depth;
|
DivSampleDepth depth;
|
||||||
|
bool loop;
|
||||||
|
// valid values are:
|
||||||
|
// - 0: No loop
|
||||||
|
// - 1: Forward loop
|
||||||
|
// - 2: Backward loop
|
||||||
|
// - 3: Pingpong loop
|
||||||
|
DivSampleLoopMode loopMode;
|
||||||
|
|
||||||
// these are the new data structures.
|
// these are the new data structures.
|
||||||
signed char* data8; // 8
|
signed char* data8; // 8
|
||||||
|
@ -120,11 +140,29 @@ struct DivSample {
|
||||||
*/
|
*/
|
||||||
bool isLoopable();
|
bool isLoopable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get sample start position
|
||||||
|
* @return the samples start position.
|
||||||
|
*/
|
||||||
|
int getLoopStartPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get sample loop end position
|
||||||
|
* @return the samples loop end position.
|
||||||
|
*/
|
||||||
|
int getLoopEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get sample end position
|
* get sample end position
|
||||||
* @return the samples end position.
|
* @return the samples end position.
|
||||||
*/
|
*/
|
||||||
unsigned int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
int getEndPosition(DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get sample offset
|
||||||
|
* @return the sample offset.
|
||||||
|
*/
|
||||||
|
int getSampleOffset(int offset, int length, DivSampleDepth depth=DIV_SAMPLE_DEPTH_MAX);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @warning DO NOT USE - internal functions
|
* @warning DO NOT USE - internal functions
|
||||||
|
@ -253,6 +291,8 @@ struct DivSample {
|
||||||
loopEnd(-1),
|
loopEnd(-1),
|
||||||
loopOffP(0),
|
loopOffP(0),
|
||||||
depth(DIV_SAMPLE_DEPTH_16BIT),
|
depth(DIV_SAMPLE_DEPTH_16BIT),
|
||||||
|
loop(false),
|
||||||
|
loopMode(DIV_SAMPLE_LOOP_FORWARD),
|
||||||
data8(NULL),
|
data8(NULL),
|
||||||
data16(NULL),
|
data16(NULL),
|
||||||
data1(NULL),
|
data1(NULL),
|
||||||
|
|
|
@ -511,6 +511,7 @@ struct DivSong {
|
||||||
bool e1e2StopOnSameNote;
|
bool e1e2StopOnSameNote;
|
||||||
bool brokenPortaArp;
|
bool brokenPortaArp;
|
||||||
bool snNoLowPeriods;
|
bool snNoLowPeriods;
|
||||||
|
bool disableSampleMacro;
|
||||||
bool autoSystem;
|
bool autoSystem;
|
||||||
|
|
||||||
std::vector<DivInstrument*> ins;
|
std::vector<DivInstrument*> ins;
|
||||||
|
@ -616,6 +617,7 @@ struct DivSong {
|
||||||
e1e2StopOnSameNote(false),
|
e1e2StopOnSameNote(false),
|
||||||
brokenPortaArp(false),
|
brokenPortaArp(false),
|
||||||
snNoLowPeriods(false),
|
snNoLowPeriods(false),
|
||||||
|
disableSampleMacro(true),
|
||||||
autoSystem(true) {
|
autoSystem(true) {
|
||||||
for (int i=0; i<32; i++) {
|
for (int i=0; i<32; i++) {
|
||||||
system[i]=DIV_SYSTEM_NULL;
|
system[i]=DIV_SYSTEM_NULL;
|
||||||
|
|
|
@ -505,6 +505,11 @@ void DivEngine::registerSystems() {
|
||||||
|
|
||||||
fmOPNPostEffectHandlerMap.insert(ayPostEffectHandlerMap.begin(), ayPostEffectHandlerMap.end());
|
fmOPNPostEffectHandlerMap.insert(ayPostEffectHandlerMap.begin(), ayPostEffectHandlerMap.end());
|
||||||
|
|
||||||
|
EffectHandlerMap fmOPNAPostEffectHandlerMap(fmOPNPostEffectHandlerMap);
|
||||||
|
fmOPNAPostEffectHandlerMap.insert({
|
||||||
|
{0x31, {DIV_CMD_ADPCMA_GLOBAL_VOLUME, "1Fxx: Set ADPCM-A global volume (0 to 3F)"}},
|
||||||
|
});
|
||||||
|
|
||||||
EffectHandlerMap fmOPLLPostEffectHandlerMap={
|
EffectHandlerMap fmOPLLPostEffectHandlerMap={
|
||||||
{0x11, {DIV_CMD_FM_FB, "11xx: Set feedback (0 to 7)"}},
|
{0x11, {DIV_CMD_FM_FB, "11xx: Set feedback (0 to 7)"}},
|
||||||
{0x12, {DIV_CMD_FM_TL, "12xx: Set level of operator 1 (0 highest, 3F lowest)", constVal<0>, effectVal}},
|
{0x12, {DIV_CMD_FM_TL, "12xx: Set level of operator 1 (0 highest, 3F lowest)", constVal<0>, effectVal}},
|
||||||
|
@ -661,7 +666,7 @@ void DivEngine::registerSystems() {
|
||||||
{"Pulse 1", "Pulse 2", "Triangle", "Noise", "PCM"},
|
{"Pulse 1", "Pulse 2", "Triangle", "Noise", "PCM"},
|
||||||
{"S1", "S2", "TR", "NO", "PCM"},
|
{"S1", "S2", "TR", "NO", "PCM"},
|
||||||
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM},
|
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||||
{DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA},
|
{DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_NES, DIV_INS_AMIGA},
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
{0x11, {DIV_CMD_NES_DMC, "11xx: Write to delta modulation counter (0 to 7F)"}},
|
{0x11, {DIV_CMD_NES_DMC, "11xx: Write to delta modulation counter (0 to 7F)"}},
|
||||||
|
@ -720,10 +725,10 @@ 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"},
|
{"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"},
|
{"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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPNPostEffectHandlerMap
|
fmOPNAPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_YM2610_EXT]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_YM2610_EXT]=new DivSysDef(
|
||||||
|
@ -732,10 +737,10 @@ 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"},
|
{"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"},
|
{"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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPNPostEffectHandlerMap
|
fmOPNAPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_AY8910]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_AY8910]=new DivSysDef(
|
||||||
|
@ -772,7 +777,7 @@ void DivEngine::registerSystems() {
|
||||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8"},
|
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8"},
|
||||||
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"},
|
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"},
|
||||||
{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_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_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_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM, DIV_INS_OPM},
|
||||||
{},
|
{},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPMPostEffectHandlerMap
|
fmOPMPostEffectHandlerMap
|
||||||
|
@ -911,7 +916,7 @@ void DivEngine::registerSystems() {
|
||||||
{"Pulse 1", "Pulse 2", "PCM"},
|
{"Pulse 1", "Pulse 2", "PCM"},
|
||||||
{"S1", "S2", "PCM"},
|
{"S1", "S2", "PCM"},
|
||||||
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM},
|
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM},
|
||||||
{DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA},
|
{DIV_INS_NES, DIV_INS_NES, DIV_INS_AMIGA},
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
{0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"}},
|
{0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"}},
|
||||||
|
@ -973,10 +978,10 @@ 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"},
|
{"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"},
|
{"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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPNPostEffectHandlerMap
|
fmOPNAPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_PC98_EXT]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_PC98_EXT]=new DivSysDef(
|
||||||
|
@ -985,10 +990,10 @@ 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"},
|
{"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"},
|
{"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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPNPostEffectHandlerMap
|
fmOPNAPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_OPL]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_OPL]=new DivSysDef(
|
||||||
|
@ -1060,6 +1065,7 @@ void DivEngine::registerSystems() {
|
||||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
|
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
|
||||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
|
{"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_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}
|
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1100,7 +1106,7 @@ void DivEngine::registerSystems() {
|
||||||
{"Square"},
|
{"Square"},
|
||||||
{"SQ"},
|
{"SQ"},
|
||||||
{DIV_CH_PULSE},
|
{DIV_CH_PULSE},
|
||||||
{DIV_INS_STD}
|
{DIV_INS_BEEPER}
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_SEGAPCM]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_SEGAPCM]=new DivSysDef(
|
||||||
|
@ -1109,9 +1115,9 @@ 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"},
|
{"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"},
|
{"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_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},
|
{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},
|
||||||
{},
|
{},
|
||||||
{},
|
|
||||||
segaPCMPostEffectHandlerMap
|
segaPCMPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1142,10 +1148,10 @@ 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"},
|
{"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"},
|
{"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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPNPostEffectHandlerMap
|
fmOPNAPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_SFX_BEEPER]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_SFX_BEEPER]=new DivSysDef(
|
||||||
|
@ -1227,10 +1233,10 @@ 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"},
|
{"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"},
|
{"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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPNPostEffectHandlerMap
|
fmOPNAPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_YM2610_FULL_EXT]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_YM2610_FULL_EXT]=new DivSysDef(
|
||||||
|
@ -1239,10 +1245,10 @@ 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"},
|
{"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"},
|
{"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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPNPostEffectHandlerMap
|
fmOPNAPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_OPLL_DRUMS]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_OPLL_DRUMS]=new DivSysDef(
|
||||||
|
@ -1291,8 +1297,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"},
|
{"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"},
|
{"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_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},
|
{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},
|
||||||
{},
|
|
||||||
qSoundEffectHandlerMap
|
qSoundEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1316,10 +1322,10 @@ 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"},
|
{"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"},
|
{"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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPNPostEffectHandlerMap
|
fmOPNAPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_SEGAPCM_COMPAT]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_SEGAPCM_COMPAT]=new DivSysDef(
|
||||||
|
@ -1328,9 +1334,9 @@ void DivEngine::registerSystems() {
|
||||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"},
|
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"},
|
||||||
{"P1", "P2", "P3", "P4", "P5"},
|
{"P1", "P2", "P3", "P4", "P5"},
|
||||||
{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_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},
|
||||||
{},
|
{},
|
||||||
{},
|
|
||||||
segaPCMPostEffectHandlerMap
|
segaPCMPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1345,6 +1351,7 @@ void DivEngine::registerSystems() {
|
||||||
{
|
{
|
||||||
{0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}},
|
{0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}},
|
||||||
{0x11, {DIV_CMD_X1_010_ENVELOPE_SHAPE, "11xx: Set envelope shape"}},
|
{0x11, {DIV_CMD_X1_010_ENVELOPE_SHAPE, "11xx: Set envelope shape"}},
|
||||||
|
{0x12, {DIV_CMD_X1_010_SAMPLE_BANK_SLOT, "12xx: Set sample bank slot (0 to 7)"}},
|
||||||
{0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Toggle PCM mode"}},
|
{0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Toggle PCM mode"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1402,8 +1409,8 @@ void DivEngine::registerSystems() {
|
||||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "ADPCM"},
|
{"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"},
|
{"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_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_AMIGA},
|
{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_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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPLPostEffectHandlerMap
|
fmOPLPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
@ -1414,8 +1421,8 @@ void DivEngine::registerSystems() {
|
||||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat", "ADPCM"},
|
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat", "ADPCM"},
|
||||||
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "P"},
|
{"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_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_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_ADPCMB},
|
||||||
{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},
|
||||||
fmEffectHandlerMap,
|
fmEffectHandlerMap,
|
||||||
fmOPLPostEffectHandlerMap
|
fmOPLPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
@ -1474,8 +1481,8 @@ void DivEngine::registerSystems() {
|
||||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
|
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
|
||||||
{"CH1", "CH2", "CH3", "CH4"},
|
{"CH1", "CH2", "CH3", "CH4"},
|
||||||
{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_MSM6295, DIV_INS_MSM6295, DIV_INS_MSM6295, DIV_INS_MSM6295},
|
||||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||||
{},
|
|
||||||
{
|
{
|
||||||
{0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set chip output rate (0: clock/132; 1: clock/165)"}},
|
{0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set chip output rate (0: clock/132; 1: clock/165)"}},
|
||||||
}
|
}
|
||||||
|
@ -1487,8 +1494,8 @@ void DivEngine::registerSystems() {
|
||||||
{"Sample"},
|
{"Sample"},
|
||||||
{"PCM"},
|
{"PCM"},
|
||||||
{DIV_CH_PCM},
|
{DIV_CH_PCM},
|
||||||
|
{DIV_INS_MSM6258},
|
||||||
{DIV_INS_AMIGA},
|
{DIV_INS_AMIGA},
|
||||||
{},
|
|
||||||
{
|
{
|
||||||
{0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set frequency divider (0-2)"}},
|
{0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set frequency divider (0-2)"}},
|
||||||
{0x21, {DIV_CMD_SAMPLE_MODE, "21xx: Select clock rate (0: full; 1: half)"}},
|
{0x21, {DIV_CMD_SAMPLE_MODE, "21xx: Select clock rate (0: full; 1: half)"}},
|
||||||
|
@ -1501,6 +1508,7 @@ void DivEngine::registerSystems() {
|
||||||
{"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8"},
|
{"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8"},
|
||||||
{"1", "2", "3", "4", "5", "6", "7", "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_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}
|
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -511,7 +511,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
w->writeC(0x95);
|
w->writeC(0x95);
|
||||||
w->writeC(streamID);
|
w->writeC(streamID);
|
||||||
w->writeS(write.val); // sample number
|
w->writeS(write.val); // sample number
|
||||||
w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags
|
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||||
if (sample->isLoopable() && !sampleDir[streamID]) {
|
if (sample->isLoopable() && !sampleDir[streamID]) {
|
||||||
loopTimer[streamID]=sample->length8;
|
loopTimer[streamID]=sample->length8;
|
||||||
loopSample[streamID]=write.val;
|
loopSample[streamID]=write.val;
|
||||||
|
@ -1549,7 +1549,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<song.sampleLen; i++) {
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
DivSample* sample=song.sample[i];
|
DivSample* sample=song.sample[i];
|
||||||
unsigned int alignedSize=(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff);
|
unsigned int alignedSize=(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)+0xff)&(~0xff);
|
||||||
if (alignedSize>65536) alignedSize=65536;
|
if (alignedSize>65536) alignedSize=65536;
|
||||||
if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) {
|
if ((memPos&0xff0000)!=((memPos+alignedSize)&0xff0000)) {
|
||||||
memPos=(memPos+0xffff)&0xff0000;
|
memPos=(memPos+0xffff)&0xff0000;
|
||||||
|
@ -1559,9 +1559,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
sample->offSegaPCM=memPos;
|
sample->offSegaPCM=memPos;
|
||||||
unsigned int readPos=0;
|
unsigned int readPos=0;
|
||||||
for (unsigned int j=0; j<alignedSize; j++) {
|
for (unsigned int j=0; j<alignedSize; j++) {
|
||||||
if (readPos>=sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
if (readPos>=(unsigned int)sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
||||||
if (sample->isLoopable()) {
|
if (sample->isLoopable()) {
|
||||||
readPos=sample->loopStart;
|
readPos=sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||||
pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
|
pcmMem[memPos++]=((unsigned char)sample->data8[readPos]+0x80);
|
||||||
} else {
|
} else {
|
||||||
pcmMem[memPos++]=0x80;
|
pcmMem[memPos++]=0x80;
|
||||||
|
@ -1572,7 +1572,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
readPos++;
|
readPos++;
|
||||||
if (memPos>=16777216) break;
|
if (memPos>=16777216) break;
|
||||||
}
|
}
|
||||||
sample->loopOffP=readPos-sample->loopStart;
|
sample->loopOffP=readPos-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||||
if (memPos>=16777216) break;
|
if (memPos>=16777216) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1897,12 +1897,12 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
if (loopSample[nextToTouch]<song.sampleLen) {
|
if (loopSample[nextToTouch]<song.sampleLen) {
|
||||||
DivSample* sample=song.sample[loopSample[nextToTouch]];
|
DivSample* sample=song.sample[loopSample[nextToTouch]];
|
||||||
// insert loop
|
// insert loop
|
||||||
if (sample->loopStart<(int)sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
if (sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)<sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)) {
|
||||||
w->writeC(0x93);
|
w->writeC(0x93);
|
||||||
w->writeC(nextToTouch);
|
w->writeC(nextToTouch);
|
||||||
w->writeI(sample->off8+sample->loopStart);
|
w->writeI(sample->off8+sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||||
w->writeC(0x81);
|
w->writeC(0x81);
|
||||||
w->writeI(sample->getEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->loopStart);
|
w->writeI(sample->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT)-sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loopSample[nextToTouch]=-1;
|
loopSample[nextToTouch]=-1;
|
||||||
|
|
|
@ -281,6 +281,10 @@ void FurnaceGUI::drawCompatFlags() {
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("behavior changed in 0.6pre1.5");
|
ImGui::SetTooltip("behavior changed in 0.6pre1.5");
|
||||||
}
|
}
|
||||||
|
ImGui::Checkbox("Disable new sample features",&e->song.disableSampleMacro);
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("behavior changed in 0.6pre2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;
|
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
|
@ -338,6 +338,46 @@ void FurnaceGUI::drawInsList(bool asChild) {
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL_DRUMS]);
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL_DRUMS]);
|
||||||
name=fmt::sprintf(ICON_FA_COFFEE " %.2X: %s##_INS%d",i,ins->name,i);
|
name=fmt::sprintf(ICON_FA_COFFEE " %.2X: %s##_INS%d",i,ins->name,i);
|
||||||
break;
|
break;
|
||||||
|
case DIV_INS_OPM:
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPM]);
|
||||||
|
name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i);
|
||||||
|
break;
|
||||||
|
case DIV_INS_NES:
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_NES]);
|
||||||
|
name=fmt::sprintf(ICON_FA_GAMEPAD " %.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:
|
default:
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]);
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]);
|
||||||
name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i);
|
name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i);
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
#include "../engine/platform/nes.h"
|
#include "../engine/platform/nes.h"
|
||||||
#include "../engine/platform/c64.h"
|
#include "../engine/platform/c64.h"
|
||||||
#include "../engine/platform/arcade.h"
|
#include "../engine/platform/arcade.h"
|
||||||
|
#include "../engine/platform/segapcm.h"
|
||||||
|
#include "../engine/platform/ym2203.h"
|
||||||
|
#include "../engine/platform/ym2203ext.h"
|
||||||
|
#include "../engine/platform/ym2608.h"
|
||||||
|
#include "../engine/platform/ym2608ext.h"
|
||||||
#include "../engine/platform/ym2610.h"
|
#include "../engine/platform/ym2610.h"
|
||||||
#include "../engine/platform/ym2610ext.h"
|
#include "../engine/platform/ym2610ext.h"
|
||||||
#include "../engine/platform/ym2610b.h"
|
#include "../engine/platform/ym2610b.h"
|
||||||
|
@ -36,23 +41,110 @@
|
||||||
#include "../engine/platform/tia.h"
|
#include "../engine/platform/tia.h"
|
||||||
#include "../engine/platform/saa.h"
|
#include "../engine/platform/saa.h"
|
||||||
#include "../engine/platform/amiga.h"
|
#include "../engine/platform/amiga.h"
|
||||||
|
#include "../engine/platform/qsound.h"
|
||||||
#include "../engine/platform/x1_010.h"
|
#include "../engine/platform/x1_010.h"
|
||||||
#include "../engine/platform/n163.h"
|
#include "../engine/platform/n163.h"
|
||||||
#include "../engine/platform/vrc6.h"
|
#include "../engine/platform/vrc6.h"
|
||||||
|
#include "../engine/platform/lynx.h"
|
||||||
|
#include "../engine/platform/pcmdac.h"
|
||||||
#include "../engine/platform/dummy.h"
|
#include "../engine/platform/dummy.h"
|
||||||
|
|
||||||
#define GENESIS_DEBUG \
|
#define COMMON_CHIP_DEBUG \
|
||||||
|
ImGui::Text("- rate: %d",ch->rate); \
|
||||||
|
ImGui::Text("- chipClock: %d",ch->chipClock);
|
||||||
|
|
||||||
|
#define FM_CHIP_DEBUG \
|
||||||
|
COMMON_CHIP_DEBUG; \
|
||||||
|
ImGui::Text("- lastBusy: %d",ch->lastBusy); \
|
||||||
|
ImGui::Text("- delay: %d",ch->delay);
|
||||||
|
|
||||||
|
#define FM_OPN_CHIP_DEBUG \
|
||||||
|
FM_CHIP_DEBUG; \
|
||||||
|
ImGui::Text("- fmFreqBase: %.f",ch->fmFreqBase); \
|
||||||
|
ImGui::Text("- fmDivBase: %d",ch->fmDivBase); \
|
||||||
|
ImGui::Text("- ayDiv: %d",ch->ayDiv);
|
||||||
|
|
||||||
|
#define COMMON_CHIP_DEBUG_BOOL \
|
||||||
|
ImGui::TextColored(ch->skipRegisterWrites?colorOn:colorOff,">> SkipRegisterWrites"); \
|
||||||
|
ImGui::TextColored(ch->dumpWrites?colorOn:colorOff,">> DumpWrites");
|
||||||
|
|
||||||
|
#define FM_CHIP_DEBUG_BOOL \
|
||||||
|
COMMON_CHIP_DEBUG_BOOL; \
|
||||||
|
ImGui::TextColored(ch->lastBusy?colorOn:colorOff,">> LastBusy"); \
|
||||||
|
|
||||||
|
#define FM_OPN_CHIP_DEBUG_BOOL \
|
||||||
|
FM_CHIP_DEBUG_BOOL; \
|
||||||
|
ImGui::TextColored(ch->extSys?colorOn:colorOff,">> ExtSys"); \
|
||||||
|
|
||||||
|
#define GENESIS_CHIP_DEBUG \
|
||||||
|
DivPlatformGenesis* ch=(DivPlatformGenesis*)data; \
|
||||||
|
ImGui::Text("> YM2612"); \
|
||||||
|
FM_OPN_CHIP_DEBUG; \
|
||||||
|
ImGui::Text("- lfoValue: %d",ch->lfoValue); \
|
||||||
|
ImGui::Text("- softPCMTimer: %d",ch->softPCMTimer); \
|
||||||
|
FM_OPN_CHIP_DEBUG_BOOL; \
|
||||||
|
ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode"); \
|
||||||
|
ImGui::TextColored(ch->softPCM?colorOn:colorOff,">> SoftPCM"); \
|
||||||
|
ImGui::TextColored(ch->useYMFM?colorOn:colorOff,">> UseYMFM"); \
|
||||||
|
ImGui::TextColored(ch->ladder?colorOn:colorOff,">> Ladder");
|
||||||
|
|
||||||
|
#define OPNB_CHIP_DEBUG \
|
||||||
|
FM_OPN_CHIP_DEBUG; \
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank); \
|
||||||
|
ImGui::Text("- writeADPCMAOff: %d",ch->writeADPCMAOff); \
|
||||||
|
ImGui::Text("- writeADPCMAOn: %d",ch->writeADPCMAOn); \
|
||||||
|
ImGui::Text("- globalADPCMAVolume: %d",ch->globalADPCMAVolume); \
|
||||||
|
ImGui::Text("- extChanOffs: %d",ch->extChanOffs); \
|
||||||
|
ImGui::Text("- psgChanOffs: %d",ch->psgChanOffs); \
|
||||||
|
ImGui::Text("- adpcmAChanOffs: %d",ch->adpcmAChanOffs); \
|
||||||
|
ImGui::Text("- adpcmBChanOffs: %d",ch->adpcmBChanOffs); \
|
||||||
|
ImGui::Text("- chanNum: %d",ch->chanNum); \
|
||||||
|
FM_OPN_CHIP_DEBUG_BOOL; \
|
||||||
|
ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode");
|
||||||
|
|
||||||
|
#define SMS_CHIP_DEBUG \
|
||||||
|
DivPlatformSMS* sms=(DivPlatformSMS*)data; \
|
||||||
|
ImGui::Text("> SMS"); \
|
||||||
|
ImGui::Text("- rate: %d",sms->rate); \
|
||||||
|
ImGui::Text("- chipClock: %d",sms->chipClock); \
|
||||||
|
ImGui::Text("- lastPan: %d",sms->lastPan); \
|
||||||
|
ImGui::Text("- oldValue: %d",sms->oldValue); \
|
||||||
|
ImGui::Text("- snNoiseMode: %d",sms->snNoiseMode); \
|
||||||
|
ImGui::Text("- divider: %d",sms->divider); \
|
||||||
|
ImGui::Text("- toneDivider: %.f",sms->toneDivider); \
|
||||||
|
ImGui::Text("- noiseDivider: %.f",sms->noiseDivider); \
|
||||||
|
ImGui::TextColored(sms->skipRegisterWrites?colorOn:colorOff,">> SkipRegisterWrites"); \
|
||||||
|
ImGui::TextColored(sms->dumpWrites?colorOn:colorOff,">> DumpWrites"); \
|
||||||
|
ImGui::TextColored(sms->updateSNMode?colorOn:colorOff,">> UpdateSNMode"); \
|
||||||
|
ImGui::TextColored(sms->resetPhase?colorOn:colorOff,">> ResetPhase"); \
|
||||||
|
ImGui::TextColored(sms->isRealSN?colorOn:colorOff,">> IsRealSN"); \
|
||||||
|
ImGui::TextColored(sms->stereo?colorOn:colorOff,">> Stereo"); \
|
||||||
|
ImGui::TextColored(sms->nuked?colorOn:colorOff,">> Nuked");
|
||||||
|
|
||||||
|
|
||||||
|
#define GENESIS_CHAN_DEBUG \
|
||||||
DivPlatformGenesis::Channel* ch=(DivPlatformGenesis::Channel*)data; \
|
DivPlatformGenesis::Channel* ch=(DivPlatformGenesis::Channel*)data; \
|
||||||
ImGui::Text("> YM2612"); \
|
ImGui::Text("> YM2612"); \
|
||||||
ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \
|
ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \
|
||||||
ImGui::Text("* freq: %d",ch->freq); \
|
ImGui::Text("* freq: %d",ch->freq); \
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq); \
|
ImGui::Text(" - base: %d",ch->baseFreq); \
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch); \
|
ImGui::Text(" - pitch: %d",ch->pitch); \
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2); \
|
||||||
|
ImGui::Text("- portaPauseFreq: %d",ch->portaPauseFreq); \
|
||||||
|
ImGui::Text("* DAC:"); \
|
||||||
|
ImGui::Text(" - period: %d",ch->dacPeriod); \
|
||||||
|
ImGui::Text(" - rate: %d",ch->dacRate); \
|
||||||
|
ImGui::Text(" - pos: %d",ch->dacPos); \
|
||||||
|
ImGui::Text(" - sample: %d",ch->dacSample); \
|
||||||
|
ImGui::Text(" - delay: %d",ch->dacDelay); \
|
||||||
|
ImGui::Text(" - output: %d",ch->dacOutput); \
|
||||||
ImGui::Text("- note: %d",ch->note); \
|
ImGui::Text("- note: %d",ch->note); \
|
||||||
ImGui::Text("- ins: %d",ch->ins); \
|
ImGui::Text("- ins: %d",ch->ins); \
|
||||||
ImGui::Text("- vol: %.2x",ch->vol); \
|
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||||
ImGui::Text("- outVol: %.2x",ch->outVol); \
|
ImGui::Text("- outVol: %.2x",ch->outVol); \
|
||||||
ImGui::Text("- pan: %x",ch->pan); \
|
ImGui::Text("- pan: %x",ch->pan); \
|
||||||
|
ImGui::Text("- opMask: %x",ch->opMask); \
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank); \
|
||||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \
|
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); \
|
||||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \
|
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); \
|
||||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \
|
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged"); \
|
||||||
|
@ -60,14 +152,41 @@
|
||||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \
|
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff"); \
|
||||||
ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \
|
ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause"); \
|
||||||
ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); \
|
ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC"); \
|
||||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta"); \
|
||||||
|
ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \
|
||||||
|
ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \
|
||||||
|
ImGui::TextColored(ch->dacMode?colorOn:colorOff,">> DACMode"); \
|
||||||
|
ImGui::TextColored(ch->dacReady?colorOn:colorOff,">> DACReady"); \
|
||||||
|
ImGui::TextColored(ch->dacDirection?colorOn:colorOff,">> DACDirection");
|
||||||
|
|
||||||
#define SMS_DEBUG \
|
#define GENESIS_OPCHAN_DEBUG \
|
||||||
|
DivPlatformGenesisExt::OpChannel* ch=(DivPlatformGenesisExt::OpChannel*)data; \
|
||||||
|
ImGui::Text("> YM2612 (per operator)"); \
|
||||||
|
ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \
|
||||||
|
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("- portaPauseFreq: %d",ch->portaPauseFreq); \
|
||||||
|
ImGui::Text("- ins: %d",ch->ins); \
|
||||||
|
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||||
|
ImGui::Text("- pan: %x",ch->pan); \
|
||||||
|
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->mask?colorOn:colorOff,">> Mask");
|
||||||
|
|
||||||
|
#define SMS_CHAN_DEBUG \
|
||||||
DivPlatformSMS::Channel* ch=(DivPlatformSMS::Channel*)data; \
|
DivPlatformSMS::Channel* ch=(DivPlatformSMS::Channel*)data; \
|
||||||
ImGui::Text("> SMS"); \
|
ImGui::Text("> SMS"); \
|
||||||
ImGui::Text("* freq: %d",ch->freq); \
|
ImGui::Text("* freq: %d",ch->freq); \
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq); \
|
ImGui::Text(" - base: %d",ch->baseFreq); \
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch); \
|
ImGui::Text(" - pitch: %d",ch->pitch); \
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2); \
|
||||||
ImGui::Text("- note: %d",ch->note); \
|
ImGui::Text("- note: %d",ch->note); \
|
||||||
ImGui::Text("- ins: %d",ch->ins); \
|
ImGui::Text("- ins: %d",ch->ins); \
|
||||||
ImGui::Text("- vol: %.2x",ch->vol); \
|
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||||
|
@ -78,31 +197,473 @@
|
||||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \
|
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn"); \
|
||||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||||
|
|
||||||
|
#define OPN_CHAN_DEBUG \
|
||||||
|
DivPlatformYM2203::Channel* ch=(DivPlatformYM2203::Channel*)data; \
|
||||||
|
ImGui::Text("> YM2203"); \
|
||||||
|
ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \
|
||||||
|
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("- portaPauseFreq: %d",ch->portaPauseFreq); \
|
||||||
|
ImGui::Text("* PSG:"); \
|
||||||
|
ImGui::Text(" - psgMode: %d",ch->psgMode); \
|
||||||
|
ImGui::Text(" - autoEnvNum: %d",ch->autoEnvNum); \
|
||||||
|
ImGui::Text(" - autoEnvDen: %d",ch->autoEnvDen); \
|
||||||
|
ImGui::Text("- sample: %d",ch->sample); \
|
||||||
|
ImGui::Text("- note: %d",ch->note); \
|
||||||
|
ImGui::Text("- ins: %d",ch->ins); \
|
||||||
|
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||||
|
ImGui::Text("- outVol: %.2x",ch->outVol); \
|
||||||
|
ImGui::Text("- opMask: %x",ch->opMask); \
|
||||||
|
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->hardReset?colorOn:colorOff,">> hardReset"); \
|
||||||
|
ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \
|
||||||
|
ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM");
|
||||||
|
|
||||||
|
#define OPN_OPCHAN_DEBUG \
|
||||||
|
DivPlatformYM2203Ext::OpChannel* ch=(DivPlatformYM2203Ext::OpChannel*)data; \
|
||||||
|
ImGui::Text("> YM2203 (per operator)"); \
|
||||||
|
ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \
|
||||||
|
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("- portaPauseFreq: %d",ch->portaPauseFreq); \
|
||||||
|
ImGui::Text("- ins: %d",ch->ins); \
|
||||||
|
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||||
|
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->mask?colorOn:colorOff,">> Mask");
|
||||||
|
|
||||||
|
#define OPNB_CHAN_DEBUG \
|
||||||
|
ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \
|
||||||
|
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("- portaPauseFreq: %d",ch->portaPauseFreq); \
|
||||||
|
ImGui::Text("* PSG:"); \
|
||||||
|
ImGui::Text(" - psgMode: %d",ch->psgMode); \
|
||||||
|
ImGui::Text(" - autoEnvNum: %d",ch->autoEnvNum); \
|
||||||
|
ImGui::Text(" - autoEnvDen: %d",ch->autoEnvDen); \
|
||||||
|
ImGui::Text("- sample: %d",ch->sample); \
|
||||||
|
ImGui::Text("- note: %d",ch->note); \
|
||||||
|
ImGui::Text("- ins: %d",ch->ins); \
|
||||||
|
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||||
|
ImGui::Text("- outVol: %.2x",ch->outVol); \
|
||||||
|
ImGui::Text("- pan: %x",ch->pan); \
|
||||||
|
ImGui::Text("- opMask: %x",ch->opMask); \
|
||||||
|
ImGui::Text("- macroVolMul: %x",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->inPorta?colorOn:colorOff,">> InPorta"); \
|
||||||
|
ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \
|
||||||
|
ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \
|
||||||
|
ImGui::TextColored(ch->furnacePCM?colorOn:colorOff,">> FurnacePCM");
|
||||||
|
|
||||||
|
#define OPNB_OPCHAN_DEBUG \
|
||||||
|
ImGui::Text("- freqHL: %.2x%.2x",ch->freqH,ch->freqL); \
|
||||||
|
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("- portaPauseFreq: %d",ch->portaPauseFreq); \
|
||||||
|
ImGui::Text("- ins: %d",ch->ins); \
|
||||||
|
ImGui::Text("- vol: %.2x",ch->vol); \
|
||||||
|
ImGui::Text("- pan: %x",ch->pan); \
|
||||||
|
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->mask?colorOn:colorOff,">> Mask");
|
||||||
|
|
||||||
|
void putDispatchChip(void* data, int type) {
|
||||||
|
ImVec4 colorOn=ImVec4(1.0f,1.0f,0.0f,1.0f);
|
||||||
|
ImVec4 colorOff=ImVec4(0.3f,0.3f,0.3f,1.0f);
|
||||||
|
switch (type) {
|
||||||
|
case DIV_SYSTEM_YM2612:
|
||||||
|
case DIV_SYSTEM_YM2612_EXT:
|
||||||
|
case DIV_SYSTEM_YM2612_FRAC:
|
||||||
|
case DIV_SYSTEM_YM2612_FRAC_EXT: {
|
||||||
|
GENESIS_CHIP_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_GENESIS:
|
||||||
|
case DIV_SYSTEM_GENESIS_EXT: {
|
||||||
|
GENESIS_CHIP_DEBUG;
|
||||||
|
SMS_CHIP_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_SMS: {
|
||||||
|
SMS_CHIP_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_OPN:
|
||||||
|
case DIV_SYSTEM_OPN_EXT: {
|
||||||
|
DivPlatformYM2203* ch=(DivPlatformYM2203*)data;
|
||||||
|
ImGui::Text("> YM2203");
|
||||||
|
FM_OPN_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank);
|
||||||
|
ImGui::Text("- prescale: %d",ch->prescale);
|
||||||
|
FM_OPN_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_PC98:
|
||||||
|
case DIV_SYSTEM_PC98_EXT: {
|
||||||
|
DivPlatformYM2608* ch=(DivPlatformYM2608*)data;
|
||||||
|
ImGui::Text("> YM2608");
|
||||||
|
FM_OPN_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank);
|
||||||
|
ImGui::Text("- writeRSSOff: %d",ch->writeRSSOff);
|
||||||
|
ImGui::Text("- writeRSSOn: %d",ch->writeRSSOn);
|
||||||
|
ImGui::Text("- globalRSSVolume: %d",ch->globalRSSVolume);
|
||||||
|
ImGui::Text("- prescale: %d",ch->prescale);
|
||||||
|
FM_OPN_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_YM2610:
|
||||||
|
case DIV_SYSTEM_YM2610_EXT:
|
||||||
|
case DIV_SYSTEM_YM2610_FULL:
|
||||||
|
case DIV_SYSTEM_YM2610_FULL_EXT: {
|
||||||
|
DivPlatformYM2610* ch=(DivPlatformYM2610*)data;
|
||||||
|
ImGui::Text("> YM2610");
|
||||||
|
OPNB_CHIP_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_YM2610B:
|
||||||
|
case DIV_SYSTEM_YM2610B_EXT: {
|
||||||
|
DivPlatformYM2610B* ch=(DivPlatformYM2610B*)data;
|
||||||
|
ImGui::Text("> YM2610B");
|
||||||
|
OPNB_CHIP_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_GB: {
|
||||||
|
DivPlatformGB* ch=(DivPlatformGB*)data;
|
||||||
|
ImGui::Text("> GameBoy");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- lastPan: %d",ch->lastPan);
|
||||||
|
ImGui::Text("- antiClickPeriodCount: %d",ch->antiClickPeriodCount);
|
||||||
|
ImGui::Text("- antiClickWavePos: %d",ch->antiClickWavePos);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->antiClickEnabled?colorOn:colorOff,">> AntiClickEnabled");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_PCE: {
|
||||||
|
DivPlatformPCE* ch=(DivPlatformPCE*)data;
|
||||||
|
ImGui::Text("> PCEngine");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- lastPan: %d",ch->lastPan);
|
||||||
|
ImGui::Text("- cycles: %d",ch->cycles);
|
||||||
|
ImGui::Text("- curChan: %d",ch->curChan);
|
||||||
|
ImGui::Text("- delay: %d",ch->delay);
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank);
|
||||||
|
ImGui::Text("- lfoMode: %d",ch->lfoMode);
|
||||||
|
ImGui::Text("- lfoSpeed: %d",ch->lfoSpeed);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->antiClickEnabled?colorOn:colorOff,">> AntiClickEnabled");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_NES: {
|
||||||
|
DivPlatformNES* ch=(DivPlatformNES*)data;
|
||||||
|
ImGui::Text("> NES");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("* DAC:");
|
||||||
|
ImGui::Text(" - Period: %d",ch->dacPeriod);
|
||||||
|
ImGui::Text(" - Rate: %d",ch->dacRate);
|
||||||
|
ImGui::Text(" - Pos: %d",ch->dacPos);
|
||||||
|
ImGui::Text(" - AntiClick: %d",ch->dacAntiClick);
|
||||||
|
ImGui::Text(" - Sample: %d",ch->dacSample);
|
||||||
|
ImGui::Text("- dpcmBank: %d",ch->dpcmBank);
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank);
|
||||||
|
ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf);
|
||||||
|
ImGui::Text("- apuType: %d",ch->apuType);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->dpcmMode?colorOn:colorOff,">> DPCMMode");
|
||||||
|
ImGui::TextColored(ch->dacAntiClickOn?colorOn:colorOff,">> DACAntiClickOn");
|
||||||
|
ImGui::TextColored(ch->useNP?colorOn:colorOff,">> UseNP");
|
||||||
|
ImGui::TextColored(ch->goingToLoop?colorOn:colorOff,">> GoingToLoop");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: {
|
||||||
|
DivPlatformC64* ch=(DivPlatformC64*)data;
|
||||||
|
ImGui::Text("> C64");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- filtControl: %d",ch->filtControl);
|
||||||
|
ImGui::Text("- filtRes: %d",ch->filtRes);
|
||||||
|
ImGui::Text("- vol: %d",ch->vol);
|
||||||
|
ImGui::Text("- writeOscBuf: %d",ch->writeOscBuf);
|
||||||
|
ImGui::Text("- filtCut: %d",ch->filtCut);
|
||||||
|
ImGui::Text("- resetTime: %d",ch->resetTime);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->isFP?colorOn:colorOff,">> IsFP");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_ARCADE:
|
||||||
|
case DIV_SYSTEM_YM2151: {
|
||||||
|
DivPlatformArcade* ch=(DivPlatformArcade*)data;
|
||||||
|
ImGui::Text("> YM2151");
|
||||||
|
FM_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- baseFreqOff: %d",ch->baseFreqOff);
|
||||||
|
ImGui::Text("- amDepth: %d",ch->amDepth);
|
||||||
|
ImGui::Text("- pmDepth: %d",ch->pmDepth);
|
||||||
|
FM_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->useYMFM?colorOn:colorOff,">> UseYMFM");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_SEGAPCM:
|
||||||
|
case DIV_SYSTEM_SEGAPCM_COMPAT: {
|
||||||
|
DivPlatformSegaPCM* ch=(DivPlatformSegaPCM*)data;
|
||||||
|
ImGui::Text("> SegaPCM");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- delay: %d",ch->delay);
|
||||||
|
ImGui::Text("- pcmL: %d",ch->pcmL);
|
||||||
|
ImGui::Text("- pcmR: %d",ch->pcmR);
|
||||||
|
ImGui::Text("- pcmCycles: %d",ch->pcmCycles);
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank);
|
||||||
|
ImGui::Text("- lastBusy: %d",ch->lastBusy);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_AY8910: {
|
||||||
|
DivPlatformAY8910* ch=(DivPlatformAY8910*)data;
|
||||||
|
ImGui::Text("> AY-3-8910");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- lastBusy: %d",ch->lastBusy);
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank);
|
||||||
|
ImGui::Text("- stereoSep: %d",ch->stereoSep);
|
||||||
|
ImGui::Text("- delay: %d",ch->delay);
|
||||||
|
ImGui::Text("- extClock: %d",ch->extClock);
|
||||||
|
ImGui::Text("- extDiv: %d",ch->extDiv);
|
||||||
|
ImGui::Text("- portAVal: %d",ch->portAVal);
|
||||||
|
ImGui::Text("- portBVal: %d",ch->portBVal);
|
||||||
|
ImGui::Text("* envelope:");
|
||||||
|
ImGui::Text(" - mode: %d",ch->ayEnvMode);
|
||||||
|
ImGui::Text(" - period: %d",ch->ayEnvPeriod);
|
||||||
|
ImGui::Text(" * slide: %d",ch->ayEnvSlide);
|
||||||
|
ImGui::Text(" - slideLow: %d",ch->ayEnvSlideLow);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode");
|
||||||
|
ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo");
|
||||||
|
ImGui::TextColored(ch->sunsoft?colorOn:colorOff,">> Sunsoft");
|
||||||
|
ImGui::TextColored(ch->intellivision?colorOn:colorOff,">> Intellivision");
|
||||||
|
ImGui::TextColored(ch->clockSel?colorOn:colorOff,">> ClockSel");
|
||||||
|
ImGui::TextColored(ch->ioPortA?colorOn:colorOff,">> IoPortA");
|
||||||
|
ImGui::TextColored(ch->ioPortB?colorOn:colorOff,">> IoPortB");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_AY8930: {
|
||||||
|
DivPlatformAY8930* ch=(DivPlatformAY8930*)data;
|
||||||
|
ImGui::Text("> AY8930");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("* noise:");
|
||||||
|
ImGui::Text(" - and: %d",ch->ayNoiseAnd);
|
||||||
|
ImGui::Text(" - or: %d",ch->ayNoiseOr);
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank);
|
||||||
|
ImGui::Text("- stereoSep: %d",ch->stereoSep);
|
||||||
|
ImGui::Text("- delay: %d",ch->delay);
|
||||||
|
ImGui::Text("- portAVal: %d",ch->portAVal);
|
||||||
|
ImGui::Text("- portBVal: %d",ch->portBVal);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->bank?colorOn:colorOff,">> Bank");
|
||||||
|
ImGui::TextColored(ch->extMode?colorOn:colorOff,">> ExtMode");
|
||||||
|
ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo");
|
||||||
|
ImGui::TextColored(ch->clockSel?colorOn:colorOff,">> ClockSel");
|
||||||
|
ImGui::TextColored(ch->ioPortA?colorOn:colorOff,">> IoPortA");
|
||||||
|
ImGui::TextColored(ch->ioPortB?colorOn:colorOff,">> IoPortB");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_QSOUND: {
|
||||||
|
DivPlatformQSound* ch=(DivPlatformQSound*)data;
|
||||||
|
ImGui::Text("> QSound");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("* echo:");
|
||||||
|
ImGui::Text(" - delay: %d",ch->echoDelay);
|
||||||
|
ImGui::Text(" - feedback: %d",ch->echoFeedback);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_X1_010: {
|
||||||
|
DivPlatformX1_010* ch=(DivPlatformX1_010*)data;
|
||||||
|
ImGui::Text("> X1-010");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- sampleBank: %d",ch->sampleBank);
|
||||||
|
ImGui::Text("- bankSlot: [%d,%d,%d,%d,%d,%d,%d,%d]",ch->bankSlot[0],ch->bankSlot[1],ch->bankSlot[2],ch->bankSlot[3],ch->bankSlot[4],ch->bankSlot[5],ch->bankSlot[6],ch->bankSlot[7]);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->stereo?colorOn:colorOff,">> Stereo");
|
||||||
|
ImGui::TextColored(ch->isBanked?colorOn:colorOff,">> IsBanked");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_N163: {
|
||||||
|
DivPlatformN163* ch=(DivPlatformN163*)data;
|
||||||
|
ImGui::Text("> N163");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- initChanMax: %d",ch->initChanMax);
|
||||||
|
ImGui::Text("- chanMax: %d",ch->chanMax);
|
||||||
|
ImGui::Text("- loadWave: %d",ch->loadWave);
|
||||||
|
ImGui::Text("- loadPos: %d",ch->loadPos);
|
||||||
|
ImGui::Text("- loadLen: %d",ch->loadLen);
|
||||||
|
ImGui::Text("- loadMode: %d",ch->loadMode);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->multiplex?colorOn:colorOff,">> Multiplex");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_VRC6: {
|
||||||
|
DivPlatformVRC6* ch=(DivPlatformVRC6*)data;
|
||||||
|
ImGui::Text("> VRC6");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- sampleBank: %.2x",ch->sampleBank);
|
||||||
|
ImGui::Text("- writeOscBuf: %.2x",ch->writeOscBuf);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_LYNX: {
|
||||||
|
DivPlatformLynx* ch=(DivPlatformLynx*)data;
|
||||||
|
ImGui::Text("> Lynx");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_PCM_DAC: {
|
||||||
|
DivPlatformPCMDAC* ch=(DivPlatformPCMDAC*)data;
|
||||||
|
ImGui::Text("> PCM DAC");
|
||||||
|
COMMON_CHIP_DEBUG;
|
||||||
|
ImGui::Text("- outDepth: %d",ch->outDepth);
|
||||||
|
COMMON_CHIP_DEBUG_BOOL;
|
||||||
|
ImGui::TextColored(ch->outStereo?colorOn:colorOff,">> OutStereo");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ImGui::Text("Unimplemented chip! Help!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
void putDispatchChan(void* data, int chanNum, int type) {
|
void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImVec4 colorOn=ImVec4(1.0f,1.0f,0.0f,1.0f);
|
ImVec4 colorOn=ImVec4(1.0f,1.0f,0.0f,1.0f);
|
||||||
ImVec4 colorOff=ImVec4(0.3f,0.3f,0.3f,1.0f);
|
ImVec4 colorOff=ImVec4(0.3f,0.3f,0.3f,1.0f);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DIV_SYSTEM_GENESIS:
|
case DIV_SYSTEM_GENESIS: {
|
||||||
case DIV_SYSTEM_YM2612: {
|
|
||||||
if (chanNum>5) {
|
if (chanNum>5) {
|
||||||
SMS_DEBUG;
|
SMS_CHAN_DEBUG;
|
||||||
} else {
|
} else {
|
||||||
GENESIS_DEBUG;
|
GENESIS_CHAN_DEBUG;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_SYSTEM_GENESIS_EXT: {
|
case DIV_SYSTEM_GENESIS_EXT: {
|
||||||
if (chanNum>8) {
|
if (chanNum>8) {
|
||||||
SMS_DEBUG;
|
SMS_CHAN_DEBUG;
|
||||||
} else if (chanNum>=2 && chanNum<=5) {
|
} else if (chanNum>=2 && chanNum<=5) {
|
||||||
// TODO ext ch 3 debug
|
GENESIS_OPCHAN_DEBUG
|
||||||
} else {
|
} else {
|
||||||
GENESIS_DEBUG;
|
GENESIS_CHAN_DEBUG;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_YM2612:
|
||||||
|
case DIV_SYSTEM_YM2612_FRAC: {
|
||||||
|
GENESIS_CHAN_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_YM2612_EXT:
|
||||||
|
case DIV_SYSTEM_YM2612_FRAC_EXT: {
|
||||||
|
if (chanNum>=2 && chanNum<=5) {
|
||||||
|
GENESIS_OPCHAN_DEBUG
|
||||||
|
} else {
|
||||||
|
GENESIS_CHAN_DEBUG;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_SYSTEM_SMS: {
|
case DIV_SYSTEM_SMS: {
|
||||||
SMS_DEBUG;
|
SMS_CHAN_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_OPN: {
|
||||||
|
OPN_CHAN_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_OPN_EXT: {
|
||||||
|
if (chanNum>=2 && chanNum<=5) {
|
||||||
|
OPN_OPCHAN_DEBUG;
|
||||||
|
} else {
|
||||||
|
OPN_CHAN_DEBUG;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_PC98: {
|
||||||
|
DivPlatformYM2608::Channel* ch=(DivPlatformYM2608::Channel*)data;
|
||||||
|
ImGui::Text("> YM2608");
|
||||||
|
OPNB_CHAN_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_PC98_EXT: {
|
||||||
|
if (chanNum>=2 && chanNum<=5) {
|
||||||
|
DivPlatformYM2608Ext::OpChannel* ch=(DivPlatformYM2608Ext::OpChannel*)data;
|
||||||
|
ImGui::Text("> YM2608 (per operator)");
|
||||||
|
OPNB_OPCHAN_DEBUG;
|
||||||
|
} else {
|
||||||
|
DivPlatformYM2608Ext::Channel* ch=(DivPlatformYM2608Ext::Channel*)data;
|
||||||
|
ImGui::Text("> YM2608");
|
||||||
|
OPNB_CHAN_DEBUG;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_YM2610:
|
||||||
|
case DIV_SYSTEM_YM2610_FULL: {
|
||||||
|
DivPlatformYM2610::Channel* ch=(DivPlatformYM2610::Channel*)data;
|
||||||
|
ImGui::Text("> YM2610");
|
||||||
|
OPNB_CHAN_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_YM2610B: {
|
||||||
|
DivPlatformYM2610B::Channel* ch=(DivPlatformYM2610B::Channel*)data;
|
||||||
|
ImGui::Text("> YM2610B");
|
||||||
|
OPNB_CHAN_DEBUG;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_YM2610_EXT:
|
||||||
|
case DIV_SYSTEM_YM2610_FULL_EXT: {
|
||||||
|
if (chanNum>=1 && chanNum<=4) {
|
||||||
|
DivPlatformYM2610Ext::OpChannel* ch=(DivPlatformYM2610Ext::OpChannel*)data;
|
||||||
|
ImGui::Text("> YM2610 (per operator)");
|
||||||
|
OPNB_OPCHAN_DEBUG;
|
||||||
|
} else {
|
||||||
|
DivPlatformYM2610Ext::Channel* ch=(DivPlatformYM2610Ext::Channel*)data;
|
||||||
|
ImGui::Text("> YM2610");
|
||||||
|
OPNB_CHAN_DEBUG;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DIV_SYSTEM_YM2610B_EXT: {
|
||||||
|
if (chanNum>=2 && chanNum<=5) {
|
||||||
|
DivPlatformYM2610BExt::OpChannel* ch=(DivPlatformYM2610BExt::OpChannel*)data;
|
||||||
|
ImGui::Text("> YM2610B (per operator)");
|
||||||
|
OPNB_OPCHAN_DEBUG;
|
||||||
|
} else {
|
||||||
|
DivPlatformYM2610BExt::Channel* ch=(DivPlatformYM2610BExt::Channel*)data;
|
||||||
|
ImGui::Text("> YM2610B");
|
||||||
|
OPNB_CHAN_DEBUG;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_SYSTEM_GB: {
|
case DIV_SYSTEM_GB: {
|
||||||
|
@ -111,6 +672,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text("* freq: %d",ch->freq);
|
ImGui::Text("* freq: %d",ch->freq);
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||||
ImGui::Text("- note: %d",ch->note);
|
ImGui::Text("- note: %d",ch->note);
|
||||||
ImGui::Text("- ins: %d",ch->ins);
|
ImGui::Text("- ins: %d",ch->ins);
|
||||||
ImGui::Text("- duty: %d",ch->duty);
|
ImGui::Text("- duty: %d",ch->duty);
|
||||||
|
@ -133,17 +695,20 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text("* freq: %d",ch->freq);
|
ImGui::Text("* freq: %d",ch->freq);
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||||
ImGui::Text("- note: %d",ch->note);
|
ImGui::Text("- note: %d",ch->note);
|
||||||
ImGui::Text("* DAC:");
|
ImGui::Text("* DAC:");
|
||||||
ImGui::Text(" - period: %d",ch->dacPeriod);
|
ImGui::Text(" - period: %d",ch->dacPeriod);
|
||||||
ImGui::Text(" - rate: %d",ch->dacRate);
|
ImGui::Text(" - rate: %d",ch->dacRate);
|
||||||
ImGui::Text(" - pos: %d",ch->dacPos);
|
ImGui::Text(" - pos: %d",ch->dacPos);
|
||||||
|
ImGui::Text(" - out: %d",ch->dacOut);
|
||||||
ImGui::Text(" - sample: %d",ch->dacSample);
|
ImGui::Text(" - sample: %d",ch->dacSample);
|
||||||
ImGui::Text("- ins: %d",ch->ins);
|
ImGui::Text("- ins: %d",ch->ins);
|
||||||
ImGui::Text("- pan: %.2x",ch->pan);
|
ImGui::Text("- pan: %.2x",ch->pan);
|
||||||
ImGui::Text("- vol: %.2x",ch->vol);
|
ImGui::Text("- vol: %.2x",ch->vol);
|
||||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||||
ImGui::Text("- wave: %d",ch->wave);
|
ImGui::Text("- wave: %d",ch->wave);
|
||||||
|
ImGui::Text("- macroVolMul: %d",ch->macroVolMul);
|
||||||
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
ImGui::TextColored(ch->active?colorOn:colorOff,">> Active");
|
||||||
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged");
|
||||||
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");
|
||||||
|
@ -161,6 +726,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text("* freq: %d",ch->freq);
|
ImGui::Text("* freq: %d",ch->freq);
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||||
ImGui::Text(" - prev: %d",ch->prevFreq);
|
ImGui::Text(" - prev: %d",ch->prevFreq);
|
||||||
ImGui::Text("- note: %d",ch->note);
|
ImGui::Text("- note: %d",ch->note);
|
||||||
ImGui::Text("- ins: %d",ch->ins);
|
ImGui::Text("- ins: %d",ch->ins);
|
||||||
|
@ -185,6 +751,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text("* freq: %d",ch->freq);
|
ImGui::Text("* freq: %d",ch->freq);
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||||
ImGui::Text(" - prev: %d",ch->prevFreq);
|
ImGui::Text(" - prev: %d",ch->prevFreq);
|
||||||
ImGui::Text("- testWhen: %d",ch->testWhen);
|
ImGui::Text("- testWhen: %d",ch->testWhen);
|
||||||
ImGui::Text("- note: %d",ch->note);
|
ImGui::Text("- note: %d",ch->note);
|
||||||
|
@ -218,6 +785,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text("* freq: %d",ch->freq);
|
ImGui::Text("* freq: %d",ch->freq);
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||||
ImGui::Text("- note: %d",ch->note);
|
ImGui::Text("- note: %d",ch->note);
|
||||||
ImGui::Text("- ins: %d",ch->ins);
|
ImGui::Text("- ins: %d",ch->ins);
|
||||||
ImGui::Text("- KOnCycles: %d",ch->konCycles);
|
ImGui::Text("- KOnCycles: %d",ch->konCycles);
|
||||||
|
@ -231,8 +799,140 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
ImGui::TextColored(ch->keyOn?colorOn:colorOff,">> KeyOn");
|
||||||
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
ImGui::TextColored(ch->keyOff?colorOn:colorOff,">> KeyOff");
|
||||||
ImGui::TextColored(ch->portaPause?colorOn:colorOff,">> PortaPause");
|
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->furnacePCM?colorOn:colorOff,">> FurnacePCM");
|
||||||
ImGui::TextColored(ch->inPorta?colorOn:colorOff,">> InPorta");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_SYSTEM_X1_010: {
|
case DIV_SYSTEM_X1_010: {
|
||||||
|
@ -241,6 +941,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text("* freq: %.4x",ch->freq);
|
ImGui::Text("* freq: %.4x",ch->freq);
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||||
ImGui::Text("- note: %d",ch->note);
|
ImGui::Text("- note: %d",ch->note);
|
||||||
ImGui::Text("- wave: %d",ch->wave);
|
ImGui::Text("- wave: %d",ch->wave);
|
||||||
ImGui::Text("- sample: %d",ch->sample);
|
ImGui::Text("- sample: %d",ch->sample);
|
||||||
|
@ -254,6 +955,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text(" - autoEnvNum: %.2x",ch->autoEnvNum);
|
ImGui::Text(" - autoEnvNum: %.2x",ch->autoEnvNum);
|
||||||
ImGui::Text(" - autoEnvDen: %.2x",ch->autoEnvDen);
|
ImGui::Text(" - autoEnvDen: %.2x",ch->autoEnvDen);
|
||||||
ImGui::Text("- WaveBank: %d",ch->waveBank);
|
ImGui::Text("- WaveBank: %d",ch->waveBank);
|
||||||
|
ImGui::Text("- bankSlot: %d",ch->bankSlot);
|
||||||
ImGui::Text("- vol: %.2x",ch->vol);
|
ImGui::Text("- vol: %.2x",ch->vol);
|
||||||
ImGui::Text("- outVol: %.2x",ch->outVol);
|
ImGui::Text("- outVol: %.2x",ch->outVol);
|
||||||
ImGui::Text("- Lvol: %.2x",ch->lvol);
|
ImGui::Text("- Lvol: %.2x",ch->lvol);
|
||||||
|
@ -282,6 +984,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text("* freq: %.4x",ch->freq);
|
ImGui::Text("* freq: %.4x",ch->freq);
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||||
ImGui::Text("- note: %d",ch->note);
|
ImGui::Text("- note: %d",ch->note);
|
||||||
ImGui::Text("- wave: %d",ch->wave);
|
ImGui::Text("- wave: %d",ch->wave);
|
||||||
ImGui::Text("- wavepos: %d",ch->wavePos);
|
ImGui::Text("- wavepos: %d",ch->wavePos);
|
||||||
|
@ -312,6 +1015,7 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::Text("* freq: %d",ch->freq);
|
ImGui::Text("* freq: %d",ch->freq);
|
||||||
ImGui::Text(" - base: %d",ch->baseFreq);
|
ImGui::Text(" - base: %d",ch->baseFreq);
|
||||||
ImGui::Text(" - pitch: %d",ch->pitch);
|
ImGui::Text(" - pitch: %d",ch->pitch);
|
||||||
|
ImGui::Text(" - pitch2: %d",ch->pitch2);
|
||||||
ImGui::Text("- note: %d",ch->note);
|
ImGui::Text("- note: %d",ch->note);
|
||||||
ImGui::Text("* DAC:");
|
ImGui::Text("* DAC:");
|
||||||
ImGui::Text(" - period: %d",ch->dacPeriod);
|
ImGui::Text(" - period: %d",ch->dacPeriod);
|
||||||
|
@ -333,6 +1037,71 @@ void putDispatchChan(void* data, int chanNum, int type) {
|
||||||
ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC");
|
ImGui::TextColored(ch->furnaceDac?colorOn:colorOff,">> FurnaceDAC");
|
||||||
break;
|
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:
|
default:
|
||||||
ImGui::Text("Unimplemented chip! Help!");
|
ImGui::Text("Unimplemented chip! Help!");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,5 +21,6 @@
|
||||||
#define _GUI_DEBUG_H
|
#define _GUI_DEBUG_H
|
||||||
#include "../engine/song.h"
|
#include "../engine/song.h"
|
||||||
|
|
||||||
|
void putDispatchChip(void* data, int type);
|
||||||
void putDispatchChan(void* data, int chanNum, int type);
|
void putDispatchChan(void* data, int chanNum, int type);
|
||||||
#endif
|
#endif
|
|
@ -66,6 +66,22 @@ void FurnaceGUI::drawDebug() {
|
||||||
ImGui::Checkbox("Enable",&bpOn);
|
ImGui::Checkbox("Enable",&bpOn);
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
if (ImGui::TreeNode("Chip Status")) {
|
||||||
|
ImGui::Text("for best results set latency to minimum or use the Frame Advance button.");
|
||||||
|
ImGui::Columns(e->song.systemLen);
|
||||||
|
for (int i=0; i<e->song.systemLen; i++) {
|
||||||
|
void* ch=e->getDispatch(i);
|
||||||
|
ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Chip %d: %s",i,getSystemName(e->song.system[i]));
|
||||||
|
if (e->song.system[i]==DIV_SYSTEM_NULL) {
|
||||||
|
ImGui::Text("NULL");
|
||||||
|
} else {
|
||||||
|
putDispatchChip(ch,e->song.system[i]);
|
||||||
|
}
|
||||||
|
ImGui::NextColumn();
|
||||||
|
}
|
||||||
|
ImGui::Columns();
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
if (ImGui::TreeNode("Dispatch Status")) {
|
if (ImGui::TreeNode("Dispatch Status")) {
|
||||||
ImGui::Text("for best results set latency to minimum or use the Frame Advance button.");
|
ImGui::Text("for best results set latency to minimum or use the Frame Advance button.");
|
||||||
ImGui::Columns(e->getTotalChannelCount());
|
ImGui::Columns(e->getTotalChannelCount());
|
||||||
|
@ -157,10 +173,11 @@ void FurnaceGUI::drawDebug() {
|
||||||
ImGui::Text("loopStart: %d",sample->loopStart);
|
ImGui::Text("loopStart: %d",sample->loopStart);
|
||||||
ImGui::Text("loopEnd: %d", sample->loopEnd);
|
ImGui::Text("loopEnd: %d", sample->loopEnd);
|
||||||
ImGui::Text("loopOffP: %d",sample->loopOffP);
|
ImGui::Text("loopOffP: %d",sample->loopOffP);
|
||||||
if (sampleDepths[sample->depth]!=NULL) {
|
ImGui::Text(sample->loop?"loop: Enabled":"loop: Disabled");
|
||||||
ImGui::Text("depth: %d (%s)",(unsigned char)sample->depth,sampleDepths[sample->depth]);
|
if (sampleLoopModes[sample->loopMode]!=NULL) {
|
||||||
|
ImGui::Text("loopMode: %d (%s)",(unsigned char)sample->loopMode,sampleLoopModes[sample->loopMode]);
|
||||||
} else {
|
} else {
|
||||||
ImGui::Text("depth: %d (<NULL!>)",(unsigned char)sample->depth);
|
ImGui::Text("loopMode: %d (<NULL!>)",(unsigned char)sample->loopMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("length8: %d",sample->length8);
|
ImGui::Text("length8: %d",sample->length8);
|
||||||
|
|
|
@ -736,6 +736,8 @@ void FurnaceGUI::doAction(int what) {
|
||||||
sample->name=prevSample->name;
|
sample->name=prevSample->name;
|
||||||
sample->loopStart=prevSample->loopStart;
|
sample->loopStart=prevSample->loopStart;
|
||||||
sample->loopEnd=prevSample->loopEnd;
|
sample->loopEnd=prevSample->loopEnd;
|
||||||
|
sample->loop=prevSample->loop;
|
||||||
|
sample->loopMode=prevSample->loopMode;
|
||||||
sample->depth=prevSample->depth;
|
sample->depth=prevSample->depth;
|
||||||
if (sample->init(prevSample->samples)) {
|
if (sample->init(prevSample->samples)) {
|
||||||
if (prevSample->getCurBuf()!=NULL) {
|
if (prevSample->getCurBuf()!=NULL) {
|
||||||
|
@ -1299,6 +1301,7 @@ void FurnaceGUI::doAction(int what) {
|
||||||
|
|
||||||
sample->loopStart=start;
|
sample->loopStart=start;
|
||||||
sample->loopEnd=end;
|
sample->loopEnd=end;
|
||||||
|
sample->loop=true;
|
||||||
updateSampleTex=true;
|
updateSampleTex=true;
|
||||||
|
|
||||||
e->renderSamples();
|
e->renderSamples();
|
||||||
|
|
|
@ -159,6 +159,16 @@ enum FurnaceGUIColors {
|
||||||
GUI_COLOR_INSTR_SU,
|
GUI_COLOR_INSTR_SU,
|
||||||
GUI_COLOR_INSTR_NAMCO,
|
GUI_COLOR_INSTR_NAMCO,
|
||||||
GUI_COLOR_INSTR_OPL_DRUMS,
|
GUI_COLOR_INSTR_OPL_DRUMS,
|
||||||
|
GUI_COLOR_INSTR_OPM,
|
||||||
|
GUI_COLOR_INSTR_NES,
|
||||||
|
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_INSTR_UNKNOWN,
|
||||||
|
|
||||||
GUI_COLOR_CHANNEL_BG,
|
GUI_COLOR_CHANNEL_BG,
|
||||||
|
|
|
@ -80,11 +80,11 @@ const int vgmVersions[6]={
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* insTypes[DIV_INS_MAX+1]={
|
const char* insTypes[DIV_INS_MAX+1]={
|
||||||
"Standard (SMS/NES)",
|
"SN76489/Sega PSG",
|
||||||
"FM (4-operator)",
|
"FM (OPN)",
|
||||||
"Game Boy",
|
"Game Boy",
|
||||||
"C64",
|
"C64",
|
||||||
"Sample",
|
"Generic Sample",
|
||||||
"PC Engine",
|
"PC Engine",
|
||||||
"AY-3-8910/SSG",
|
"AY-3-8910/SSG",
|
||||||
"AY8930",
|
"AY8930",
|
||||||
|
@ -113,9 +113,25 @@ const char* insTypes[DIV_INS_MAX+1]={
|
||||||
"Sound Unit",
|
"Sound Unit",
|
||||||
"Namco WSG",
|
"Namco WSG",
|
||||||
"OPL (drums)",
|
"OPL (drums)",
|
||||||
|
"FM (OPM)", // 33
|
||||||
|
"NES", // 34
|
||||||
|
"MSM6258",
|
||||||
|
"MSM6295",
|
||||||
|
"ADPCM-A",
|
||||||
|
"ADPCM-B",
|
||||||
|
"SegaPCM",
|
||||||
|
"QSound",
|
||||||
|
"YMZ280B",
|
||||||
|
"RF5C68",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* sampleLoopModes[DIV_SAMPLE_LOOP_MAX]={
|
||||||
|
"Forward",
|
||||||
|
"Backward",
|
||||||
|
"Ping pong"
|
||||||
|
};
|
||||||
|
|
||||||
const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={
|
const char* sampleDepths[DIV_SAMPLE_DEPTH_MAX]={
|
||||||
"1-bit PCM",
|
"1-bit PCM",
|
||||||
"1-bit DPCM",
|
"1-bit DPCM",
|
||||||
|
@ -772,6 +788,16 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
||||||
D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)),
|
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_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_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_OPM,"",ImVec4(0.2f,0.6f,1.0f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_NES,"",ImVec4(0.4f,1.0f,0.3f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_MSM6258,"",ImVec4(1.0f,0.5f,0.7f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_MSM6295,"",ImVec4(1.0f,0.6f,0.9f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_ADPCMA,"",ImVec4(1.0f,1.0f,0.5f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_ADPCMB,"",ImVec4(1.0f,0.75f,0.5f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_SEGAPCM,"",ImVec4(1.0f,0.9f,0.6f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_QSOUND,"",ImVec4(1.0f,0.8f,0.3f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_YMZ280B,"",ImVec4(0.4f,0.5f,1.0f,1.0f)),
|
||||||
|
D(GUI_COLOR_INSTR_RF5C68,"",ImVec4(1.0f,0.3f,0.3f,1.0f)),
|
||||||
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
|
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
|
||||||
|
|
||||||
D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)),
|
D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)),
|
||||||
|
|
|
@ -40,6 +40,7 @@ extern const char* noteNames[180];
|
||||||
extern const char* noteNamesG[180];
|
extern const char* noteNamesG[180];
|
||||||
extern const char* pitchLabel[11];
|
extern const char* pitchLabel[11];
|
||||||
extern const char* insTypes[];
|
extern const char* insTypes[];
|
||||||
|
extern const char* sampleLoopModes[];
|
||||||
extern const char* sampleDepths[];
|
extern const char* sampleDepths[];
|
||||||
extern const char* resampleStrats[];
|
extern const char* resampleStrats[];
|
||||||
extern const char* chipCategoryNames[];
|
extern const char* chipCategoryNames[];
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue