mirror of
https://github.com/tildearrow/furnace.git
synced 2025-01-05 07:01:21 +00:00
Merge pull request #275 from cam900/ym2610_check
Make some pitch command work in ADPCM-B, still partially and 01xx command is broken
This commit is contained in:
commit
0ee16c63f1
4 changed files with 92 additions and 70 deletions
|
@ -313,11 +313,22 @@ const char* DivPlatformYM2610::getEffectName(unsigned char effect) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double DivPlatformYM2610::NOTE_OPNB(int ch, int note) {
|
||||||
|
if (ch>6) { // ADPCM
|
||||||
|
return NOTE_ADPCMB(note);
|
||||||
|
} else if (ch>3) { // PSG
|
||||||
|
return NOTE_PERIODIC(note);
|
||||||
|
}
|
||||||
|
// FM
|
||||||
|
return NOTE_FREQUENCY(note);
|
||||||
|
}
|
||||||
|
|
||||||
double DivPlatformYM2610::NOTE_ADPCMB(int note) {
|
double DivPlatformYM2610::NOTE_ADPCMB(int note) {
|
||||||
DivInstrument* ins=parent->getIns(chan[13].ins);
|
if (chan[13].sample>=0 && chan[13].sample<parent->song.sampleLen) {
|
||||||
if (ins->type!=DIV_INS_AMIGA) return 0;
|
double off=(double)(parent->getSample(chan[13].sample)->centerRate)/8363.0;
|
||||||
double off=(double)(parent->getSample(ins->amiga.initSample)->centerRate)/8363.0;
|
return off*parent->calcBaseFreq((double)chipClock/144,65535,note,false);
|
||||||
return off*parent->calcBaseFreq((double)chipClock/144,65535,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) {
|
||||||
|
@ -691,22 +702,33 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
immWrite(0x1b,chan[c.chan].outVol);
|
immWrite(0x1b,chan[c.chan].outVol);
|
||||||
}
|
}
|
||||||
DivSample* s=parent->getSample(ins->amiga.initSample);
|
chan[c.chan].sample=ins->amiga.initSample;
|
||||||
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(chan[c.chan].sample);
|
||||||
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->loopStart>=0)?0x90:0x80); // start/repeat
|
immWrite(0x15,end>>16);
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||||
chan[c.chan].note=c.value;
|
immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat
|
||||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].freqChanged=true;
|
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 {
|
||||||
|
immWrite(0x10,0x01); // reset
|
||||||
|
immWrite(0x12,0);
|
||||||
|
immWrite(0x13,0);
|
||||||
|
immWrite(0x14,0);
|
||||||
|
immWrite(0x15,0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
chan[c.chan].active=true;
|
|
||||||
chan[c.chan].keyOn=true;
|
|
||||||
} else {
|
} else {
|
||||||
|
chan[c.chan].sample=-1;
|
||||||
chan[c.chan].std.init(NULL);
|
chan[c.chan].std.init(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) {
|
||||||
|
@ -915,8 +937,8 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
case DIV_CMD_NOTE_PORTA: {
|
||||||
if (c.chan>3) { // PSG
|
if (c.chan>3) { // PSG, ADPCM-B
|
||||||
int destFreq=NOTE_PERIODIC(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) {
|
||||||
chan[c.chan].baseFreq+=c.value;
|
chan[c.chan].baseFreq+=c.value;
|
||||||
|
@ -975,11 +997,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>3) { // PSG
|
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
|
||||||
} else {
|
|
||||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
|
||||||
}
|
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1210,11 +1228,6 @@ void DivPlatformYM2610::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBusy=60;
|
lastBusy=60;
|
||||||
dacMode=0;
|
|
||||||
dacPeriod=0;
|
|
||||||
dacPos=0;
|
|
||||||
dacRate=0;
|
|
||||||
dacSample=-1;
|
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
ayEnvPeriod=0;
|
ayEnvPeriod=0;
|
||||||
ayEnvMode=0;
|
ayEnvMode=0;
|
||||||
|
|
|
@ -47,6 +47,7 @@ class DivPlatformYM2610: public DivDispatch {
|
||||||
signed char konCycles;
|
signed char konCycles;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM;
|
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
|
int sample;
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
Channel():
|
Channel():
|
||||||
|
@ -70,6 +71,7 @@ class DivPlatformYM2610: public DivDispatch {
|
||||||
furnacePCM(false),
|
furnacePCM(false),
|
||||||
vol(0),
|
vol(0),
|
||||||
outVol(15),
|
outVol(15),
|
||||||
|
sample(-1),
|
||||||
pan(3) {}
|
pan(3) {}
|
||||||
};
|
};
|
||||||
Channel chan[14];
|
Channel chan[14];
|
||||||
|
@ -87,11 +89,6 @@ class DivPlatformYM2610: public DivDispatch {
|
||||||
unsigned char regPool[512];
|
unsigned char regPool[512];
|
||||||
unsigned char lastBusy;
|
unsigned char lastBusy;
|
||||||
|
|
||||||
bool dacMode;
|
|
||||||
int dacPeriod;
|
|
||||||
int dacRate;
|
|
||||||
int dacPos;
|
|
||||||
int dacSample;
|
|
||||||
int ayNoiseFreq;
|
int ayNoiseFreq;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
|
|
||||||
|
@ -108,6 +105,7 @@ class DivPlatformYM2610: public DivDispatch {
|
||||||
|
|
||||||
int octave(int freq);
|
int octave(int freq);
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
|
double NOTE_OPNB(int ch, int note);
|
||||||
double NOTE_ADPCMB(int note);
|
double NOTE_ADPCMB(int note);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
|
|
|
@ -377,11 +377,22 @@ const char* DivPlatformYM2610B::getEffectName(unsigned char effect) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double DivPlatformYM2610B::NOTE_OPNB(int ch, int note) {
|
||||||
|
if (ch>8) { // ADPCM-B
|
||||||
|
return NOTE_ADPCMB(note);
|
||||||
|
} else if (ch>5) { // PSG
|
||||||
|
return NOTE_PERIODIC(note);
|
||||||
|
}
|
||||||
|
// FM
|
||||||
|
return NOTE_FREQUENCY(note);
|
||||||
|
}
|
||||||
|
|
||||||
double DivPlatformYM2610B::NOTE_ADPCMB(int note) {
|
double DivPlatformYM2610B::NOTE_ADPCMB(int note) {
|
||||||
DivInstrument* ins=parent->getIns(chan[15].ins);
|
if (chan[15].sample>=0 && chan[15].sample<parent->song.sampleLen) {
|
||||||
if (ins->type!=DIV_INS_AMIGA) return 0;
|
double off=(double)(parent->getSample(chan[15].sample)->centerRate)/8363.0;
|
||||||
double off=(double)(parent->getSample(ins->amiga.initSample)->centerRate)/8363.0;
|
return off*parent->calcBaseFreq((double)chipClock/144,65535,note,false);
|
||||||
return off*parent->calcBaseFreq((double)chipClock/144,65535,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) {
|
||||||
|
@ -754,22 +765,33 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
chan[c.chan].outVol=chan[c.chan].vol;
|
chan[c.chan].outVol=chan[c.chan].vol;
|
||||||
immWrite(0x1b,chan[c.chan].outVol);
|
immWrite(0x1b,chan[c.chan].outVol);
|
||||||
}
|
}
|
||||||
DivSample* s=parent->getSample(ins->amiga.initSample);
|
chan[c.chan].sample=ins->amiga.initSample;
|
||||||
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(chan[c.chan].sample);
|
||||||
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->loopStart>=0)?0x90:0x80); // start/repeat
|
immWrite(0x15,end>>16);
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||||
chan[c.chan].note=c.value;
|
immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat
|
||||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].freqChanged=true;
|
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 {
|
||||||
|
immWrite(0x10,0x01); // reset
|
||||||
|
immWrite(0x12,0);
|
||||||
|
immWrite(0x13,0);
|
||||||
|
immWrite(0x14,0);
|
||||||
|
immWrite(0x15,0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
chan[c.chan].active=true;
|
|
||||||
chan[c.chan].keyOn=true;
|
|
||||||
} else {
|
} else {
|
||||||
|
chan[c.chan].sample=-1;
|
||||||
chan[c.chan].std.init(NULL);
|
chan[c.chan].std.init(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) {
|
||||||
|
@ -978,8 +1000,8 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
case DIV_CMD_NOTE_PORTA: {
|
||||||
if (c.chan>5) { // PSG
|
if (c.chan>5) { // PSG, ADPCM-B
|
||||||
int destFreq=NOTE_PERIODIC(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) {
|
||||||
chan[c.chan].baseFreq+=c.value;
|
chan[c.chan].baseFreq+=c.value;
|
||||||
|
@ -1038,11 +1060,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>5) { // PSG
|
chan[c.chan].baseFreq=NOTE_OPNB(c.chan,c.value);
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
|
||||||
} else {
|
|
||||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
|
||||||
}
|
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1273,11 +1291,6 @@ void DivPlatformYM2610B::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBusy=60;
|
lastBusy=60;
|
||||||
dacMode=0;
|
|
||||||
dacPeriod=0;
|
|
||||||
dacPos=0;
|
|
||||||
dacRate=0;
|
|
||||||
dacSample=-1;
|
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
ayEnvPeriod=0;
|
ayEnvPeriod=0;
|
||||||
ayEnvMode=0;
|
ayEnvMode=0;
|
||||||
|
|
|
@ -40,6 +40,7 @@ class DivPlatformYM2610B: public DivDispatch {
|
||||||
signed char konCycles;
|
signed char konCycles;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM;
|
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
|
int sample;
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
DivMacroInt std;
|
DivMacroInt std;
|
||||||
Channel():
|
Channel():
|
||||||
|
@ -63,6 +64,7 @@ class DivPlatformYM2610B: public DivDispatch {
|
||||||
furnacePCM(false),
|
furnacePCM(false),
|
||||||
vol(0),
|
vol(0),
|
||||||
outVol(15),
|
outVol(15),
|
||||||
|
sample(-1),
|
||||||
pan(3) {}
|
pan(3) {}
|
||||||
};
|
};
|
||||||
Channel chan[16];
|
Channel chan[16];
|
||||||
|
@ -80,11 +82,6 @@ class DivPlatformYM2610B: public DivDispatch {
|
||||||
unsigned char regPool[512];
|
unsigned char regPool[512];
|
||||||
unsigned char lastBusy;
|
unsigned char lastBusy;
|
||||||
|
|
||||||
bool dacMode;
|
|
||||||
int dacPeriod;
|
|
||||||
int dacRate;
|
|
||||||
int dacPos;
|
|
||||||
int dacSample;
|
|
||||||
int ayNoiseFreq;
|
int ayNoiseFreq;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
|
|
||||||
|
@ -101,6 +98,7 @@ class DivPlatformYM2610B: public DivDispatch {
|
||||||
|
|
||||||
int octave(int freq);
|
int octave(int freq);
|
||||||
int toFreq(int freq);
|
int toFreq(int freq);
|
||||||
|
double NOTE_OPNB(int ch, int note);
|
||||||
double NOTE_ADPCMB(int note);
|
double NOTE_ADPCMB(int note);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue