From ad42390cdd3bc6b3328548e2ff35b0a914ceb6cc Mon Sep 17 00:00:00 2001 From: Brooke Vibber Date: Sat, 31 Aug 2024 10:58:15 -0700 Subject: [PATCH] dither audio --- dither4.s | 25 ++++++++++++++----------- pack-wav.js | 31 ++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/dither4.s b/dither4.s index bbdb96c..c691b46 100644 --- a/dither4.s +++ b/dither4.s @@ -129,17 +129,9 @@ wait_loop: ldy VCOUNT ; 4 cycles bne wait_loop ; 2 cycles - .macro audio_prep - ; Y is VCOUNT at entry - lda (sample_ptr),y ; 5/6 cyc - sta audiotemp ; 3 cyc - .endmacro - .macro inner_scanline frame_offset, line_offset ; Y should be VCOUNT at entry ; it'll fire on unused lines, but harmlessly - ;ldy scanline ; 3 cyc - ;inc scanline ; 5 cyc ; 23-26 cycles before break ; Leisurely memory fetches @@ -149,6 +141,7 @@ wait_loop: lda frame1_palette3_even + frame_offset + line_offset - scanline_offset / 2,y ; 4/5 tay ; 2 pla ; 3 + ; Wait for horizontal blank sta WSYNC ; 4 @@ -165,13 +158,21 @@ wait_loop: sta AUDC1 ; 4 cyc .endmacro + .macro audio_prep + ; Y is VCOUNT at entry + lda (sample_ptr),y ; 5/6 cyc + sta audiotemp ; 3 cyc + .endmacro + + ; call with A pre-loaded to audiotemp .macro audio_play_lo - lda audiotemp ; 3 cyc + ;lda audiotemp ; 3 cyc and #$0f ; 2 cyc ora #$10 ; 2 cyc sta AUDC1 ; 4 cyc .endmacro + ; clobbers Y .macro audio_play_hi ; 12 cycles ldy audiotemp ; 3 cyc lda audio_high_byte,y ; 5 cyc @@ -212,11 +213,13 @@ wait_loop: each_scanline_pair: sty scanline ; 3 cycles + audio_prep + audio_play_lo inner_scanline frame_offset, 0 ; 23-26 cycles before break, 12 cycles after - ldy scanline ; 3 cycles - audio_play_raw ; 8-10 cycles + audio_play_hi + ldy scanline ; 3 cycles inner_scanline frame_offset, 128 ; 23-26 cycles before break, 12 cycles after ; pair cleanup: 6 cycles diff --git a/pack-wav.js b/pack-wav.js index f8ee37f..50379a0 100644 --- a/pack-wav.js +++ b/pack-wav.js @@ -14,31 +14,44 @@ function byte2byte(arr) { return lines.join('\n'); } -function to4bit(val8) { - let val = (val8 + 7) >> 4; - if (val > 15) { - return 15; +class Dither { + constructor() { + this.err = 0; + } + + to4bit(val8) { + let val = (val8 / 255) - this.err; + if (val < 0) { + val = 0; + } + if (val > 1) { + val = 1; + } + let val4 = Math.round(val * 15); + let dithered = (val4 / 15); + this.err = (dithered - val); + return val4; } - return val; } function pack(audio) { let packed = []; - /* + let dither = new Dither(); for (let i = 0; i < audio.length; i += 2) { // little-endian 4-bit samples - let low = to4bit(audio[i]); - let high = to4bit(audio[i + 1]); + let low = dither.to4bit(audio[i]); + let high = dither.to4bit(audio[i + 1]); let byte = low | (high << 4); packed.push(byte); } - */ + /* // raw push bytes for (let i = 0; i < audio.length; i += 2) { let val = to4bit(audio[i]); let byte = val | 0x10; packed.push(byte); } + */ return packed; }