From 8dd9ede0d06f0ad4f5393f2796bc8e91007b361d Mon Sep 17 00:00:00 2001 From: host12prog Date: Wed, 9 Jul 2025 21:57:47 +0700 Subject: [PATCH] add envelope channel to OPN SSG + rel. noise & stereo --- extern/SDL | 2 +- src/engine/dispatchContainer.cpp | 10 ++ src/engine/platform/ay.cpp | 153 +++++++++++++++++++++++------- src/engine/platform/ay.h | 9 +- src/engine/platform/ym2203.cpp | 48 ++++++++-- src/engine/platform/ym2203.h | 5 + src/engine/platform/ym2203ext.cpp | 7 +- src/engine/platform/ym2203ext.h | 1 + src/engine/song.h | 1 + src/engine/sysDef.cpp | 14 +++ src/gui/insEdit.cpp | 2 +- src/gui/presets.cpp | 5 + src/gui/sysConf.cpp | 41 ++++++++ 13 files changed, 252 insertions(+), 46 deletions(-) diff --git a/extern/SDL b/extern/SDL index 6371fd44c..2359383fc 160000 --- a/extern/SDL +++ b/extern/SDL @@ -1 +1 @@ -Subproject commit 6371fd44c8a3cdfb3166b36d4798f5daeca2eeee +Subproject commit 2359383fc187386204c3bb22de89655a494cd128 diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 23cbde76b..addbaede8 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -449,6 +449,16 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do } ((DivPlatformYM2203Ext*)dispatch)->setCSM(1); 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); + break; case DIV_SYSTEM_YM2608: dispatch=new DivPlatformYM2608; if (isRender) { diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 30e0e26d3..bfcb242fe 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -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)); } else { if (stereo) { - int out0=ayBuf[0]+ayBuf[1]+((ayBuf[2]*stereoSep)>>8); - int out1=((ayBuf[0]*stereoSep)>>8)+ayBuf[1]+ayBuf[2]; + int out0=ayBuf[0]+((ayBuf[1]*centerVol+ayBuf[2]*sideVol)>>8); + int out1=((ayBuf[0]*sideVol+ayBuf[1]*centerVol)>>8)+ayBuf[2]; if (lastOut[0]!=out0) { blip_add_delta(bb[0],i,out0-lastOut[0]); lastOut[0]=out0; @@ -388,8 +388,8 @@ void DivPlatformAY8910::acquire_atomic(short** buf, size_t len) { SSG_Clock(&ay_atomic,1); if (stereo) { - buf[0][i]=ay_atomic.o_analog[0]+ay_atomic.o_analog[1]+((ay_atomic.o_analog[2]*stereoSep)>>8); - buf[1][i]=((ay_atomic.o_analog[0]*stereoSep)>>8)+ay_atomic.o_analog[1]+ay_atomic.o_analog[2]; + 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]*sideVol+ay_atomic.o_analog[1]*centerVol)>>8)+ay_atomic.o_analog[2]; } else { buf[0][i]=ay_atomic.o_analog[0]+ay_atomic.o_analog[1]+ay_atomic.o_analog[2]; buf[1][i]=buf[0][i]; @@ -453,6 +453,7 @@ void DivPlatformAY8910::updateOutSel(bool immediate) { } void DivPlatformAY8910::tick(bool sysTick) { + signed char noiseAdd=-1; // PSG for (int i=0; i<3; i++) { chan[i].std.next(); @@ -478,7 +479,13 @@ void DivPlatformAY8910::tick(bool sysTick) { chan[i].freqChanged=true; } 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].nextPSGMode.val&8)) { @@ -547,10 +554,8 @@ void DivPlatformAY8910::tick(bool sysTick) { chan[i].fixedFreq=chan[i].std.ex4.val; chan[i].freqChanged=true; } - if (chan[i].std.ex5.had) { - ayEnvPeriod=chan[i].std.ex5.val; - immWrite(0x0b,ayEnvPeriod); - immWrite(0x0c,ayEnvPeriod>>8); + if (chan[i].std.ex5.had && (!chan[3].active && extendedSsg)) { + ayEnvPeriod=chan[i].std.ex5.val<<8; } if (chan[i].std.ex6.had) { // 0 - disable timer @@ -627,6 +632,9 @@ void DivPlatformAY8910::tick(bool sysTick) { rWrite((i)<<1,chan[i].freq&0xff); 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].keyOff) chan[i].keyOff=false; if (chan[i].freqChanged && chan[i].autoEnvNum>0 && chan[i].autoEnvDen>0) { @@ -638,6 +646,48 @@ 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) { + 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(); if (ayEnvSlide!=0) { @@ -659,6 +709,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++) { if (pendingWrites[i]!=oldWrites[i]) { @@ -760,7 +817,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { 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]) { rWrite(0x08+c.chan,0); } else if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) { @@ -788,7 +845,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { 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]) { rWrite(0x08+c.chan,0); } else { @@ -856,20 +913,23 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (chan[c.chan].active) { chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val; } - if (isMuted[c.chan]) { - rWrite(0x08+c.chan,0); - } else if (chan[c.chan].active) { - if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) { - rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2); - } else { - rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].nextPSGMode.getEnvelope())<<2)); + if (c.chan<3) { + if (isMuted[c.chan]) { + rWrite(0x08+c.chan,0); + } else if (chan[c.chan].active) { + if (intellivision && (chan[c.chan].nextPSGMode.getEnvelope())) { + rWrite(0x08+c.chan,(chan[c.chan].outVol&0xc)<<2); + } else { + rWrite(0x08+c.chan,(chan[c.chan].outVol&15)|((chan[c.chan].nextPSGMode.getEnvelope())<<2)); + } } } } } break; case DIV_CMD_STD_NOISE_FREQ: - rWrite(0x06,31-c.value); + ayNoisePeriod=c.value; + rWrite(0x06,31-ayNoisePeriod); break; case DIV_CMD_AY_ENVELOPE_SET: ayEnvMode=c.value>>4; @@ -891,16 +951,18 @@ int DivPlatformAY8910::dispatch(DivCommand c) { } break; case DIV_CMD_AY_ENVELOPE_LOW: - ayEnvPeriod&=0xff00; - ayEnvPeriod|=c.value; - immWrite(0x0b,ayEnvPeriod); - immWrite(0x0c,ayEnvPeriod>>8); + ayEnvPeriod&=0xff0000; + ayEnvPeriod|=c.value<<8; + ayOldEnvPeriod=ayEnvPeriod>>8; + immWrite(0x0b,ayOldEnvPeriod&0xff); + immWrite(0x0c,ayOldEnvPeriod>>8); break; case DIV_CMD_AY_ENVELOPE_HIGH: - ayEnvPeriod&=0xff; - ayEnvPeriod|=c.value<<8; - immWrite(0x0b,ayEnvPeriod); - immWrite(0x0c,ayEnvPeriod>>8); + ayEnvPeriod&=0xff00; + ayEnvPeriod|=c.value<<16; + ayOldEnvPeriod=ayEnvPeriod>>8; + immWrite(0x0b,ayOldEnvPeriod&0xff); + immWrite(0x0c,ayOldEnvPeriod>>8); break; case DIV_CMD_AY_ENVELOPE_SLIDE: ayEnvSlide=c.value; @@ -985,6 +1047,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { } void DivPlatformAY8910::muteChannel(int ch, bool mute) { + if (ch>=3) return; isMuted[ch]=mute; if (isMuted[ch]) { rWrite(0x08+ch,0); @@ -1000,14 +1063,15 @@ void DivPlatformAY8910::muteChannel(int ch, bool mute) { } void DivPlatformAY8910::forceIns() { - for (int i=0; i<3; i++) { + for (int i=0; i<4; i++) { chan[i].curPSGMode.val&=~8; chan[i].nextPSGMode.val&=~8; chan[i].insChanged=true; chan[i].freqChanged=true; } - immWrite(0x0b,ayEnvPeriod); - immWrite(0x0c,ayEnvPeriod>>8); + ayOldEnvPeriod=ayEnvPeriod>>8; + immWrite(0x0b,ayOldEnvPeriod&0xff); + immWrite(0x0c,ayOldEnvPeriod>>8); immWrite(0x0d,ayEnvMode); } @@ -1029,7 +1093,7 @@ DivSamplePos DivPlatformAY8910::getSamplePos(int ch) { } DivDispatchOscBuffer* DivPlatformAY8910::getOscBuffer(int ch) { - return oscBuf[ch]; + return (ch<3)?oscBuf[ch]:NULL; } int DivPlatformAY8910::mapVelocity(int ch, float vel) { @@ -1061,7 +1125,7 @@ void DivPlatformAY8910::reset() { while (!writes.empty()) writes.pop(); ay->device_reset(); memset(regPool,0,16); - for (int i=0; i<3; i++) { + for (int i=0; i<4; i++) { chan[i]=DivPlatformAY8910::Channel(); chan[i].std.setEngine(parent); chan[i].vol=0x0f; @@ -1082,7 +1146,9 @@ void DivPlatformAY8910::reset() { } sampleBank=0; + ayNoisePeriod=0; ayEnvPeriod=0; + ayOldEnvPeriod=0; ayEnvMode=0; ayEnvSlide=0; ayEnvSlideLow=0; @@ -1114,7 +1180,7 @@ bool DivPlatformAY8910::getLegacyAlwaysSetVolume() { } 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); } } @@ -1250,6 +1316,21 @@ void DivPlatformAY8910::setFlags(const DivConfig& flags) { stereo=flags.getBool("stereo",false); stereoSep=flags.getInt("stereoSep",0)&255; + extendedSsg=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) { @@ -1263,7 +1344,11 @@ int DivPlatformAY8910::init(DivEngine* p, int channels, int sugRate, const DivCo ay=NULL; setFlags(flags); reset(); - return 3; + return extendedSsg?4:3; +} + +void DivPlatformAY8910::setExtended(bool extended) { + extendedSsg=extended; } void DivPlatformAY8910::quit() { diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index b488616d5..7d6b27e14 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -106,7 +106,7 @@ class DivPlatformAY8910: public DivDispatch { konCycles(0), fixedFreq(0) {} }; - Channel chan[3]; + Channel chan[4]; bool isMuted[3]; struct QueuedWrite { unsigned short addr; @@ -123,6 +123,8 @@ class DivPlatformAY8910: public DivDispatch { unsigned char sampleBank; unsigned char stereoSep; + unsigned short sideVol; + unsigned short centerVol; unsigned char selCore; ssg_t ay_atomic; @@ -130,6 +132,8 @@ class DivPlatformAY8910: public DivDispatch { int delay; int lastOut[2]; + bool extendedSsg; + bool extMode; unsigned int extClock; int dacRate; @@ -142,7 +146,9 @@ class DivPlatformAY8910: public DivDispatch { short oldWrites[16]; short pendingWrites[16]; + unsigned char ayNoisePeriod; unsigned char ayEnvMode; + unsigned short ayOldEnvPeriod; unsigned short ayEnvPeriod; short ayEnvSlideLow; short ayEnvSlide; @@ -189,6 +195,7 @@ class DivPlatformAY8910: public DivDispatch { void poke(std::vector& wlist); const char** getRegisterSheet(); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); + void setExtended(bool extended); void quit(); DivPlatformAY8910(bool useExtMode=false, unsigned int eclk=COLOR_NTSC, unsigned char ediv=8, unsigned char ddiv=24): DivDispatch(), diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 33747168d..2d74ab4fc 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -167,6 +167,7 @@ void DivPlatformYM2203::acquire(short** buf, size_t len) { void DivPlatformYM2203::acquire_combo(short** buf, size_t len) { thread_local int os; + thread_local int os1, os2; thread_local short ignored[2]; for (int i=0; i<7; i++) { @@ -233,11 +234,23 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) { // ymfm part fm->generate(&fmout); - 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 (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++) { oscBuf[i]->putSample(h,CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767)); @@ -1241,7 +1254,7 @@ DivMacroInt* DivPlatformYM2203::getChanMacroInt(int ch) { } DivDispatchOscBuffer* DivPlatformYM2203::getOscBuffer(int ch) { - return oscBuf[ch]; + return (ch<(3+2+4+isCSM))?oscBuf[ch]:NULL; } unsigned char* DivPlatformYM2203::getRegisterPool() { @@ -1344,7 +1357,7 @@ void DivPlatformYM2203::reset() { } int DivPlatformYM2203::getOutputCount() { - return 1; + return extendedSSG?2:1; } bool DivPlatformYM2203::keyOffAffectsArp(int ch) { @@ -1423,6 +1436,25 @@ void DivPlatformYM2203::setFlags(const DivConfig& flags) { fbAllOps=flags.getBool("fbAllOps",false); ssgVol=flags.getInt("ssgVol",128); 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)); if (useCombo==2) { rate=chipClock/(fmDivBase*2); } else { @@ -1451,7 +1483,7 @@ int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, const DivCo // YM2149, 2MHz ay=new DivPlatformAY8910(true,chipClock,ayDiv); ay->setCore(0); - ay->init(p,3,sugRate,ayFlags); + ay->init(p,extendedSSG?4:3,sugRate,ayFlags); ay->toggleRegisterDump(true); setFlags(flags); diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 0166d7a85..e88551252 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -55,6 +55,11 @@ class DivPlatformYM2203: public DivPlatformOPN { bool lastS; DivPlatformAY8910* ay; + bool extendedSSG; + bool stereo; + unsigned char stereoSep; + unsigned short sideVol; + unsigned short centerVol; unsigned char sampleBank; bool extMode, noExtMacros; diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index a65210f35..bae6d5fd8 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -739,6 +739,7 @@ DivMacroInt* DivPlatformYM2203Ext::getChanMacroInt(int ch) { } DivDispatchOscBuffer* DivPlatformYM2203Ext::getOscBuffer(int ch) { + if (ch>9) return NULL; if (ch>=6) return oscBuf[ch-3]; if (ch<3) return oscBuf[ch]; return NULL; @@ -791,7 +792,7 @@ int DivPlatformYM2203Ext::init(DivEngine* parent, int channels, int sugRate, con isOpMuted[i]=false; } extSys=true; - + if (extendedSSG) ay->setExtended(1); reset(); 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() { } diff --git a/src/engine/platform/ym2203ext.h b/src/engine/platform/ym2203ext.h index 5588a4c1e..1be28f760 100644 --- a/src/engine/platform/ym2203ext.h +++ b/src/engine/platform/ym2203ext.h @@ -45,6 +45,7 @@ class DivPlatformYM2203Ext: public DivPlatformYM2203 { int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); void quit(); void setCSM(bool isCSM); + void setExtSSG(bool isExtended); ~DivPlatformYM2203Ext(); }; diff --git a/src/engine/song.h b/src/engine/song.h index e13d8b101..0d244f8aa 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -146,6 +146,7 @@ enum DivSystem { DIV_SYSTEM_UPD1771C, DIV_SYSTEM_SID3, DIV_SYSTEM_C64_PCM, + DIV_SYSTEM_YM2203_CSM_ENV, DIV_SYSTEM_MAX }; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index e3971a2c6..10640510c 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1252,6 +1252,20 @@ void DivEngine::registerSystems() { fmExtChEffectHandlerMap ); + sysDefs[DIV_SYSTEM_YM2203_CSM_ENV]=new DivSysDef( + _("Yamaha YM2203 (OPN) CSM + Envelope"), NULL, 0xfe, 0, 11, true, true, 0x151, false, 1U<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)); 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(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 41a29bd32..ca1e1fc85 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -3242,6 +3242,11 @@ void FurnaceGUI::initSystemPresets() { 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( _("Yamaha YM2608 (OPNA)"), { CH(DIV_SYSTEM_YM2608, 1.0f, 0, "") diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 3b6a5d977..be0d16ef0 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -1343,6 +1343,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl } case DIV_SYSTEM_YM2203: case DIV_SYSTEM_YM2203_EXT: + case DIV_SYSTEM_YM2203_CSM_ENV: case DIV_SYSTEM_YM2203_CSM: { int clockSel=flags.getInt("clockSel",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); int ssgVol=flags.getInt("ssgVol",128); 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::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) { e->lockSave([&]() { 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("ssgVol",ssgVol); flags.set("fmVol",fmVol); + flags.set("stereo",stereo); + flags.set("stereoSep",stereoSep); + flags.set("panLaw",panLaw); }); } break;