From f9ae6add8f6080ec0deb73e7940dc442b146d162 Mon Sep 17 00:00:00 2001 From: lxpollitt <630494+lxpollitt@users.noreply.github.com> Date: Thu, 11 Jun 2026 08:37:42 +0100 Subject: [PATCH 1/2] Fix period register writes disturbing the tone, noise and envelope counters The handlers for the tone (R0-R5), noise (R6) and envelope (R11/R12) period registers adjust the running countdown to the next flip-flop toggle when the period changes. The adjustment's sign was inverted: it subtracted the period change from the remaining count instead of adding it. The counters count down to the next toggle, so preserving the time already elapsed since the last toggle - which is what the real chip does, as a period write only changes the value the counter is compared against - requires moving the remaining count by the same amount as the period. With the inverted sign, every period write displaced the next toggle in the wrong direction by twice the period change: period increases could force an immediate spurious toggle (an audible click), and period decreases stalled the next toggle by up to nearly a full old period. The audible effect was extra transient noise during repeated period writes, e.g. pitch slides, vibrato and alternating tones, giving them a buzzy texture. Steady tones were unaffected, since the adjustment only happens at write time and the counter refills correctly from the new period at each toggle. --- html/src/main/java/emu/joric/gwt/GwtAYPSG.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/html/src/main/java/emu/joric/gwt/GwtAYPSG.java b/html/src/main/java/emu/joric/gwt/GwtAYPSG.java index a7c98b5..f4cf99f 100644 --- a/html/src/main/java/emu/joric/gwt/GwtAYPSG.java +++ b/html/src/main/java/emu/joric/gwt/GwtAYPSG.java @@ -340,7 +340,12 @@ public void writeRegister(int address, int value) { int val = (((registers[(address << 1) + 1] & 0x0f) << 8) | registers[address << 1]) * updateStep; int last = period[address]; period[address] = val = ((val < 0x8000) ? 0x8000 : val); - int newCount = count[address] - (val - last); + // Adjust the time remaining to the next flip-flop toggle so that the + // time already elapsed since the last toggle is preserved, i.e. the + // period write moves only the target, as on the real chip. If the + // elapsed time already exceeds the new period, the clamp below makes + // the overdue toggle happen straight away. + int newCount = count[address] + (val - last); count[address] = newCount < 1 ? 1 : newCount; break; } @@ -351,7 +356,7 @@ public void writeRegister(int address, int value) { val *= 2; int last = period[NOISE]; period[NOISE] = val = val == 0 ? updateStep : val; - int newCount = count[NOISE] - (val - last); + int newCount = count[NOISE] + (val - last); count[NOISE] = newCount < 1 ? 1 : newCount; break; } @@ -386,7 +391,7 @@ public void writeRegister(int address, int value) { int val = (((registers[0x0C] << 8) | registers[0x0B]) * updateStep) << 1; int last = period[ENVELOPE]; period[ENVELOPE] = val; - int newCount = count[ENVELOPE] - (val - last); + int newCount = count[ENVELOPE] + (val - last); count[ENVELOPE] = newCount < 1 ? 1 : newCount; break; } From 6ea0eab88b1e3d1103d14cf070c0e149ac27f9a4 Mon Sep 17 00:00:00 2001 From: lxpollitt <630494+lxpollitt@users.noreply.github.com> Date: Thu, 11 Jun 2026 09:38:38 +0100 Subject: [PATCH 2/2] Fix noise period 0 running at twice the speed of period 1 The noise period register (R6) handler mapped a written value of 0 to half the period 1 value, making the noise generator's shift rate twice as fast as period 1. The data sheet notes that, as with the tone period, the lowest noise period value is 1 (divide by 1), so a written value of 0 behaves the same as 1. This has also been verified on original Oric-1 hardware: noise periods 0 and 1 sound identical there (while 1 and 2 are clearly distinguishable), whereas the emulation produced noticeably brighter noise for period 0. The zero mapping predates the code's doubling of the noise period value and was not updated when the doubling was added, which is how "0 behaves as 1" silently became "0 behaves as a half". The fix applies the zero mapping before the doubling. --- html/src/main/java/emu/joric/gwt/GwtAYPSG.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/html/src/main/java/emu/joric/gwt/GwtAYPSG.java b/html/src/main/java/emu/joric/gwt/GwtAYPSG.java index f4cf99f..9623fb7 100644 --- a/html/src/main/java/emu/joric/gwt/GwtAYPSG.java +++ b/html/src/main/java/emu/joric/gwt/GwtAYPSG.java @@ -353,9 +353,14 @@ public void writeRegister(int address, int value) { // Noise period. case 0x06: { int val = (value & 0x1f) * updateStep; + // A noise period of 0 behaves the same as a noise period of 1: the + // data sheet notes that the lowest period value is 1 for both tone + // and noise, and this behaviour has been verified using original + // Oric-1 hardware. + val = (val == 0 ? updateStep : val); val *= 2; int last = period[NOISE]; - period[NOISE] = val = val == 0 ? updateStep : val; + period[NOISE] = val; int newCount = count[NOISE] + (val - last); count[NOISE] = newCount < 1 ? 1 : newCount; break;