Compare commits
6 commits
kurumitsu-
...
xenium2025
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8ceefbe4e5 | ||
|
a3c33aa31e | ||
|
f2e2d4e0b4 | ||
![]() |
ccd0d676c2 | ||
![]() |
ccfb3d3407 | ||
![]() |
8dd9ede0d0 |
2
extern/SDL
vendored
2
extern/SDL
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 6371fd44c8a3cdfb3166b36d4798f5daeca2eeee
|
Subproject commit 2359383fc187386204c3bb22de89655a494cd128
|
|
@ -449,6 +449,17 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
||||||
}
|
}
|
||||||
((DivPlatformYM2203Ext*)dispatch)->setCSM(1);
|
((DivPlatformYM2203Ext*)dispatch)->setCSM(1);
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_YM2203_CSM_ENV:
|
||||||
|
dispatch = new DivPlatformYM2203Ext;
|
||||||
|
if (isRender) {
|
||||||
|
((DivPlatformYM2203Ext*)dispatch)->setCombo(eng->getConfInt("opn1CoreRender", 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
((DivPlatformYM2203Ext*)dispatch)->setCombo(eng->getConfInt("opn1Core", 1));
|
||||||
|
}
|
||||||
|
((DivPlatformYM2203Ext*)dispatch)->setCSM(1);
|
||||||
|
((DivPlatformYM2203Ext*)dispatch)->setExtSSG(1);
|
||||||
|
break;
|
||||||
case DIV_SYSTEM_YM2608:
|
case DIV_SYSTEM_YM2608:
|
||||||
dispatch=new DivPlatformYM2608;
|
dispatch=new DivPlatformYM2608;
|
||||||
if (isRender) {
|
if (isRender) {
|
||||||
|
|
|
@ -2450,6 +2450,10 @@ int DivEngine::getTotalTicks() {
|
||||||
return totalTicks;
|
return totalTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DivEngine::getTotalTicksR() {
|
||||||
|
return totalTicksR;
|
||||||
|
}
|
||||||
|
|
||||||
bool DivEngine::getRepeatPattern() {
|
bool DivEngine::getRepeatPattern() {
|
||||||
return repeatPattern;
|
return repeatPattern;
|
||||||
}
|
}
|
||||||
|
|
|
@ -994,6 +994,7 @@ class DivEngine {
|
||||||
|
|
||||||
// get time
|
// get time
|
||||||
int getTotalTicks(); // 1/1000000th of a second
|
int getTotalTicks(); // 1/1000000th of a second
|
||||||
|
int getTotalTicksR(); // song ticks
|
||||||
int getTotalSeconds();
|
int getTotalSeconds();
|
||||||
|
|
||||||
// get repeat pattern
|
// get repeat pattern
|
||||||
|
|
|
@ -339,8 +339,8 @@ void DivPlatformAY8910::acquire_mame(blip_buffer_t** bb, size_t len) {
|
||||||
oscBuf[2]->putSample(i,CLAMP(sunsoftVolTable[31-((ay->lastIndx>>10)&31)]<<3,-32768,32767));
|
oscBuf[2]->putSample(i,CLAMP(sunsoftVolTable[31-((ay->lastIndx>>10)&31)]<<3,-32768,32767));
|
||||||
} else {
|
} else {
|
||||||
if (stereo) {
|
if (stereo) {
|
||||||
int out0=ayBuf[0]+ayBuf[1]+((ayBuf[2]*stereoSep)>>8);
|
int out0=ayBuf[0]+((ayBuf[1]*centerVol+ayBuf[2]*sideVol)>>8);
|
||||||
int out1=((ayBuf[0]*stereoSep)>>8)+ayBuf[1]+ayBuf[2];
|
int out1=((ayBuf[0]*sideVol+ayBuf[1]*centerVol)>>8)+ayBuf[2];
|
||||||
if (lastOut[0]!=out0) {
|
if (lastOut[0]!=out0) {
|
||||||
blip_add_delta(bb[0],i,out0-lastOut[0]);
|
blip_add_delta(bb[0],i,out0-lastOut[0]);
|
||||||
lastOut[0]=out0;
|
lastOut[0]=out0;
|
||||||
|
@ -388,8 +388,8 @@ void DivPlatformAY8910::acquire_atomic(short** buf, size_t len) {
|
||||||
SSG_Clock(&ay_atomic,1);
|
SSG_Clock(&ay_atomic,1);
|
||||||
|
|
||||||
if (stereo) {
|
if (stereo) {
|
||||||
buf[0][i]=ay_atomic.o_analog[0]+ay_atomic.o_analog[1]+((ay_atomic.o_analog[2]*stereoSep)>>8);
|
buf[0][i]=ay_atomic.o_analog[0]+((ay_atomic.o_analog[1]*centerVol+ay_atomic.o_analog[2]*sideVol)>>8);
|
||||||
buf[1][i]=((ay_atomic.o_analog[0]*stereoSep)>>8)+ay_atomic.o_analog[1]+ay_atomic.o_analog[2];
|
buf[1][i]=((ay_atomic.o_analog[0]*sideVol+ay_atomic.o_analog[1]*centerVol)>>8)+ay_atomic.o_analog[2];
|
||||||
} else {
|
} else {
|
||||||
buf[0][i]=ay_atomic.o_analog[0]+ay_atomic.o_analog[1]+ay_atomic.o_analog[2];
|
buf[0][i]=ay_atomic.o_analog[0]+ay_atomic.o_analog[1]+ay_atomic.o_analog[2];
|
||||||
buf[1][i]=buf[0][i];
|
buf[1][i]=buf[0][i];
|
||||||
|
@ -453,6 +453,7 @@ void DivPlatformAY8910::updateOutSel(bool immediate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::tick(bool sysTick) {
|
void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
|
signed char noiseAdd=-1;
|
||||||
// PSG
|
// PSG
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
|
@ -478,7 +479,13 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
if (chan[i].std.duty.had) {
|
if (chan[i].std.duty.had) {
|
||||||
rWrite(0x06,31-chan[i].std.duty.val);
|
if (chan[i].std.duty.mode) {
|
||||||
|
noiseAdd=chan[i].std.duty.val;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ayNoisePeriod=chan[i].std.duty.val;
|
||||||
|
noiseAdd=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].std.wave.had) {
|
if (chan[i].std.wave.had) {
|
||||||
if (!(chan[i].nextPSGMode.val&8)) {
|
if (!(chan[i].nextPSGMode.val&8)) {
|
||||||
|
@ -547,10 +554,8 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
chan[i].fixedFreq=chan[i].std.ex4.val;
|
chan[i].fixedFreq=chan[i].std.ex4.val;
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
if (chan[i].std.ex5.had) {
|
if (chan[i].std.ex5.had && (!chan[3].active && extendedSsg)) {
|
||||||
ayEnvPeriod=chan[i].std.ex5.val;
|
ayEnvPeriod=chan[i].std.ex5.val<<8;
|
||||||
immWrite(0x0b,ayEnvPeriod);
|
|
||||||
immWrite(0x0c,ayEnvPeriod>>8);
|
|
||||||
}
|
}
|
||||||
if (chan[i].std.ex6.had) {
|
if (chan[i].std.ex6.had) {
|
||||||
// 0 - disable timer
|
// 0 - disable timer
|
||||||
|
@ -627,6 +632,9 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
rWrite((i)<<1,chan[i].freq&0xff);
|
rWrite((i)<<1,chan[i].freq&0xff);
|
||||||
rWrite(1+((i)<<1),chan[i].freq>>8);
|
rWrite(1+((i)<<1),chan[i].freq>>8);
|
||||||
}
|
}
|
||||||
|
if (chan[i].freqChanged && chan[i].autoEnvNum>0 && chan[i].autoEnvDen>0 && (!chan[3].active && extendedSsg)) {
|
||||||
|
ayEnvPeriod=(chan[i].freq*chan[i].autoEnvDen/chan[i].autoEnvNum)<<4;
|
||||||
|
}
|
||||||
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;
|
||||||
if (chan[i].freqChanged && chan[i].autoEnvNum>0 && chan[i].autoEnvDen>0) {
|
if (chan[i].freqChanged && chan[i].autoEnvNum>0 && chan[i].autoEnvDen>0) {
|
||||||
|
@ -638,6 +646,62 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Envelope
|
||||||
|
chan[3].std.next();
|
||||||
|
if (NEW_ARP_STRAT) {
|
||||||
|
chan[3].handleArp();
|
||||||
|
} else if (chan[3].std.arp.had) {
|
||||||
|
if (!chan[3].inPorta) {
|
||||||
|
int note=parent->calcArp(chan[3].note,chan[3].std.arp.val);
|
||||||
|
chan[3].baseFreq=round(parent->calcBaseFreq(chipClock*16,CHIP_DIVIDER,note,true));
|
||||||
|
}
|
||||||
|
chan[3].freqChanged=true;
|
||||||
|
}
|
||||||
|
if (chan[3].std.pitch.had) {
|
||||||
|
if (chan[3].std.pitch.mode) {
|
||||||
|
chan[3].pitch2+=chan[3].std.pitch.val;
|
||||||
|
CLAMP_VAR(chan[3].pitch2,-32768,32767);
|
||||||
|
} else {
|
||||||
|
chan[3].pitch2=chan[3].std.pitch.val;
|
||||||
|
}
|
||||||
|
chan[3].freqChanged=true;
|
||||||
|
}
|
||||||
|
if (chan[3].std.ex2.had) {
|
||||||
|
ayEnvMode=chan[3].std.ex2.val;
|
||||||
|
rWrite(0x0d,ayEnvMode);
|
||||||
|
}
|
||||||
|
if (chan[3].std.ex5.had && chan[3].active) {
|
||||||
|
ayEnvPeriod=chan[3].std.ex5.val<<8;
|
||||||
|
}
|
||||||
|
else if ((chan[3].freqChanged && chan[3].active) || chan[3].keyOn) {
|
||||||
|
if (envRawMode) {
|
||||||
|
// Compute base without pitch2, then apply pitch2 directly to the raw envelope period
|
||||||
|
int baseFreq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,chan[3].fixedArp?chan[3].baseNoteOverride:chan[3].arpOff,chan[3].fixedArp,true,0,0,chipClock*16,CHIP_DIVIDER);
|
||||||
|
if (baseFreq<0) baseFreq=0;
|
||||||
|
if (baseFreq>65535*256) baseFreq=65535*256;
|
||||||
|
// Apply pitch2 later as raw offset in the same fixed-point scale (8 fractional bits)
|
||||||
|
long adjusted=(long)baseFreq + ((long)chan[3].pitch2<<8);
|
||||||
|
if (adjusted<0) adjusted=0;
|
||||||
|
if (adjusted>(long)65535*256) adjusted=(long)65535*256;
|
||||||
|
chan[3].freq=(int)adjusted;
|
||||||
|
ayEnvPeriod=chan[3].freq;
|
||||||
|
chan[3].freqChanged=false;
|
||||||
|
} else {
|
||||||
|
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,chan[3].fixedArp?chan[3].baseNoteOverride:chan[3].arpOff,chan[3].fixedArp,true,0,chan[3].pitch2,chipClock*16,CHIP_DIVIDER);
|
||||||
|
if (chan[3].freq<0) chan[3].freq=0;
|
||||||
|
if (chan[3].freq>65535*256) chan[3].freq=65535*256;
|
||||||
|
ayEnvPeriod=chan[3].freq;
|
||||||
|
chan[3].freqChanged=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[3].keyOn) chan[3].keyOn=false;
|
||||||
|
if (chan[3].keyOff) chan[3].keyOff=false;
|
||||||
|
|
||||||
|
if (noiseAdd>=0) {
|
||||||
|
ayNoisePeriod=(ayNoisePeriod+noiseAdd)&31;
|
||||||
|
rWrite(0x06,31-ayNoisePeriod);
|
||||||
|
}
|
||||||
|
|
||||||
updateOutSel();
|
updateOutSel();
|
||||||
|
|
||||||
if (ayEnvSlide!=0) {
|
if (ayEnvSlide!=0) {
|
||||||
|
@ -660,6 +724,13 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int newPeriod=ayEnvPeriod>>8;
|
||||||
|
if (newPeriod!=ayOldEnvPeriod) {
|
||||||
|
immWrite(0x0b,newPeriod&0xff);
|
||||||
|
immWrite(0x0c,newPeriod>>8);
|
||||||
|
ayOldEnvPeriod=newPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<16; i++) {
|
||||||
if (pendingWrites[i]!=oldWrites[i]) {
|
if (pendingWrites[i]!=oldWrites[i]) {
|
||||||
immWrite(i,pendingWrites[i]&0xff);
|
immWrite(i,pendingWrites[i]&0xff);
|
||||||
|
@ -760,7 +831,7 @@ 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 (!(chan[c.chan].nextPSGMode.val&8)) {
|
if (c.chan<3 && !(chan[c.chan].nextPSGMode.val&8)) {
|
||||||
if (isMuted[c.chan]) {
|
if (isMuted[c.chan]) {
|
||||||
rWrite(0x08+c.chan,0);
|
rWrite(0x08+c.chan,0);
|
||||||
} else if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) {
|
} else if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) {
|
||||||
|
@ -788,7 +859,7 @@ 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 (!(chan[c.chan].nextPSGMode.val&8)) {
|
if (c.chan<3 && !(chan[c.chan].nextPSGMode.val&8)) {
|
||||||
if (isMuted[c.chan]) {
|
if (isMuted[c.chan]) {
|
||||||
rWrite(0x08+c.chan,0);
|
rWrite(0x08+c.chan,0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -856,20 +927,23 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
if (chan[c.chan].active) {
|
if (chan[c.chan].active) {
|
||||||
chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val;
|
chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val;
|
||||||
}
|
}
|
||||||
if (isMuted[c.chan]) {
|
if (c.chan<3) {
|
||||||
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].nextPSGMode.getEnvelope())) {
|
} else if (chan[c.chan].active) {
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2);
|
if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) {
|
||||||
} else {
|
rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2);
|
||||||
rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].nextPSGMode.getEnvelope())<<2));
|
} else {
|
||||||
|
rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].nextPSGMode.getEnvelope())<<2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_STD_NOISE_FREQ:
|
case DIV_CMD_STD_NOISE_FREQ:
|
||||||
rWrite(0x06,31-c.value);
|
ayNoisePeriod=c.value;
|
||||||
|
rWrite(0x06,31-ayNoisePeriod);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_AY_ENVELOPE_SET:
|
case DIV_CMD_AY_ENVELOPE_SET:
|
||||||
ayEnvMode=c.value>>4;
|
ayEnvMode=c.value>>4;
|
||||||
|
@ -891,16 +965,18 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_AY_ENVELOPE_LOW:
|
case DIV_CMD_AY_ENVELOPE_LOW:
|
||||||
ayEnvPeriod&=0xff00;
|
ayEnvPeriod&=0xff0000;
|
||||||
ayEnvPeriod|=c.value;
|
ayEnvPeriod|=c.value<<8;
|
||||||
immWrite(0x0b,ayEnvPeriod);
|
ayOldEnvPeriod=ayEnvPeriod>>8;
|
||||||
immWrite(0x0c,ayEnvPeriod>>8);
|
immWrite(0x0b,ayOldEnvPeriod&0xff);
|
||||||
|
immWrite(0x0c,ayOldEnvPeriod>>8);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_AY_ENVELOPE_HIGH:
|
case DIV_CMD_AY_ENVELOPE_HIGH:
|
||||||
ayEnvPeriod&=0xff;
|
ayEnvPeriod&=0xff00;
|
||||||
ayEnvPeriod|=c.value<<8;
|
ayEnvPeriod|=c.value<<16;
|
||||||
immWrite(0x0b,ayEnvPeriod);
|
ayOldEnvPeriod=ayEnvPeriod>>8;
|
||||||
immWrite(0x0c,ayEnvPeriod>>8);
|
immWrite(0x0b,ayOldEnvPeriod&0xff);
|
||||||
|
immWrite(0x0c,ayOldEnvPeriod>>8);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_AY_ENVELOPE_SLIDE:
|
case DIV_CMD_AY_ENVELOPE_SLIDE:
|
||||||
ayEnvSlide=c.value;
|
ayEnvSlide=c.value;
|
||||||
|
@ -985,6 +1061,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::muteChannel(int ch, bool mute) {
|
void DivPlatformAY8910::muteChannel(int ch, bool mute) {
|
||||||
|
if (ch>=3) return;
|
||||||
isMuted[ch]=mute;
|
isMuted[ch]=mute;
|
||||||
if (isMuted[ch]) {
|
if (isMuted[ch]) {
|
||||||
rWrite(0x08+ch,0);
|
rWrite(0x08+ch,0);
|
||||||
|
@ -1000,14 +1077,15 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::forceIns() {
|
void DivPlatformAY8910::forceIns() {
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
chan[i].curPSGMode.val&=~8;
|
chan[i].curPSGMode.val&=~8;
|
||||||
chan[i].nextPSGMode.val&=~8;
|
chan[i].nextPSGMode.val&=~8;
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
immWrite(0x0b,ayEnvPeriod);
|
ayOldEnvPeriod=ayEnvPeriod>>8;
|
||||||
immWrite(0x0c,ayEnvPeriod>>8);
|
immWrite(0x0b,ayOldEnvPeriod&0xff);
|
||||||
|
immWrite(0x0c,ayOldEnvPeriod>>8);
|
||||||
immWrite(0x0d,ayEnvMode);
|
immWrite(0x0d,ayEnvMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,7 +1107,7 @@ DivSamplePos DivPlatformAY8910::getSamplePos(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DivDispatchOscBuffer* DivPlatformAY8910::getOscBuffer(int ch) {
|
DivDispatchOscBuffer* DivPlatformAY8910::getOscBuffer(int ch) {
|
||||||
return oscBuf[ch];
|
return (ch<3)?oscBuf[ch]:NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformAY8910::mapVelocity(int ch, float vel) {
|
int DivPlatformAY8910::mapVelocity(int ch, float vel) {
|
||||||
|
@ -1061,7 +1139,7 @@ void DivPlatformAY8910::reset() {
|
||||||
while (!writes.empty()) writes.pop();
|
while (!writes.empty()) writes.pop();
|
||||||
ay->device_reset();
|
ay->device_reset();
|
||||||
memset(regPool,0,16);
|
memset(regPool,0,16);
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
chan[i]=DivPlatformAY8910::Channel();
|
chan[i]=DivPlatformAY8910::Channel();
|
||||||
chan[i].std.setEngine(parent);
|
chan[i].std.setEngine(parent);
|
||||||
chan[i].vol=0x0f;
|
chan[i].vol=0x0f;
|
||||||
|
@ -1082,7 +1160,9 @@ void DivPlatformAY8910::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
|
ayNoisePeriod=0;
|
||||||
ayEnvPeriod=0;
|
ayEnvPeriod=0;
|
||||||
|
ayOldEnvPeriod=0;
|
||||||
ayEnvMode=0;
|
ayEnvMode=0;
|
||||||
ayEnvSlide=0;
|
ayEnvSlide=0;
|
||||||
ayEnvSlideLow=0;
|
ayEnvSlideLow=0;
|
||||||
|
@ -1114,7 +1194,7 @@ bool DivPlatformAY8910::getLegacyAlwaysSetVolume() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::notifyInsDeletion(void* ins) {
|
void DivPlatformAY8910::notifyInsDeletion(void* ins) {
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1250,6 +1330,22 @@ void DivPlatformAY8910::setFlags(const DivConfig& flags) {
|
||||||
|
|
||||||
stereo=flags.getBool("stereo",false);
|
stereo=flags.getBool("stereo",false);
|
||||||
stereoSep=flags.getInt("stereoSep",0)&255;
|
stereoSep=flags.getInt("stereoSep",0)&255;
|
||||||
|
extendedSsg=false;
|
||||||
|
envRawMode=flags.getBool("envRawMode",false);
|
||||||
|
switch (flags.getInt("panLaw",0)) {
|
||||||
|
case 1:
|
||||||
|
centerVol=sqrtf((stereoSep+256)/512.f)*256.f;
|
||||||
|
sideVol=sqrtf(stereoSep/256.f)*256.f;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
centerVol=(stereoSep+256)/2;
|
||||||
|
sideVol=stereoSep;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
centerVol=256;
|
||||||
|
sideVol=stereoSep;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformAY8910::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformAY8910::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||||
|
@ -1263,7 +1359,11 @@ int DivPlatformAY8910::init(DivEngine* p, int channels, int sugRate, const DivCo
|
||||||
ay=NULL;
|
ay=NULL;
|
||||||
setFlags(flags);
|
setFlags(flags);
|
||||||
reset();
|
reset();
|
||||||
return 3;
|
return extendedSsg?4:3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformAY8910::setExtended(bool extended) {
|
||||||
|
extendedSsg=extended;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::quit() {
|
void DivPlatformAY8910::quit() {
|
||||||
|
|
|
@ -106,7 +106,7 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
konCycles(0),
|
konCycles(0),
|
||||||
fixedFreq(0) {}
|
fixedFreq(0) {}
|
||||||
};
|
};
|
||||||
Channel chan[3];
|
Channel chan[4];
|
||||||
bool isMuted[3];
|
bool isMuted[3];
|
||||||
struct QueuedWrite {
|
struct QueuedWrite {
|
||||||
unsigned short addr;
|
unsigned short addr;
|
||||||
|
@ -123,6 +123,8 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
|
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
unsigned char stereoSep;
|
unsigned char stereoSep;
|
||||||
|
unsigned short sideVol;
|
||||||
|
unsigned short centerVol;
|
||||||
unsigned char selCore;
|
unsigned char selCore;
|
||||||
|
|
||||||
ssg_t ay_atomic;
|
ssg_t ay_atomic;
|
||||||
|
@ -130,6 +132,8 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
int delay;
|
int delay;
|
||||||
int lastOut[2];
|
int lastOut[2];
|
||||||
|
|
||||||
|
bool extendedSsg;
|
||||||
|
|
||||||
bool extMode;
|
bool extMode;
|
||||||
unsigned int extClock;
|
unsigned int extClock;
|
||||||
int dacRate;
|
int dacRate;
|
||||||
|
@ -137,13 +141,19 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
unsigned char dacRateDiv;
|
unsigned char dacRateDiv;
|
||||||
|
|
||||||
bool stereo, sunsoft, intellivision, clockSel, yamaha;
|
bool stereo, sunsoft, intellivision, clockSel, yamaha;
|
||||||
|
// When true, the AY "envelope column" uses raw register values instead of
|
||||||
|
// converting linear pitch/note values into envelope frequency. Intended for
|
||||||
|
// embedded AY inside chips like YM2203.
|
||||||
|
bool envRawMode;
|
||||||
bool ioPortA, ioPortB;
|
bool ioPortA, ioPortB;
|
||||||
unsigned char portAVal, portBVal;
|
unsigned char portAVal, portBVal;
|
||||||
|
|
||||||
short oldWrites[16];
|
short oldWrites[16];
|
||||||
short pendingWrites[16];
|
short pendingWrites[16];
|
||||||
|
unsigned char ayNoisePeriod;
|
||||||
unsigned char ayEnvMode;
|
unsigned char ayEnvMode;
|
||||||
unsigned short ayEnvPeriod;
|
unsigned int ayOldEnvPeriod;
|
||||||
|
unsigned int ayEnvPeriod;
|
||||||
short ayEnvSlideLow;
|
short ayEnvSlideLow;
|
||||||
short ayEnvSlide;
|
short ayEnvSlide;
|
||||||
|
|
||||||
|
@ -189,12 +199,14 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
const char** getRegisterSheet();
|
const char** getRegisterSheet();
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
|
void setExtended(bool extended);
|
||||||
void quit();
|
void quit();
|
||||||
DivPlatformAY8910(bool useExtMode=false, unsigned int eclk=COLOR_NTSC, unsigned char ediv=8, unsigned char ddiv=24):
|
DivPlatformAY8910(bool useExtMode=false, unsigned int eclk=COLOR_NTSC, unsigned char ediv=8, unsigned char ddiv=24):
|
||||||
DivDispatch(),
|
DivDispatch(),
|
||||||
extMode(useExtMode),
|
extMode(useExtMode),
|
||||||
extClock(eclk),
|
extClock(eclk),
|
||||||
extDiv(ediv),
|
extDiv(ediv),
|
||||||
dacRateDiv(ddiv) {}
|
dacRateDiv(ddiv),
|
||||||
|
envRawMode(false) {}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -167,6 +167,7 @@ void DivPlatformYM2203::acquire(short** buf, size_t len) {
|
||||||
|
|
||||||
void DivPlatformYM2203::acquire_combo(short** buf, size_t len) {
|
void DivPlatformYM2203::acquire_combo(short** buf, size_t len) {
|
||||||
thread_local int os;
|
thread_local int os;
|
||||||
|
thread_local int os1, os2;
|
||||||
thread_local short ignored[2];
|
thread_local short ignored[2];
|
||||||
|
|
||||||
for (int i=0; i<7; i++) {
|
for (int i=0; i<7; i++) {
|
||||||
|
@ -233,11 +234,23 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) {
|
||||||
// ymfm part
|
// ymfm part
|
||||||
fm->generate(&fmout);
|
fm->generate(&fmout);
|
||||||
|
|
||||||
os+=((fmout.data[1]+fmout.data[2]+fmout.data[3])*ssgVol)>>8;
|
if (stereo) {
|
||||||
if (os<-32768) os=-32768;
|
// so ugly
|
||||||
if (os>32767) os=32767;
|
os1=((fmout.data[1]+((fmout.data[2]*centerVol+fmout.data[3]*sideVol)>>8))*ssgVol)>>8;
|
||||||
|
os2=((((fmout.data[1]*sideVol+fmout.data[2]*centerVol)>>8)+fmout.data[3])*ssgVol)>>8;
|
||||||
buf[0][h]=os;
|
if (os1<-32768) os1=-32768;
|
||||||
|
if (os1>32767) os1=32767;
|
||||||
|
if (os2<-32768) os2=-32768;
|
||||||
|
if (os2>32767) os2=32767;
|
||||||
|
buf[0][h]=os+os1;
|
||||||
|
buf[1][h]=os+os2;
|
||||||
|
} else {
|
||||||
|
os+=((fmout.data[1]+fmout.data[2]+fmout.data[3])*ssgVol)>>8;
|
||||||
|
if (os<-32768) os=-32768;
|
||||||
|
if (os>32767) os=32767;
|
||||||
|
buf[0][h]=os;
|
||||||
|
if (extendedSSG) buf[1][h]=os;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
oscBuf[i]->putSample(h,CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767));
|
oscBuf[i]->putSample(h,CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767));
|
||||||
|
@ -255,6 +268,7 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) {
|
||||||
|
|
||||||
void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) {
|
void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) {
|
||||||
thread_local int os;
|
thread_local int os;
|
||||||
|
thread_local int os1, os2;
|
||||||
|
|
||||||
ymfm::ym2203::fm_engine* fme=fm->debug_fm_engine();
|
ymfm::ym2203::fm_engine* fme=fm->debug_fm_engine();
|
||||||
|
|
||||||
|
@ -297,12 +311,27 @@ void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) {
|
||||||
fm->generate(&fmout);
|
fm->generate(&fmout);
|
||||||
iface.clock(24);
|
iface.clock(24);
|
||||||
|
|
||||||
os=((fmout.data[0]*fmVol)>>8)+(((fmout.data[1]+fmout.data[2]+fmout.data[3])*ssgVol)>>8);
|
os=((fmout.data[0]*fmVol)>>8);
|
||||||
if (os<-32768) os=-32768;
|
if (os<-32768) os=-32768;
|
||||||
if (os>32767) os=32767;
|
if (os>32767) os=32767;
|
||||||
|
|
||||||
buf[0][h]=os;
|
if (stereo) {
|
||||||
|
// so ugly
|
||||||
|
os1=((fmout.data[1]+((fmout.data[2]*centerVol+fmout.data[3]*sideVol)>>8))*ssgVol)>>8;
|
||||||
|
os2=((((fmout.data[1]*sideVol+fmout.data[2]*centerVol)>>8)+fmout.data[3])*ssgVol)>>8;
|
||||||
|
if (os1<-32768) os1=-32768;
|
||||||
|
if (os1>32767) os1=32767;
|
||||||
|
if (os2<-32768) os2=-32768;
|
||||||
|
if (os2>32767) os2=32767;
|
||||||
|
buf[0][h]=os+os1;
|
||||||
|
buf[1][h]=os+os2;
|
||||||
|
} else {
|
||||||
|
os+=((fmout.data[1]+fmout.data[2]+fmout.data[3])*ssgVol)>>8;
|
||||||
|
if (os<-32768) os=-32768;
|
||||||
|
if (os>32767) os=32767;
|
||||||
|
buf[0][h]=os;
|
||||||
|
if (extendedSSG) buf[1][h]=os;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
|
int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
|
||||||
|
@ -480,6 +509,7 @@ void DivPlatformYM2203::acquire_lle(short** buf, size_t len) {
|
||||||
if (outL>32767) outL=32767;
|
if (outL>32767) outL=32767;
|
||||||
|
|
||||||
buf[0][h]=outL;
|
buf[0][h]=outL;
|
||||||
|
if (extendedSSG) buf[1][h]=outL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<7; i++) {
|
for (int i=0; i<7; i++) {
|
||||||
|
@ -1241,7 +1271,7 @@ DivMacroInt* DivPlatformYM2203::getChanMacroInt(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DivDispatchOscBuffer* DivPlatformYM2203::getOscBuffer(int ch) {
|
DivDispatchOscBuffer* DivPlatformYM2203::getOscBuffer(int ch) {
|
||||||
return oscBuf[ch];
|
return (ch<(3+2+4+isCSM))?oscBuf[ch]:NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* DivPlatformYM2203::getRegisterPool() {
|
unsigned char* DivPlatformYM2203::getRegisterPool() {
|
||||||
|
@ -1344,7 +1374,7 @@ void DivPlatformYM2203::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformYM2203::getOutputCount() {
|
int DivPlatformYM2203::getOutputCount() {
|
||||||
return 1;
|
return extendedSSG?2:1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformYM2203::keyOffAffectsArp(int ch) {
|
bool DivPlatformYM2203::keyOffAffectsArp(int ch) {
|
||||||
|
@ -1423,6 +1453,28 @@ void DivPlatformYM2203::setFlags(const DivConfig& flags) {
|
||||||
fbAllOps=flags.getBool("fbAllOps",false);
|
fbAllOps=flags.getBool("fbAllOps",false);
|
||||||
ssgVol=flags.getInt("ssgVol",128);
|
ssgVol=flags.getInt("ssgVol",128);
|
||||||
fmVol=flags.getInt("fmVol",256);
|
fmVol=flags.getInt("fmVol",256);
|
||||||
|
stereo=flags.getBool("stereo",false);
|
||||||
|
stereoSep=flags.getInt("stereoSep",0)&255;
|
||||||
|
switch (flags.getInt("panLaw",0)) {
|
||||||
|
case 1:
|
||||||
|
centerVol=sqrtf((stereoSep+256)/512.f)*256.f;
|
||||||
|
sideVol=sqrtf(stereoSep/256.f)*256.f;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
centerVol=(stereoSep+256)/2;
|
||||||
|
sideVol=stereoSep;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
centerVol=256;
|
||||||
|
sideVol=stereoSep;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ayFlags.set("stereo",stereo);
|
||||||
|
ayFlags.set("stereoSep",stereoSep);
|
||||||
|
ayFlags.set("panLaw",flags.getInt("panLaw",0));
|
||||||
|
// AY inside YM2203 should treat envelope column values as raw register values
|
||||||
|
// rather than linear pitch-derived values.
|
||||||
|
ayFlags.set("envRawMode",true);
|
||||||
if (useCombo==2) {
|
if (useCombo==2) {
|
||||||
rate=chipClock/(fmDivBase*2);
|
rate=chipClock/(fmDivBase*2);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1451,7 +1503,7 @@ int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, const DivCo
|
||||||
// YM2149, 2MHz
|
// YM2149, 2MHz
|
||||||
ay=new DivPlatformAY8910(true,chipClock,ayDiv);
|
ay=new DivPlatformAY8910(true,chipClock,ayDiv);
|
||||||
ay->setCore(0);
|
ay->setCore(0);
|
||||||
ay->init(p,3,sugRate,ayFlags);
|
ay->init(p,extendedSSG?4:3,sugRate,ayFlags);
|
||||||
ay->toggleRegisterDump(true);
|
ay->toggleRegisterDump(true);
|
||||||
setFlags(flags);
|
setFlags(flags);
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,11 @@ class DivPlatformYM2203: public DivPlatformOPN {
|
||||||
bool lastS;
|
bool lastS;
|
||||||
|
|
||||||
DivPlatformAY8910* ay;
|
DivPlatformAY8910* ay;
|
||||||
|
bool extendedSSG;
|
||||||
|
bool stereo;
|
||||||
|
unsigned char stereoSep;
|
||||||
|
unsigned short sideVol;
|
||||||
|
unsigned short centerVol;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
|
|
||||||
bool extMode, noExtMacros;
|
bool extMode, noExtMacros;
|
||||||
|
|
|
@ -739,6 +739,7 @@ DivMacroInt* DivPlatformYM2203Ext::getChanMacroInt(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DivDispatchOscBuffer* DivPlatformYM2203Ext::getOscBuffer(int ch) {
|
DivDispatchOscBuffer* DivPlatformYM2203Ext::getOscBuffer(int ch) {
|
||||||
|
if (ch>9) return NULL;
|
||||||
if (ch>=6) return oscBuf[ch-3];
|
if (ch>=6) return oscBuf[ch-3];
|
||||||
if (ch<3) return oscBuf[ch];
|
if (ch<3) return oscBuf[ch];
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -791,7 +792,7 @@ int DivPlatformYM2203Ext::init(DivEngine* parent, int channels, int sugRate, con
|
||||||
isOpMuted[i]=false;
|
isOpMuted[i]=false;
|
||||||
}
|
}
|
||||||
extSys=true;
|
extSys=true;
|
||||||
|
if (extendedSSG) ay->setExtended(1);
|
||||||
reset();
|
reset();
|
||||||
return 3+2+4+isCSM; // 3xPSG + 2xFM + 4xOP + optional CSM
|
return 3+2+4+isCSM; // 3xPSG + 2xFM + 4xOP + optional CSM
|
||||||
}
|
}
|
||||||
|
@ -809,5 +810,9 @@ void DivPlatformYM2203Ext::setCSM(bool isCSM) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2203Ext::setExtSSG(bool isExtended) {
|
||||||
|
extendedSSG=isExtended;
|
||||||
|
}
|
||||||
|
|
||||||
DivPlatformYM2203Ext::~DivPlatformYM2203Ext() {
|
DivPlatformYM2203Ext::~DivPlatformYM2203Ext() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 {
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
void setCSM(bool isCSM);
|
void setCSM(bool isCSM);
|
||||||
|
void setExtSSG(bool isExtended);
|
||||||
~DivPlatformYM2203Ext();
|
~DivPlatformYM2203Ext();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,7 @@ enum DivSystem {
|
||||||
DIV_SYSTEM_UPD1771C,
|
DIV_SYSTEM_UPD1771C,
|
||||||
DIV_SYSTEM_SID3,
|
DIV_SYSTEM_SID3,
|
||||||
DIV_SYSTEM_C64_PCM,
|
DIV_SYSTEM_C64_PCM,
|
||||||
|
DIV_SYSTEM_YM2203_CSM_ENV,
|
||||||
|
|
||||||
DIV_SYSTEM_MAX
|
DIV_SYSTEM_MAX
|
||||||
};
|
};
|
||||||
|
|
|
@ -1252,6 +1252,20 @@ void DivEngine::registerSystems() {
|
||||||
fmExtChEffectHandlerMap
|
fmExtChEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
sysDefs[DIV_SYSTEM_YM2203_CSM_ENV]=new DivSysDef(
|
||||||
|
_("Yamaha YM2203 (OPN) CSM + Envelope"), NULL, 0xfe, 0, 11, true, true, 0x151, false, 1U<<DIV_SAMPLE_DEPTH_8BIT, 0, 0,
|
||||||
|
_("cost-reduced version of the OPM with a different register layout and no stereo...\n...but it has a built-in AY-3-8910! (actually an YM2149)\nthis one is in Extended Channel mode, which turns the third FM channel into four operators with independent notes/frequencies."
|
||||||
|
"\nthis one includes CSM mode control for special effects on Channel 3."),
|
||||||
|
{_("FM 1"), _("FM 2"), _("FM 3 OP1"), _("FM 3 OP2"), _("FM 3 OP3"), _("FM 3 OP4"), _("CSM Timer"), _("PSG 1"), _("PSG 2"), _("PSG 3"), _("Envelope")},
|
||||||
|
{"F1", "F2", "O1", "O2", "O3", "O4", "CSM", "S1", "S2", "S3", "ENV"},
|
||||||
|
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE},
|
||||||
|
{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_AY},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
fmOPNPostEffectHandlerMap,
|
||||||
|
fmExtChEffectHandlerMap
|
||||||
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_YM2608]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_YM2608]=new DivSysDef(
|
||||||
_("Yamaha YM2608 (OPNA)"), NULL, 0x8e, 0, 16, true, true, 0x151, false, (1U<<DIV_SAMPLE_DEPTH_ADPCM_B)|(1U<<DIV_SAMPLE_DEPTH_8BIT), 0, 0,
|
_("Yamaha YM2608 (OPNA)"), NULL, 0x8e, 0, 16, true, true, 0x151, false, (1U<<DIV_SAMPLE_DEPTH_ADPCM_B)|(1U<<DIV_SAMPLE_DEPTH_8BIT), 0, 0,
|
||||||
_("OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels."),
|
_("OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels."),
|
||||||
|
|
|
@ -267,6 +267,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
case DIV_SYSTEM_YM2203:
|
case DIV_SYSTEM_YM2203:
|
||||||
case DIV_SYSTEM_YM2203_EXT:
|
case DIV_SYSTEM_YM2203_EXT:
|
||||||
case DIV_SYSTEM_YM2203_CSM:
|
case DIV_SYSTEM_YM2203_CSM:
|
||||||
|
case DIV_SYSTEM_YM2203_CSM_ENV:
|
||||||
for (int i=0; i<3; i++) { // set SL and RR to highest
|
for (int i=0; i<3; i++) { // set SL and RR to highest
|
||||||
w->writeC(5|baseAddr1);
|
w->writeC(5|baseAddr1);
|
||||||
w->writeC(0x80+i);
|
w->writeC(0x80+i);
|
||||||
|
@ -998,6 +999,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
case DIV_SYSTEM_YM2203:
|
case DIV_SYSTEM_YM2203:
|
||||||
case DIV_SYSTEM_YM2203_EXT:
|
case DIV_SYSTEM_YM2203_EXT:
|
||||||
case DIV_SYSTEM_YM2203_CSM:
|
case DIV_SYSTEM_YM2203_CSM:
|
||||||
|
case DIV_SYSTEM_YM2203_CSM_ENV:
|
||||||
w->writeC(5|baseAddr1);
|
w->writeC(5|baseAddr1);
|
||||||
w->writeC(write.addr&0xff);
|
w->writeC(write.addr&0xff);
|
||||||
w->writeC(write.val);
|
w->writeC(write.val);
|
||||||
|
@ -1637,6 +1639,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
case DIV_SYSTEM_YM2203:
|
case DIV_SYSTEM_YM2203:
|
||||||
case DIV_SYSTEM_YM2203_EXT:
|
case DIV_SYSTEM_YM2203_EXT:
|
||||||
case DIV_SYSTEM_YM2203_CSM:
|
case DIV_SYSTEM_YM2203_CSM:
|
||||||
|
case DIV_SYSTEM_YM2203_CSM_ENV:
|
||||||
if (!hasOPN) {
|
if (!hasOPN) {
|
||||||
hasOPN=disCont[i].dispatch->chipClock;
|
hasOPN=disCont[i].dispatch->chipClock;
|
||||||
willExport[i]=true;
|
willExport[i]=true;
|
||||||
|
|
|
@ -4758,6 +4758,7 @@ bool FurnaceGUI::loop() {
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PLAYBACK_STAT]);
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PLAYBACK_STAT]);
|
||||||
if (e->isPlaying() && settings.playbackTime) {
|
if (e->isPlaying() && settings.playbackTime) {
|
||||||
int totalTicks=e->getTotalTicks();
|
int totalTicks=e->getTotalTicks();
|
||||||
|
int totalTicksR=e->getTotalTicksR();
|
||||||
int totalSeconds=e->getTotalSeconds();
|
int totalSeconds=e->getTotalSeconds();
|
||||||
|
|
||||||
String info;
|
String info;
|
||||||
|
@ -4785,6 +4786,8 @@ bool FurnaceGUI::loop() {
|
||||||
info+=fmt::sprintf(_("| Row %d/%d "),oldRow,e->curSubSong->patLen);
|
info+=fmt::sprintf(_("| Row %d/%d "),oldRow,e->curSubSong->patLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info+=fmt::sprintf(_("| Tick %d "),totalTicksR);
|
||||||
|
|
||||||
info+=_("| ");
|
info+=_("| ");
|
||||||
|
|
||||||
if (totalSeconds==0x7fffffff) {
|
if (totalSeconds==0x7fffffff) {
|
||||||
|
|
|
@ -8083,7 +8083,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,15,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
|
||||||
if (!ins->amiga.useSample) {
|
if (!ins->amiga.useSample) {
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Noise Freq"),&ins->std.dutyMacro,0,31,160,uiColors[GUI_COLOR_MACRO_NOISE]));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Noise Freq"),&ins->std.dutyMacro,0,31,160,uiColors[GUI_COLOR_MACRO_NOISE],true,macroRelativeMode));
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,ayShapeBits));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,3,48,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,ayShapeBits));
|
||||||
}
|
}
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
|
||||||
|
|
|
@ -3242,6 +3242,11 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
CH(DIV_SYSTEM_YM2203_CSM, 1.0f, 0, "clockSel=3")
|
CH(DIV_SYSTEM_YM2203_CSM, 1.0f, 0, "clockSel=3")
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
SUB_ENTRY(
|
||||||
|
_("Yamaha YM2203 (CSM) with Envelope"), {
|
||||||
|
CH(DIV_SYSTEM_YM2203_CSM_ENV, 1.0f, 0, "clockSel=3")
|
||||||
|
}
|
||||||
|
);
|
||||||
ENTRY(
|
ENTRY(
|
||||||
_("Yamaha YM2608 (OPNA)"), {
|
_("Yamaha YM2608 (OPNA)"), {
|
||||||
CH(DIV_SYSTEM_YM2608, 1.0f, 0, "")
|
CH(DIV_SYSTEM_YM2608, 1.0f, 0, "")
|
||||||
|
|
|
@ -1343,6 +1343,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
||||||
}
|
}
|
||||||
case DIV_SYSTEM_YM2203:
|
case DIV_SYSTEM_YM2203:
|
||||||
case DIV_SYSTEM_YM2203_EXT:
|
case DIV_SYSTEM_YM2203_EXT:
|
||||||
|
case DIV_SYSTEM_YM2203_CSM_ENV:
|
||||||
case DIV_SYSTEM_YM2203_CSM: {
|
case DIV_SYSTEM_YM2203_CSM: {
|
||||||
int clockSel=flags.getInt("clockSel",0);
|
int clockSel=flags.getInt("clockSel",0);
|
||||||
int prescale=flags.getInt("prescale",0);
|
int prescale=flags.getInt("prescale",0);
|
||||||
|
@ -1350,6 +1351,10 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
||||||
bool fbAllOps=flags.getBool("fbAllOps",false);
|
bool fbAllOps=flags.getBool("fbAllOps",false);
|
||||||
int ssgVol=flags.getInt("ssgVol",128);
|
int ssgVol=flags.getInt("ssgVol",128);
|
||||||
int fmVol=flags.getInt("fmVol",256);
|
int fmVol=flags.getInt("fmVol",256);
|
||||||
|
// these are for the SSG part
|
||||||
|
int panLaw=flags.getInt("panLaw",0);
|
||||||
|
bool stereo=flags.getBool("stereo",false);
|
||||||
|
int stereoSep=flags.getInt("stereoSep",0);
|
||||||
|
|
||||||
ImGui::Text(_("Clock rate:"));
|
ImGui::Text(_("Clock rate:"));
|
||||||
ImGui::Indent();
|
ImGui::Indent();
|
||||||
|
@ -1415,6 +1420,39 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type==DIV_SYSTEM_YM2203_CSM_ENV) {
|
||||||
|
if (ImGui::Checkbox(_("Stereo##_AY_STEREO"),&stereo)) {
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (stereo) {
|
||||||
|
int sep=256-(stereoSep&255);
|
||||||
|
if (CWSliderInt(_("Separation"),&sep,1,256)) {
|
||||||
|
if (sep<1) sep=1;
|
||||||
|
if (sep>256) sep=256;
|
||||||
|
stereoSep=256-sep;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
ImGui::Text(_("Center level:"));
|
||||||
|
ImGui::Indent();
|
||||||
|
if (ImGui::RadioButton(_("-0 dB (VGMPlay)"),panLaw==0)) {
|
||||||
|
panLaw=0;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton(_("-3 dB"),panLaw==1)) {
|
||||||
|
panLaw=1;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton(_("-6 dB (most hardwares)"),panLaw==2)) {
|
||||||
|
panLaw=2;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
ImGui::Unindent();
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip(_("note: not supported by the VGM format!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (altered) {
|
if (altered) {
|
||||||
e->lockSave([&]() {
|
e->lockSave([&]() {
|
||||||
flags.set("clockSel",clockSel);
|
flags.set("clockSel",clockSel);
|
||||||
|
@ -1423,6 +1461,9 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
||||||
flags.set("fbAllOps",fbAllOps);
|
flags.set("fbAllOps",fbAllOps);
|
||||||
flags.set("ssgVol",ssgVol);
|
flags.set("ssgVol",ssgVol);
|
||||||
flags.set("fmVol",fmVol);
|
flags.set("fmVol",fmVol);
|
||||||
|
flags.set("stereo",stereo);
|
||||||
|
flags.set("stereoSep",stereoSep);
|
||||||
|
flags.set("panLaw",panLaw);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue