neo geo: more work
This commit is contained in:
parent
d789ae759e
commit
442180956c
|
@ -55,6 +55,10 @@ enum DivDispatchCmds {
|
|||
DIV_CMD_C64_DUTY_RESET,
|
||||
DIV_CMD_C64_EXTENDED,
|
||||
|
||||
DIV_CMD_AY_ENVELOPE_SET,
|
||||
DIV_CMD_AY_ENVELOPE_LOW,
|
||||
DIV_CMD_AY_ENVELOPE_HIGH,
|
||||
|
||||
DIV_ALWAYS_SET_VOLUME,
|
||||
|
||||
DIV_CMD_MAX
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
#include "ym2610shared.h"
|
||||
|
||||
#define FM_FREQ_BASE 624.0f
|
||||
#define PSG_FREQ_BASE 7576.0f
|
||||
|
||||
static unsigned char konOffs[4]={
|
||||
1, 2, 5, 6
|
||||
};
|
||||
|
@ -15,24 +18,22 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
for (size_t h=start; h<start+len; h++) {
|
||||
os[0]=0; os[1]=0;
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
if (w.addrOrVal) {
|
||||
fm->write(0x1+((w.addr>>8)<<1),w.val);
|
||||
//printf("write: %x = %.2x\n",w.addr,w.val);
|
||||
writes.pop();
|
||||
} else {
|
||||
if (--delay<1) {
|
||||
QueuedWrite& w=writes.front();
|
||||
fm->write(0x0+((w.addr>>8)<<1),w.addr);
|
||||
w.addrOrVal=true;
|
||||
fm->write(0x1+((w.addr>>8)<<1),w.val);
|
||||
writes.pop();
|
||||
delay=4;
|
||||
}
|
||||
}
|
||||
|
||||
fm->generate(&fmout);
|
||||
|
||||
os[0]=fmout.data[0];
|
||||
os[0]=fmout.data[0]+(fmout.data[2]>>1);
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
||||
os[1]=fmout.data[1];
|
||||
os[1]=fmout.data[1]+(fmout.data[2]>>1);
|
||||
if (os[1]<-32768) os[1]=-32768;
|
||||
if (os[1]>32767) os[1]=32767;
|
||||
|
||||
|
@ -42,6 +43,60 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l
|
|||
}
|
||||
|
||||
void DivPlatformYM2610::tick() {
|
||||
// PSG
|
||||
for (int i=4; i<7; i++) {
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.hadVol) {
|
||||
chan[i].outVol=chan[i].std.vol-(15-chan[i].vol);
|
||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
rWrite(0x04+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
|
||||
}
|
||||
if (chan[i].std.hadArp) {
|
||||
if (!chan[i].inPorta) {
|
||||
if (chan[i].std.arpMode) {
|
||||
chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].std.arp)/12.0f)));
|
||||
} else {
|
||||
chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].note+chan[i].std.arp-12)/12.0f)));
|
||||
}
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
} else {
|
||||
if (chan[i].std.arpMode && chan[i].std.finishedArp) {
|
||||
chan[i].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)(chan[i].note)/12.0f)));
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].std.hadWave) {
|
||||
chan[i].psgMode&=4;
|
||||
chan[i].psgMode|=(chan[i].std.wave+1)&3;
|
||||
}
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins);
|
||||
chan[i].freq=(chan[i].baseFreq*(ONE_SEMITONE-chan[i].pitch))/ONE_SEMITONE;
|
||||
if (chan[i].freq>4095) chan[i].freq=4095;
|
||||
if (chan[i].keyOn) {
|
||||
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
|
||||
//rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3));
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
rWrite(0x04+i,0);
|
||||
}
|
||||
rWrite((i-4)<<1,chan[i].freq&0xff);
|
||||
rWrite(1+((i-4)<<1),chan[i].freq>>8);
|
||||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
}
|
||||
|
||||
rWrite(0x07,
|
||||
~((chan[4].psgMode&1)|
|
||||
((chan[5].psgMode&1)<<1)|
|
||||
((chan[6].psgMode&1)<<2)|
|
||||
((chan[4].psgMode&2)<<2)|
|
||||
((chan[5].psgMode&2)<<3)|
|
||||
((chan[6].psgMode&2)<<4)));
|
||||
|
||||
// FM
|
||||
for (int i=0; i<4; i++) {
|
||||
if (i==1 && extMode) continue;
|
||||
|
@ -65,14 +120,13 @@ void DivPlatformYM2610::tick() {
|
|||
int freqt=toFreq(chan[i].freq);
|
||||
writes.emplace(chanOffs[i]+0xa4,freqt>>8);
|
||||
writes.emplace(chanOffs[i]+0xa0,freqt&0xff);
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
writes.emplace(0x28,0xf0|konOffs[i]);
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
||||
// PSG
|
||||
}
|
||||
|
||||
int DivPlatformYM2610::octave(int freq) {
|
||||
|
@ -120,6 +174,17 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
|
||||
if (c.chan>3) { // PSG
|
||||
chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].std.init(ins);
|
||||
rWrite(0x04+c.chan,(chan[c.chan].vol&15)|((chan[c.chan].psgMode&4)<<2));
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
|
@ -148,22 +213,24 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].insChanged=false;
|
||||
|
||||
chan[c.chan].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f));
|
||||
chan[c.chan].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f));
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].active=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan==5) {
|
||||
if (c.chan>6) {
|
||||
dacSample=-1;
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].std.init(NULL);
|
||||
break;
|
||||
case DIV_CMD_VOLUME: {
|
||||
chan[c.chan].vol=c.value;
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
if (c.chan>3) break;
|
||||
for (int i=0; i<4; i++) {
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[i];
|
||||
|
@ -186,6 +253,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.chan>3) break;
|
||||
switch (c.value) {
|
||||
case 0x01:
|
||||
chan[c.chan].pan=1;
|
||||
|
@ -207,7 +275,31 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=644.0f*pow(2.0f,((float)c.value2/12.0f));
|
||||
if (c.chan>3) { // PSG
|
||||
int destFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value2/12.0f)));
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq-=c.value;
|
||||
if (chan[c.chan].baseFreq<=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
int destFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value2/12.0f));
|
||||
int newFreq;
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
|
@ -235,13 +327,6 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
if (return2) return 2;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_MODE: {
|
||||
if (c.chan==5) {
|
||||
dacMode=c.value;
|
||||
rWrite(0x2b,c.value<<7);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
|
@ -249,7 +334,11 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
chan[c.chan].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f));
|
||||
if (c.chan>3) { // PSG
|
||||
chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
|
||||
} else {
|
||||
chan[c.chan].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f));
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
|
@ -258,6 +347,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: {
|
||||
if (c.chan>3) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
|
@ -265,6 +355,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
if (c.chan>3) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
if (isOutput[ins->fm.alg][c.value]) {
|
||||
|
@ -275,6 +366,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.chan>3) break;
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
|
@ -290,6 +382,24 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_AY_ENVELOPE_SET:
|
||||
if (c.chan<4 || c.chan>6) break;
|
||||
rWrite(0x0d,c.value>>4);
|
||||
if (c.value&15) {
|
||||
chan[c.chan].psgMode|=4;
|
||||
} else {
|
||||
chan[c.chan].psgMode&=~4;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_AY_ENVELOPE_LOW:
|
||||
if (c.chan<4 || c.chan>6) break;
|
||||
writes.emplace(0x0b,c.value);
|
||||
writes.emplace(0x0c,0);
|
||||
break;
|
||||
case DIV_CMD_AY_ENVELOPE_HIGH:
|
||||
if (c.chan<4 || c.chan>6) break;
|
||||
writes.emplace(0x0c,c.value);
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 0;
|
||||
break;
|
||||
|
@ -299,6 +409,10 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
return 127;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (c.chan>3) {
|
||||
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
|
||||
chan[c.chan].inPorta=c.value;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_PRE_NOTE:
|
||||
break;
|
||||
|
@ -326,9 +440,15 @@ int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, bool pal) {
|
|||
}
|
||||
fm=new ymfm::ym2610(iface);
|
||||
fm->reset();
|
||||
for (int i=0; i<10; i++) {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i].vol=0x7f;
|
||||
}
|
||||
for (int i=4; i<7; i++) {
|
||||
chan[i].vol=0x0f;
|
||||
}
|
||||
for (int i=7; i<13; i++) {
|
||||
chan[i].vol=0x1f;
|
||||
}
|
||||
|
||||
for (int i=0; i<512; i++) {
|
||||
oldWrites[i]=-1;
|
||||
|
@ -343,6 +463,8 @@ int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, bool pal) {
|
|||
dacSample=-1;
|
||||
sampleBank=0;
|
||||
|
||||
delay=0;
|
||||
|
||||
extMode=false;
|
||||
|
||||
// LFO
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _YM2610_H
|
||||
#define _YM2610_H
|
||||
#include "../dispatch.h"
|
||||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#include "sound/ym2610/ymfm_opn.h"
|
||||
|
||||
|
@ -15,12 +16,13 @@ class DivPlatformYM2610: public DivDispatch {
|
|||
struct Channel {
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch;
|
||||
unsigned char ins;
|
||||
unsigned char ins, note, psgMode;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
|
||||
int vol;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
|
||||
int vol, outVol;
|
||||
unsigned char pan;
|
||||
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {}
|
||||
DivMacroInt std;
|
||||
Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), note(0), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
|
||||
};
|
||||
Channel chan[13];
|
||||
struct QueuedWrite {
|
||||
|
@ -42,6 +44,8 @@ class DivPlatformYM2610: public DivDispatch {
|
|||
int dacSample;
|
||||
int sampleBank;
|
||||
|
||||
int delay;
|
||||
|
||||
bool extMode;
|
||||
|
||||
short oldWrites[512];
|
||||
|
|
|
@ -65,6 +65,10 @@ const char* cmdName[DIV_CMD_MAX]={
|
|||
"C64_DUTY_RESET",
|
||||
"C64_EXTENDED",
|
||||
|
||||
"AY_ENVELOPE_SET",
|
||||
"AY_ENVELOPE_LOW",
|
||||
"AY_ENVELOPE_HIGH",
|
||||
|
||||
"ALWAYS_SET_VOLUME"
|
||||
};
|
||||
|
||||
|
@ -170,6 +174,8 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
case DIV_SYSTEM_GENESIS:
|
||||
case DIV_SYSTEM_GENESIS_EXT:
|
||||
case DIV_SYSTEM_ARCADE:
|
||||
case DIV_SYSTEM_YM2610:
|
||||
case DIV_SYSTEM_YM2610_EXT:
|
||||
switch (effect) {
|
||||
case 0x10: // LFO or noise mode
|
||||
if (song.system==DIV_SYSTEM_ARCADE) {
|
||||
|
@ -225,9 +231,31 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
case 0x1d: // AR op4
|
||||
dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&31));
|
||||
break;
|
||||
case 0x20: // PCM frequency
|
||||
case 0x20: // PCM frequency or Neo Geo PSG mode
|
||||
if (song.system==DIV_SYSTEM_ARCADE) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal));
|
||||
} else if (song.system==DIV_SYSTEM_YM2610 || song.system==DIV_SYSTEM_YM2610_EXT) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
|
||||
}
|
||||
break;
|
||||
case 0x21: // Neo Geo PSG noise freq
|
||||
if (song.system==DIV_SYSTEM_YM2610 || song.system==DIV_SYSTEM_YM2610_EXT) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal));
|
||||
}
|
||||
break;
|
||||
case 0x22: // UNOFFICIAL: Neo Geo PSG envelope enable
|
||||
if (song.system==DIV_SYSTEM_YM2610 || song.system==DIV_SYSTEM_YM2610_EXT) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal));
|
||||
}
|
||||
break;
|
||||
case 0x23: // UNOFFICIAL: Neo Geo PSG envelope period low
|
||||
if (song.system==DIV_SYSTEM_YM2610 || song.system==DIV_SYSTEM_YM2610_EXT) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal));
|
||||
}
|
||||
break;
|
||||
case 0x24: // UNOFFICIAL: Neo Geo PSG envelope period high
|
||||
if (song.system==DIV_SYSTEM_YM2610 || song.system==DIV_SYSTEM_YM2610_EXT) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue