psg module: the envelope handler no longer writes to vera PSG voices that haven't been enabled

This commit is contained in:
Irmen de Jong
2025-03-12 22:48:13 +01:00
parent 8b08895d0f
commit 5dd45b714a
11 changed files with 73 additions and 37 deletions
+34 -10
View File
@@ -15,14 +15,22 @@ psg {
const ubyte NOISE = %11000000
const ubyte LEFT = %01000000
const ubyte RIGHT = %10000000
const ubyte DISABLED = %11111111
sub init() {
; -- initializes the psg module (all 16 voices set to disabled)
for cx16.r1L in 0 to 15
voice_enabled[cx16.r1L] = false
}
sub voice(ubyte voice_num, ubyte channel, ubyte vol, ubyte waveform, ubyte pulsewidth) {
; -- Enables a 'voice' on the PSG.
; voice_num = 0-15, the voice number.
; channel = either LEFT or RIGHT or (LEFT|RIGHT). Specifies the stereo channel(s) to use.
; channel = either LEFT or RIGHT or (LEFT|RIGHT). Specifies the stereo channel(s) to use. DISABLED=disable the voice.
; vol = 0-63, the starting volume for the voice
; waveform = one of PULSE,SAWTOOTH,TRIANGLE,NOISE.
; pulsewidth = 0-63. Specifies the pulse width for waveform=PULSE.
voice_enabled[voice_num] = false
envelope_states[voice_num] = 255
sys.irqsafe_set_irqd()
cx16.r0 = $f9c2 + voice_num * 4
@@ -30,11 +38,19 @@ psg {
cx16.VERA_ADDR_L = lsb(cx16.r0)
cx16.VERA_ADDR_M = msb(cx16.r0)
cx16.VERA_ADDR_H = 1
cx16.VERA_DATA0 = channel | vol
cx16.VERA_ADDR_L++
cx16.VERA_DATA0 = waveform | pulsewidth
envelope_volumes[voice_num] = mkword(vol, 0)
envelope_maxvolumes[voice_num] = vol
if channel!=DISABLED {
cx16.VERA_DATA0 = channel | vol
cx16.VERA_ADDR_L++
cx16.VERA_DATA0 = waveform | pulsewidth
envelope_volumes[voice_num] = mkword(vol, 0)
envelope_maxvolumes[voice_num] = vol
voice_enabled[voice_num] = true
} else {
cx16.VERA_DATA0 = 0
envelope_volumes[voice_num] = 0
envelope_maxvolumes[voice_num] = 0
voice_enabled[voice_num] = false
}
sys.irqsafe_clear_irqd()
}
@@ -99,10 +115,12 @@ psg {
}
sub silent() {
; -- Shut down all PSG voices.
; -- Silence all active PSG voices.
for cx16.r1L in 0 to 15 {
envelope_states[cx16.r1L] = 255
volume(cx16.r1L, 0)
if voice_enabled[cx16.r1L] {
envelope_states[cx16.r1L] = 255
volume(cx16.r1L, 0)
}
}
}
@@ -122,6 +140,8 @@ psg {
sys.pushw(cx16.r9)
; calculate new volumes
for cx16.r1L in 0 to 15 {
if not voice_enabled[cx16.r1L]
continue
when envelope_states[cx16.r1L] {
0 -> {
; attack
@@ -165,7 +185,10 @@ psg {
cx16.VERA_ADDR_M = $f9
cx16.VERA_ADDR_H = 1 | %00110000
for cx16.r1L in 0 to 15 {
cx16.VERA_DATA0 = cx16.VERA_DATA1 & %11000000 | msb(envelope_volumes[cx16.r1L])
if voice_enabled[cx16.r1L]
cx16.VERA_DATA0 = cx16.VERA_DATA1 & %11000000 | msb(envelope_volumes[cx16.r1L])
else
cx16.VERA_DATA0 = cx16.VERA_DATA1
}
cx16.restore_vera_context()
cx16.r9 = sys.popw()
@@ -175,6 +198,7 @@ psg {
return true ; run the system IRQ handler afterwards
}
bool[16] voice_enabled
ubyte[16] envelope_states
uword[16] envelope_volumes ; scaled by 256
ubyte[16] envelope_attacks
@@ -89,7 +89,9 @@ main {
}
}
"""
@Suppress("DEPRECATION") // Thread.currentThread().id
val filenameBase = "on_the_fly_test_" + Thread.currentThread().id.toString() + "_" + sourceText.hashCode().toUInt().toString(16)
val filepath = outputDir.resolve("$filenameBase.p8")
filepath.toFile().writeText(sourceText)
val (program, options, importedfiles) = parseMainModule(filepath, errors, C64Target(), emptyList(), emptyList())
+1
View File
@@ -60,6 +60,7 @@ internal fun compileText(
errors: IErrorReporter? = null,
writeAssembly: Boolean = true,
) : CompilationResult? {
@Suppress("DEPRECATION") // Thread.currentThread().id
val filePath = outputDir.resolve("on_the_fly_test_" + Thread.currentThread().id.toString() + "_" + sourceText.hashCode().toUInt().toString(16) + ".p8")
// we don't assumeNotExists(filePath) - should be ok to just overwrite it
filePath.toFile().writeText(sourceText)
@@ -1,5 +1,6 @@
Prog8 compiler v11.2 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.3-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 8e31b622 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c128.p8
@@ -1,5 +1,6 @@
Prog8 compiler v11.2 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.3-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 8e31b622 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c64.p8
@@ -1,5 +1,6 @@
Prog8 compiler v11.2 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.3-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 8e31b622 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-cx16.p8
@@ -586,6 +587,7 @@ LIBRARY MODULE NAME: psg
------------------------
psg {
const ubyte DISABLED
const ubyte LEFT
const ubyte NOISE
const ubyte PULSE
@@ -598,9 +600,11 @@ psg {
ubyte[] envelope_states
ubyte[] envelope_sustains
uword[] envelope_volumes
bool[] voice_enabled
envelope (ubyte voice_num, ubyte maxvolume, ubyte attack, ubyte sustain, ubyte release)
envelopes_irq () -> bool
freq (ubyte voice_num, uword vera_freq)
init ()
pulse_width (ubyte voice_num, ubyte pw)
silent ()
voice (ubyte voice_num, ubyte channel, ubyte vol, ubyte waveform, ubyte pulsewidth)
@@ -1,5 +1,6 @@
Prog8 compiler v11.2 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.3-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 8e31b622 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-pet32.p8
@@ -1,5 +1,6 @@
Prog8 compiler v11.2 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.3-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 8e31b622 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-virtual.p8
@@ -293,6 +294,7 @@ strings {
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
ncompare (str st1, str st2, ubyte length) -> byte
rfind (uword stringptr, ubyte character) -> ubyte
right (str source, ubyte slen, str target)
rstrip (str s)
+1
View File
@@ -9,6 +9,7 @@ TODO
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
- in unit test helpers: replace own temp file name creation by kotest tempfile()/tempdir() , instead of using Thread.currentThread().id, which is deprecated in newer Java versions
- allow integer range as when choice? because 1,2,3,4,5 is already allowed, so perhaps 1 to 5 should be allowed too? However, [1,2,3,4,5] usually is the desugared equivalent of 1 to 5 and choice values can't be arrays.
- const values should always either be of type long or float, this is how they were usually treated in const expression evaluation already anyway
- Kotlin: can we use inline value classes in certain spots?
+20 -21
View File
@@ -1,32 +1,31 @@
%import textio
%import strings
%import psg
%zeropage basicsafe
%option no_sysinit
main {
str name1 = "irmen"
str name2 = "irmen de jong"
sub start() {
psg.init()
txt.print_b(strings.compare(name1, name2))
txt.spc()
txt.print_b(strings.compare(name2, name1))
txt.nl()
psg.voice(5, psg.LEFT, 0, psg.TRIANGLE, 0)
psg.freq(5, 1600)
psg.envelope(5, 63, 10, 50, 2)
txt.print_b(strings.ncompare(name1, name2, 6))
txt.spc()
txt.print_b(strings.ncompare(name2, name1, 6))
txt.nl()
psg.voice(6, psg.RIGHT, 0, psg.SAWTOOTH, 0)
psg.freq(6, 1200)
psg.envelope(6, 63, 2, 50, 10)
txt.print_b(strings.ncompare(name1, name2, 5))
txt.spc()
txt.print_b(strings.ncompare(name2, name1, 5))
txt.nl()
repeat 140 {
sys.waitvsync()
psg.envelopes_irq()
}
txt.print_b(strings.ncompare(name1, name2, 4))
txt.spc()
txt.print_b(strings.ncompare(name2, name1, 4))
txt.nl()
psg.voice(5, psg.DISABLED, 0, 0, 0)
psg.voice(6, psg.DISABLED, 0, 0, 0)
psg.silent()
repeat {
sys.waitvsync()
psg.envelopes_irq()
}
}
}
+1 -1
View File
@@ -3,4 +3,4 @@ org.gradle.console=rich
org.gradle.parallel=true
org.gradle.daemon=true
kotlin.code.style=official
version=11.2
version=11.3-SNAPSHOT