AY/YM Timer FX bug fixes and improvements

pull request #2547
manual merge due to modification of unrelated files according to GitHub's
files view

Co-authored-by: host12prog <hungnguyen.481335@gmail.com>
This commit is contained in:
tildearrow 2025-10-04 18:39:07 -05:00
parent 80a92b8b43
commit dc87bc489f
2 changed files with 54 additions and 37 deletions

View file

@ -166,17 +166,8 @@ void DivPlatformAY8910::runTFX(int runRate, int advance) {
if (runRate!=0) counterRatio=(double)rate/(double)runRate;
int timerPeriod, output;
for (int i=0; i<3; i++) {
if (chan[i].active && (chan[i].curPSGMode.val&16) && !(chan[i].curPSGMode.val&8) && chan[i].tfx.mode!=-1) {
if (chan[i].active && (chan[i].curPSGMode.val&16) && !(chan[i].curPSGMode.val&8)) {
if (chan[i].tfx.mode == -1 && !isMuted[i]) {
/*
bug: if in the timer FX macro the user enables
and then disables PWM while there is no volume macro
there is now a random chance that the resulting output
is silent or has volume set incorrectly
i've tried to implement a fix, but it seems to be
ineffective, so...
TODO: actually implement a proper fix
*/
if (intellivision && chan[i].curPSGMode.getEnvelope()) {
immWrite(0x08+i,(chan[i].outVol&0xc)<<2);
continue;
@ -186,12 +177,40 @@ void DivPlatformAY8910::runTFX(int runRate, int advance) {
}
}
chan[i].tfx.counter += counterRatio;
if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 0) {
if (chan[i].tfx.counter >= chan[i].tfx.period) {
chan[i].tfx.counter -= chan[i].tfx.period;
chan[i].tfx.out ^= 1;
switch (chan[i].tfx.mode) {
case 0:
// pwm
// we will handle the modulator gen after this switch... if we don't, crackling happens
chan[i].tfx.out ^= 1;
break;
case 1:
// syncbuzzer
if (!isMuted[i]) {
if (intellivision && chan[i].curPSGMode.getEnvelope()) {
immWrite(0x08 + i, (chan[i].outVol & 0xc) << 2);
}
else {
immWrite(0x08 + i, (chan[i].outVol & 15) | ((chan[i].curPSGMode.getEnvelope()) << 2));
}
}
if (intellivision && selCore) {
immWrite(0xa, ayEnvMode);
}
else {
immWrite(0xd, ayEnvMode);
}
break;
case 2:
default:
// unimplemented, or invalid effects here
break;
}
}
if (chan[i].tfx.mode == 0) {
// pwm
output = ((chan[i].tfx.out) ? chan[i].outVol : (chan[i].tfx.lowBound-(15-chan[i].outVol)));
// TODO: fix this stupid crackling noise that happens
// everytime the volume changes
output = (output <= 0) ? 0 : output; // underflow
output = (output >= 15) ? 15 : output; // overflow
output &= 15; // i don't know if i need this but i'm too scared to remove it
@ -204,20 +223,6 @@ void DivPlatformAY8910::runTFX(int runRate, int advance) {
}
}
}
if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 1) {
chan[i].tfx.counter -= chan[i].tfx.period;
if (!isMuted[i]) {
// TODO: ???????
if (intellivision && selCore) {
immWrite(0xa, ayEnvMode);
} else {
immWrite(0xd, ayEnvMode);
}
}
}
if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 2) {
chan[i].tfx.counter -= chan[i].tfx.period;
}
}
if (chan[i].tfx.num > 0) {
timerPeriod = chan[i].freq*chan[i].tfx.den/chan[i].tfx.num;

View file

@ -838,6 +838,22 @@ String macroSoundUnitWaves(int id, float val, void* u) {
return fmt::sprintf("%d: %s",id,label);
}
String macroTFXModes(int id, float val, void* u) {
switch (((int)val)&3) {
case 0:
return _("Disabled");
case 1:
return _("PWM");
case 2:
return _("SyncBuzzer");
case 3:
return _("Reserved");
default:
return "???";
}
return "???";
}
String macroSID3SpecialWaves(int id, float val, void* u) {
if ((int)val<0 || (int)val>=SID3_NUM_SPECIAL_WAVES) return "???";
@ -2099,12 +2115,12 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
}
}
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
if (MACRO_VZOOM<1) {
if (i.macro->macroType==DIV_MACRO_ARP || i.isArp) {
MACRO_VZOOM=24;
MACRO_VSCROLL=120-12;
} else if (i.macro->macroType==DIV_MACRO_PITCH || i.isPitch) {
}
else if ((i.macro->macroType == DIV_MACRO_PITCH || i.isPitch) || (i.macro->macroType == DIV_MACRO_EX7 && i.isPitch)) {
MACRO_VZOOM=128;
MACRO_VSCROLL=2048-64;
} else {
@ -8762,16 +8778,12 @@ void FurnaceGUI::drawInsEdit() {
{
if (ImGui::BeginTabItem(_("Timer Macros")))
{
ImGui::Text(_("warning: timer effects are not supported by VGM export!"));
macroList.push_back(FurnaceGUIMacroDesc(_("Timer FX"),&ins->std.ex6Macro,0,3,64,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("TFX Offset"),&ins->std.ex7Macro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true));
ImGui::Text(_("warning: timer effects require direct stream mode to be enabled during VGM export!"));
macroList.push_back(FurnaceGUIMacroDesc(_("Timer FX"),&ins->std.ex6Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroTFXModes));
macroList.push_back(FurnaceGUIMacroDesc(_("Timer Offset"),&ins->std.ex7Macro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true));
macroList.push_back(FurnaceGUIMacroDesc(_("Timer Num"),&ins->std.ex8Macro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("Timer Den"),&ins->std.fmsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("PWM Boundary"),&ins->std.amsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
// workaround, because the gui will not set
// zoom or scroll if we're not in macros tab
ins->temp.vZoom[DIV_MACRO_EX7]=128;
ins->temp.vScroll[DIV_MACRO_EX7]=2048-64;
drawMacros(macroList,macroEditStateMacros,ins);
ImGui::EndTabItem();
}