<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[The 1-Bit Forum — 1-bit sound on BBC Micro / Acorn Electron]]></title>
		<link>http://randomflux.info/1bit/viewtopic.php?id=362</link>
		<atom:link href="https://randomflux.info/1bit/extern.php?action=feed&amp;tid=362&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[The most recent posts in 1-bit sound on BBC Micro / Acorn Electron.]]></description>
		<lastBuildDate>Mon, 12 Jan 2026 20:17:59 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3272#p3272</link>
			<description><![CDATA[<p>Posting an update as I finally managed to get the Tritone engine working for the 6502.&nbsp; Drums aren’t implemented, but sounds pretty good.</p><div class="codebox"><pre><code>;Tritone beeper music engine
;Original Z80 code by Shiru 03&#039;2011
;6502 engine port by utz 03&#039;2024
;BBC Micro port by Negative Charge 01&#039;2025

; Constants
OSBYTE                  = $FFF4
OSWRCH                  = $FFEE
OSNEWL                  = $FFE7
SHEILABASE              = $FE00
SYSVIA_DDRA             = SHEILABASE + $43
SYSVIA_ORAS             = SHEILABASE + $4F
SYSVIA_REGB             = SHEILABASE + $40

DISPLAY_START           = $7c00

; Zero Page
ORG     $60
GUARD   $90

.vars_start

.ch0_acc_lo         SKIP 1
.ch0_acc_hi         SKIP 1
.ch1_acc_lo         SKIP 1
.ch1_acc_hi         SKIP 1
.ch2_acc_lo         SKIP 1
.ch2_acc_hi         SKIP 1

.ch0_div_lo         SKIP 1
.ch0_div_hi         SKIP 1
.ch1_div_lo         SKIP 1
.ch1_div_hi         SKIP 1
.ch2_div_lo         SKIP 1
.ch2_div_hi         SKIP 1

.ch0_duty           SKIP 1
.ch1_duty           SKIP 1
.ch2_duty           SKIP 1

.temp_output        SKIP 1

.loop_ptr           SKIP 2
.pattern_ptr        SKIP 2
.order_ptr          SKIP 2
.drum               SKIP 1
.row_length         SKIP 2

.vars_end

ORG     &amp;1900
GUARD   DISPLAY_START

.start

MACRO sound_write_slow
    sta     SYSVIA_ORAS
    lda     #%00000000
    sta     SYSVIA_REGB
    nop:nop:nop
    lda     #%00001000
    sta     SYSVIA_REGB
ENDMACRO

MACRO RESET_SOUND_CHIP
    lda     #%11111111
    sound_write_slow
    lda     #%11011111
    sound_write_slow
    lda     #%10111111
    sound_write_slow
    lda     #%10011111
    sound_write_slow
ENDMACRO

.init
    lda     #%11111111
    sta     SYSVIA_DDRA

    sei

    RESET_SOUND_CHIP

    lda     #%10000001
    sound_write_slow
    lda     #%00000000
    sound_write_slow
    
    lda     #%10100001
    sound_write_slow
    lda     #%00000000
    sound_write_slow
    
    lda     #%11000001
    sound_write_slow
    lda     #%00000000
    sound_write_slow

    lda     #%00000000
    sta     SYSVIA_REGB
    
    lda     #LO(music_data)
    ldx     #HI(music_data)

.play
    pha
    txa
    pha
    
    ; Clear ZP
    lda     #0
    ldx     #vars_end-vars_start
.clear_loop
    sta     vars_start,x
    dex
    bpl     clear_loop
    
    pla
    sta     pattern_ptr+1
    pla
    sta     pattern_ptr+0

    lda     pattern_ptr+0
    clc
    adc     #2
    sta     loop_ptr+0
    lda     pattern_ptr+1
    adc     #0
    sta     loop_ptr+1

.play_loop
    lda     pattern_ptr+0
    sta     order_ptr+0
    lda     pattern_ptr+1
    sta     order_ptr+1

    ldy     #0
    lda     (pattern_ptr),y
    tax
    iny
    lda     (pattern_ptr),y
    
    bne     no_loop
    cpx     #0
    bne     no_loop
    
.return_loop
    lda     loop_ptr+0
    sta     pattern_ptr+0
    lda     loop_ptr+1
    sta     pattern_ptr+1
    jmp     play_loop

.no_loop
    ; Set pattern_ptr to pattern data
    sta     pattern_ptr+1
    stx     pattern_ptr+0
    
    ; Read speed from pattern
    ldy     #0
    lda     (pattern_ptr),y
    sta     row_length+0
    iny
    lda     (pattern_ptr),y
    sta     row_length+1
    
    lda     pattern_ptr+0
    adc     #1
    sta     pattern_ptr+0
    bcc     row
    inc     pattern_ptr+1
    jmp     row

.pattern_end
    lda     order_ptr+0
    clc
    adc     #2
    sta     pattern_ptr+0
    lda     order_ptr+1
    adc     #0
    sta     pattern_ptr+1
    jmp     play_loop

.row
    ldy     #0
    lda     (pattern_ptr),y
    iny
    
    cmp     #255
    beq     pattern_end
    
    cmp     #128
    bcs     ch0
    
    cmp     #2
    bcc     ch0
    
    sta     drum
    lda     (pattern_ptr),y
    iny

.ch0
    cmp     #1
    beq     skip_ch0
    
    cmp     #2
    bcs     ch0_note
    
    sta     ch0_duty
    sta     ch0_div_lo
    sta     ch0_div_hi
    jmp     skip_ch0

.ch0_note
    tax
    and     #$0f
    sta     ch0_div_hi
    txa
    and     #$f0
    sta     ch0_duty
    lda     (pattern_ptr),y
    iny
    sta     ch0_div_lo

.skip_ch0
    lda     (pattern_ptr),y
    iny
    
    cmp     #1
    beq     skip_ch1
    
    cmp     #2
    bcs     ch1_note
    
    sta     ch1_duty
    sta     ch1_div_lo
    sta     ch1_div_hi
    jmp     skip_ch1

.ch1_note
    tax
    and     #$0f
    sta     ch1_div_hi
    txa
    and     #$f0
    sta     ch1_duty
    lda     (pattern_ptr),y
    iny
    sta     ch1_div_lo

.skip_ch1
    lda     (pattern_ptr),y
    iny
    
    cmp     #1
    beq     skip_ch2
    
    cmp     #2
    bcs     ch2_note
    
    sta     ch2_duty
    sta     ch2_div_lo
    sta     ch2_div_hi
    jmp     skip_ch2

.ch2_note
    tax
    and     #$0f
    sta     ch2_div_hi
    txa
    and     #$f0
    sta     ch2_duty
    lda     (pattern_ptr),y
    iny
    sta     ch2_div_lo

.skip_ch2
    tya
    clc
    adc     pattern_ptr+0
    sta     pattern_ptr+0
    bcc     setup_play_loop
    inc     pattern_ptr+1

.setup_play_loop
    lda     row_length+0
    ora     row_length+1
    beq     row_finished
    
    ldx     row_length+0
    ldy     row_length+1

.play_note
    ; CH0
    lda     ch0_acc_lo          ; 3
    adc     ch0_div_lo          ; 3
    sta     ch0_acc_lo          ; 3
    lda     ch0_acc_hi          ; 3
    adc     ch0_div_hi          ; 3
    sta     ch0_acc_hi          ; 3
    cmp     ch0_duty            ; 3 - carry set if acc_hi &gt;= duty
    lda     #$00                ; 2
    sbc     #$00                ; 2 - A = $00 if carry, $FF if !carry
    sta     temp_output         ; 3
    
    ; CH1
    lda     ch1_acc_lo          ; 3
    adc     ch1_div_lo          ; 3
    sta     ch1_acc_lo          ; 3
    lda     ch1_acc_hi          ; 3
    adc     ch1_div_hi          ; 3
    sta     ch1_acc_hi          ; 3
    cmp     ch1_duty            ; 3
    lda     #$00                ; 2
    sbc     #$00                ; 2
    ora     temp_output         ; 3 - mix CH0 | CH1
    sta     temp_output         ; 3
    
    ; CH2
    lda     ch2_acc_lo          ; 3
    adc     ch2_div_lo          ; 3
    sta     ch2_acc_lo          ; 3
    lda     ch2_acc_hi          ; 3
    adc     ch2_div_hi          ; 3
    sta     ch2_acc_hi          ; 3
    cmp     ch2_duty            ; 3
    lda     #$00                ; 2
    sbc     #$00                ; 2
    ora     temp_output         ; 3 - final mix (A = CH0 | CH1 | CH2)
    
    bne     play_sound          ; 2/3
    lda     #$9F                ; 2 - silent
    bne     play_output         ; 3 (always branches)
.play_sound
    lda     #$90                ; 2 - sound
.play_output
    sta     SYSVIA_ORAS         ; 4
    dex                         ; 2
    bne     play_note           ; 3
    dey                         ; 2
    bne     play_note           ; 3
    
.row_finished
    jmp     row

INCLUDE &quot;tracks\lb_zx_tritone.6502&quot; 

.end

SAVE &quot;MAIN&quot;,start,end,init</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Mon, 12 Jan 2026 20:17:59 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3272#p3272</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3071#p3071</link>
			<description><![CDATA[<p>Unfortunately I don’t hear any difference.&nbsp; However, I’ve now ported the code to the Acorn Electron which only has an on/off state for sound (no volume control) and I can hear a recognisable tune - it has a slower 1MHz processor so needs some adjustment.&nbsp; Based on what I’m hearing there may still be some issues with the pattern parsing.&nbsp; I’ll look through a disassembly of XXL’s Atari Tritone code to see if there’s anything obviously different.</p>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Sat, 16 Mar 2024 10:19:33 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3071#p3071</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3070#p3070</link>
			<description><![CDATA[<p>The noise channel probably won&#039;t be useful since it starts on a low cycle.</p><p>However <a href="https://www.smspower.org/Development/SN76489">https://www.smspower.org/Development/SN76489</a> claims that</p><div class="quotebox"><blockquote><p>If the register value is zero or one then the output is a constant value of +1. This is often used for sample playback on the SN76489.</p></blockquote></div><p>so we won&#039;t get any more volume range than we already have anyway. Might still be worth a try to see if 0 gives a better range than 1.</p>]]></description>
			<author><![CDATA[null@example.com (utz)]]></author>
			<pubDate>Thu, 14 Mar 2024 16:56:54 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3070#p3070</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3068#p3068</link>
			<description><![CDATA[<div class="quotebox"><cite>utz wrote:</cite><blockquote><p>Do you happen to know if setting the frequency of an SN channel will reset its phase?</p></blockquote></div><p>I may be wrong, but I believe this is only true of the LFSR (which I’m not using here). However, noise phase is reset by frequency writes, volume writes have no effect.</p>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Thu, 14 Mar 2024 05:33:59 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3068#p3068</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3066#p3066</link>
			<description><![CDATA[<p>Do you happen to know if setting the frequency of an SN channel will reset its phase?</p>]]></description>
			<author><![CDATA[null@example.com (utz)]]></author>
			<pubDate>Wed, 13 Mar 2024 22:32:58 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3066#p3066</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3065#p3065</link>
			<description><![CDATA[<p>Thanks - I’ll try outputting to three channels simultaneously next.&nbsp; I think some of the slowness is probably the values I’m using in the custom .1te engine to output the music data.&nbsp; I’m not sure I have the right value for CPU time.</p><p>I’ve put the code I have so far on GitHub: <a href="https://github.com/NegativeCharge/Beeb-Tritone-Player">https://github.com/NegativeCharge/Beeb-Tritone-Player</a></p>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Wed, 13 Mar 2024 06:53:00 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3065#p3065</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3062#p3062</link>
			<description><![CDATA[<p>Ah, good. I&#039;m really too tired to dig into this today.</p><p>I wonder what causes that high-pitched whine. This and the slow speed makes me think that the engine isn&#039;t running at the 2MHz I was assuming. Are there any interrupts still active? Are there any additional delays when writing to the SN, or is it possible that video is causing some blockage?</p><p>Optimizing the data read will only get you so far. Since the overall volume is low, row transitions will always be noticable. You might gain more by writing to all 3 tone channels instead of just one, provided you can make the inner sound loop run fast enough.</p><p>You might also consider mapping each Tritone channel to it&#039;s own SN channel. That would make things less timing critical.</p>]]></description>
			<author><![CDATA[null@example.com (utz)]]></author>
			<pubDate>Tue, 12 Mar 2024 21:17:26 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3062#p3062</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3061#p3061</link>
			<description><![CDATA[<p>A quick update - I’ve now got this partially working… it’s playing back too slow, is fairly quiet and there’s a high pitched whine in the background.&nbsp; However, it’s making a recognisable sound now :-)&nbsp; Thanks utz!</p><p>The issue was that the SN volume value needs to flip between 0x0 and 0xf rather than 0xff.&nbsp; I added an AND 0xf before each ORA for each channel.</p><p>I now need to alter the speed and optimize the data read somehow.</p>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Tue, 12 Mar 2024 20:26:09 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3061#p3061</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3060#p3060</link>
			<description><![CDATA[<p>Thank you utz.&nbsp; Once I have something working I may take another look at the data format.&nbsp; Here&#039;s the revised code - I still suspect something wrong with the duty or frequency parsing</p><div class="codebox"><pre><code>;Tritone beeper music engine
;Original Z80 code by Shiru 03&#039;2011, released as Public Domain
;1tracker version by Shiru 03&#039;2018
;6502 engine port by utz 03&#039;2024
;Ported to the BBC Micro by Negative Charge 03&#039;2024

; Constants
OSBYTE                  = $FFF4
OSWRCH                  = $FFEE
OSNEWL                  = $FFE7
SHEILABASE              = $FE00             ; System peripherals
SYSVIA_DDRA             = SHEILABASE + $43  ; Data direction register A
SYSVIA_ORAS             = SHEILABASE + $4F  ; Same as REGA but with no handshake I/O
SYSVIA_REGB             = SHEILABASE + $40  ; Port B I/O

DISPLAY_START           = $7c00
DEBUG                   = TRUE
ROW_DEBUG               = FALSE

OP_NOP                  = $EA
OP_ROL_A                = $2A

; Zero Page
ORG     $5f
GUARD   $8f

.vars_start

.loop_ptr           SKIP 2
.pattern_ptr        SKIP 2
.speed              SKIP 2

.drum               SKIP 1

.vars_end

ORG     &amp;1100
GUARD   DISPLAY_START

.start

INCLUDE &quot;lib\os.s.6502&quot; 

; Write data to sound chip then add processing delay
MACRO sound_write_slow
    sta     SYSVIA_ORAS        ;4 Write reg/data to SN76489

    lda     #%00000000         ;2
    sta     SYSVIA_REGB        ;4 
    nop                        ;2
    nop                        ;2
    nop                        ;2
    lda     #%00001000         ;2
    sta     SYSVIA_REGB        ;4
ENDMACRO

MACRO RESET_SOUND_CHIP
    ; Zero volumes on all SN76489 channels, just in case anything already playing
    lda     #%11111111
    sound_write_slow                                ; Channel 3 (Noise)
    lda     #%11011111
    sound_write_slow                                ; Channel 2
    lda     #%10111111
    sound_write_slow                                ; Channel 1
    lda     #%10011111
    sound_write_slow                                ; Channel 0
ENDMACRO

.init
    ; Print Track Title
    ldx     #1
    ldy     #22
    jsr     moveTextCursor

    jsr     printString
    equs    &quot;The Liberty Bell&quot;,0

    ; Print Track Artist
    ldx     #1
    ldy     #24
    jsr     moveTextCursor

    jsr     printString
    equs    &quot;John Philip Sousa&quot;,0

    ; Set up audio
    
    ; System VIA port A to all outputs
    lda     #%11111111
    sta     SYSVIA_DDRA

    sei

    RESET_SOUND_CHIP

    ; Period to 1 on tone channel 0
    lda     #%10000001
    sound_write_slow                                ; Channel 0
    lda     #%00000000
    sound_write_slow

    ; System VIA Port A, place accumulator on wires, no handshake
    lda     #%00000000         
    sta     SYSVIA_REGB

    lda     #LO(music_data)
    ldx     #HI(music_data)

.play

    pha
    txa
    pha
    
    lda     #0
    tax
.zero_page_reset_loop
    sta     vars_start,x
    inx
    cpx     #vars_end-vars_start
    bne     zero_page_reset_loop
    
    pla
    sta     pattern_ptr+1
    pla
    sta     pattern_ptr+0

IF DEBUG
        pha:txa:pha:tya:pha

        ldx     #1
        ldy     #1
        jsr     moveTextCursor
        jsr     printString
        equs    &quot;Pattern Pointer: &quot;,0

        lda     pattern_ptr+1
        jsr     s_print_hex
        lda     pattern_ptr+0
        jsr     s_print_hex
        jsr     OSNEWL

        pla:tay:pla:tax:pla
ENDIF

    ldy     #0
    lda     (pattern_ptr),y
    sta     loop_ptr+0

    iny
    lda     (pattern_ptr),y
    sta     loop_ptr+1
    
IF DEBUG
        pha:txa:pha:tya:pha

        ldx     #1
        ldy     #2
        jsr     moveTextCursor

        jsr     printString
        equs    &quot;Loop Pointer   : &quot;,0

        lda     loop_ptr+1
        jsr     s_print_hex
        lda     loop_ptr+0
        jsr     s_print_hex
        jsr     OSNEWL

        pla:tay:pla:tax:pla
ENDIF

    lda     pattern_ptr+0
    clc
    adc     #6
    sta     pattern_ptr+0
    bcc     play_loop
    inc     pattern_ptr+1

.play_loop

    ldy     #1
    lda     (pattern_ptr),y
    bne     no_loop
    
.return_loop

    lda     loop_ptr+0
    sta     pattern_ptr+0
    lda     loop_ptr+1
    sta     pattern_ptr+1
    jmp     play_loop

.no_loop
    iny
    lda     (pattern_ptr),y
    iny
    sta     speed+0
    sta     row_length_lo
    lda     (pattern_ptr),y
    iny
    sta     speed+1
    sta     row_length_hi

IF DEBUG
        pha:txa:pha:tya:pha

        ldx     #1
        ldy     #4
        jsr     moveTextCursor

        jsr     printString
        equs    &quot;Speed          : &quot;,0

        lda     speed+1
        jsr     s_print_hex
        lda     speed+0
        jsr     s_print_hex
        jsr     OSNEWL

        pla:tay:pla:tax:pla
ENDIF

jmp     row

.pattern_end
    cli                             ; Enable interrupts

    RESET_SOUND_CHIP

    rts

.row
    ldy     #0
    lda     (pattern_ptr),y
    bne     ch0

    sta     drum                    ; Silent
    sta     ch0_duty
    sta     ch0_div_lo
    sta     ch0_div_hi
    jmp     skip_ch0

.ch0
    cmp     #$ff
    beq     pattern_end
    cmp     #$01
    beq     skip_ch0                ; Same as previous ch0 entry
    cmp     #$80
    bcc     skip_drum
    sta     drum

    iny
    lda     (pattern_ptr),y

.skip_drum
    pha
    lsr     a
    lsr     a
    lsr     a
    lsr     a
    sta     ch0_duty
    pla

    ora     #%00001111
    sta     ch0_div_hi

    iny
    lda     (pattern_ptr),y
    sta     ch0_div_lo

.skip_ch0
    iny
    lda     (pattern_ptr),y
    bne     ch1             

    sta     ch1_duty
    sta     ch1_div_lo
    sta     ch1_div_hi
    jmp     skip_ch1

.ch1
    cmp     #$01
    beq     skip_ch1                ; Same as previous ch0 entry
    pha
    lsr     a
    lsr     a
    lsr     a
    lsr     a
    sta     ch1_duty
    pla

    ora     #%00001111
    sta     ch1_div_hi

    iny
    lda     (pattern_ptr),y
    sta     ch1_div_lo

.skip_ch1
    iny
    lda     (pattern_ptr),y
    bne     ch2
    
    sta     ch2_duty
    sta     ch2_div_lo
    sta     ch2_div_hi
    jmp     skip_ch2

.ch2
    cmp     #$01
    beq     skip_ch2                ; Same as previous ch0 entry
    pha
    lsr     a
    lsr     a
    lsr     a
    lsr     a
    sta     ch2_duty
    pla

    ora     #%00001111
    sta     ch2_div_hi

    iny
    lda     (pattern_ptr),y
    sta     ch2_div_lo

.skip_ch2
    tya

row_length_lo=*+1
    ldx     #0                     ;   reset row length counter lo byte
row_length_hi=*+1
    ldy     #0

IF ROW_DEBUG
    jsr     printRowInfo
ENDIF

    clc
    adc     pattern_ptr+0
    sta     pattern_ptr+0
    bcc     play_note
    inc     pattern_ptr+1

.play_note

    clc                             ;2  update osc

ch0_div_lo=*+1
    lda     #$0                     ;2
ch0_acc_lo=*+1
    adc     #$0                     ;2
    sta ch0_acc_lo                  ;4
ch0_div_hi=*+1
    lda     #$0                     ;2
ch0_acc_hi=*+1
    adc     #$0                     ;2
    sta     ch0_acc_hi              ;4
ch0_duty=*+1
    cmp     #$0                     ;2  compare against duty threshold
    sbc     ch0_acc_hi              ;4  A = 0 on low half-cycle, FF on hi half-cycle
    ora     #%10010000              ;2
    sta     SYSVIA_ORAS             ;4

    clc                             ;2
ch1_div_lo=*+1
    lda     #$0                     ;2
ch1_acc_lo=*+1
    adc     #$0                     ;2
    sta     ch1_acc_lo              ;4
ch1_div_hi=*+1
    lda     #$0                     ;2
ch1_acc_hi=*+1
    adc     #$0                     ;2
    sta     ch1_acc_hi              ;4
ch1_duty=*+1
    cmp     #$0                     ;2
    sbc     ch1_acc_hi              ;4
    ora     #%10010000              ;2
    sta     SYSVIA_ORAS             ;4

    clc                             ;2
ch2_div_lo=*+1
    lda     #$0                     ;2
ch2_acc_lo=*+1
    adc     #$0                     ;2
    sta     ch2_acc_lo              ;4
ch2_div_hi=*+1
    lda     #$0                     ;2
ch2_acc_hi=*+1
    adc     #$0                     ;2
    sta     ch2_acc_hi              ;4
ch2_duty=*+1
    cmp     #$0                     ;2
    sbc     ch2_acc_hi              ;4
    ora     #%10010000              ;2
    sta     SYSVIA_ORAS             ;2

    dex                             ;2  row length low byte
    bne     play_note               ;3 -- 95 ~ 21053Hz (original is 22876Hz)

    dey                             ; row length hi byte
    bne     play_note

    jmp     row

.s_print_hex
        pha                            ; Save A
        lsr     a
        lsr     a
        lsr     a
        lsr     a                      ; Move top nybble to bottom nybble
        jsr     printNybble
        pla
        and     #&amp;0f                   ; Mask out original bottom nybble
.printNybble
        sed
        clc
        adc     #&amp;90                   ; Produce &amp;90-&amp;99 or &amp;00-&amp;05
        adc     #&amp;40                   ; Produce &amp;30-&amp;39 or &amp;41-&amp;46
        cld
        jmp     OSWRCH                 ; Print it

.printRowInfo

        pha:txa:pha:tya:pha

        ldx     #1
        ldy     #8
        jsr     moveTextCursor

        jsr     printString
        equs    &quot;Row: &quot;,0

        lda     ch0_div_hi
        jsr     s_print_hex
        lda     ch0_div_lo
        jsr     s_print_hex

        ldx     #11
        ldy     #8
        jsr     moveTextCursor
        
        lda     ch1_div_hi
        jsr     s_print_hex
        lda     ch1_div_lo
        jsr     s_print_hex
        
        ldx     #16
        ldy     #8
        jsr     moveTextCursor

        lda     ch2_div_hi
        jsr     s_print_hex
        lda     ch2_div_lo
        jsr     s_print_hex

        pla:tay:pla:tax:pla

        rts

INCLUDE &quot;tracks\liberty_bell_tritone.6502&quot; 

.end

SAVE &quot;MAIN&quot;,start,end,init

\ ******************************************************************
\ *    Memory Info
\ ******************************************************************

PRINT &quot;-----------------------&quot;
PRINT &quot; 1-BIT TRITONE PLAYER  &quot;
PRINT &quot;-----------------------&quot;
PRINT &quot;CODE size       = &quot;, ~end-start
PRINT &quot;-----------------------&quot;
PRINT &quot;HIGH WATERMARK  = &quot;, ~P%
PRINT &quot;FREE            = &quot;, ~start+end
PRINT &quot;-----------------------&quot;

\ ******************************************************************
\ * Supporting Files
\ ******************************************************************

PUTBASIC &quot;loader.bas&quot;,&quot;LOADER&quot;
PUTFILE  &quot;screens\title.bin&quot;,&quot;TITLE&quot;,DISPLAY_START
PUTFILE  &quot;BOOT&quot;,&quot;!BOOT&quot;,$ffff</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Mon, 11 Mar 2024 22:00:39 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3060#p3060</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3059#p3059</link>
			<description><![CDATA[<p>Ah yes, sorry, Tritone has indeed only global tempo. Also, yes, speed value = row length, and that should be bne play_note.<br />I&#039;ll have to dig deeper, then. Hope I&#039;ll have some time tomorrow.</p><p>I was actually thinking you might want to bypass 1tracker and just dump directly to asm data, so you can save one conversion step and design the data format and loader however you see fit.</p>]]></description>
			<author><![CDATA[null@example.com (utz)]]></author>
			<pubDate>Mon, 11 Mar 2024 21:48:55 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3059#p3059</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3058#p3058</link>
			<description><![CDATA[<p>For standard Tritone there only appears to be a global speed setting? - Tritone Digi has per-row.</p><p>Is the speed the value that should be plugged into the row length counter?… and if so should that be bne play_note rather than beq play_note?</p><p>I’ve tried this but still just getting a high pitched note currently.</p><p>Thanks</p>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Mon, 11 Mar 2024 21:10:32 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3058#p3058</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3057#p3057</link>
			<description><![CDATA[<p>Spotted another one - you&#039;re missing the row length counting, ie.</p><div class="codebox"><pre><code>    dex                         ;2  row length low byte
    beq .play_note              ;3 -- 95 ~ 21053Hz (original is 22876Hz)

    dey                         ; row length hi byte
    beq .play_note</code></pre></div><p>where X should be 0 on init, and Y should be whatever Tritone spits out as row length. I don&#039;t have Tritone&#039;s data format at hand right now but iirc it should be the first byte of a pattern row.</p>]]></description>
			<author><![CDATA[null@example.com (utz)]]></author>
			<pubDate>Mon, 11 Mar 2024 20:02:57 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3057#p3057</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3056#p3056</link>
			<description><![CDATA[<div class="quotebox"><cite>utz wrote:</cite><blockquote><p>One thing I spotted skimming through quickly is that you&#039;re loading a drum marker per tone channel, but there&#039;s only one global drum channel in Tritone.</p></blockquote></div><p>Thanks - I&#039;ve corrected that.&nbsp; I&#039;m still getting the same high pitched output though.</p>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Mon, 11 Mar 2024 14:25:15 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3056#p3056</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3055#p3055</link>
			<description><![CDATA[<p>One thing I spotted skimming through quickly is that you&#039;re loading a drum marker per tone channel, but there&#039;s only one global drum channel in Tritone.</p>]]></description>
			<author><![CDATA[null@example.com (utz)]]></author>
			<pubDate>Mon, 11 Mar 2024 13:59:42 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3055#p3055</guid>
		</item>
		<item>
			<title><![CDATA[Re: 1-bit sound on BBC Micro / Acorn Electron]]></title>
			<link>http://randomflux.info/1bit/viewtopic.php?pid=3054#p3054</link>
			<description><![CDATA[<p>Hi utz,</p><p>I&#039;ve given this a go, but I think I&#039;m either doing something wrong iterating through the pattern data or I&#039;ve messed up the play loop - all I&#039;m getting is a high pitched squeal, and a few clicks.</p><p>I&#039;m using Shiru&#039;s data export from 1tracker, so the format should be familiar.</p><p>I think (based on the tritone.1te) that I may be misinterpreting how the duty and frequency are being stored.</p><p>Is there anything obvious in the below code that jumps out at you as incorrect?</p><p>Thanks!&nbsp; </p><div class="codebox"><pre><code>;Tritone beeper music engine
;Original Z80 code by Shiru 03&#039;2011, released as Public Domain
;1tracker version by Shiru 03&#039;2018
;6502 engine port by utz 03&#039;2024
;Ported to the BBC Micro by Negative Charge 03&#039;2024

; Constants
OSBYTE                  = $FFF4
OSWRCH                  = $FFEE
OSNEWL                  = $FFE7
SHEILABASE              = $FE00             ; System peripherals
SYSVIA_DDRA             = SHEILABASE + $43  ; Data direction register A
SYSVIA_ORAS             = SHEILABASE + $4F  ; Same as REGA but with no handshake I/O
SYSVIA_REGB             = SHEILABASE + $40  ; Port B I/O

DISPLAY_START           = $7c00
DEBUG                   = TRUE

OP_NOP                  = $EA
OP_ROL_A                = $2A

; Zero Page
ORG     $5f
GUARD   $8f

.vars_start

.loop_ptr           SKIP 2
.pattern_ptr        SKIP 2
.speed              SKIP 2

.ch0_drum           SKIP 1
.ch1_drum           SKIP 1
.ch2_drum           SKIP 1

.vars_end

ORG     &amp;1100
GUARD   DISPLAY_START

.start

INCLUDE &quot;lib\os.s.6502&quot; 

; Write data to sound chip then add processing delay
MACRO sound_write_slow
    sta     SYSVIA_ORAS        ;4 Write reg/data to SN76489

    lda     #%00000000         ;2
    sta     SYSVIA_REGB        ;4 
    nop                        ;2
    nop                        ;2
    nop                        ;2
    lda     #%00001000         ;2
    sta     SYSVIA_REGB        ;4
ENDMACRO

MACRO RESET_SOUND_CHIP
    ; Zero volumes on all SN76489 channels, just in case anything already playing
    lda     #%11111111
    sound_write_slow                                ; Channel 3 (Noise)
    lda     #%11011111
    sound_write_slow                                ; Channel 2
    lda     #%10111111
    sound_write_slow                                ; Channel 1
    lda     #%10011111
    sound_write_slow                                ; Channel 0
ENDMACRO

.init
    \ Print Track Title
    ldx     #1
    ldy     #22
    jsr     moveTextCursor

    jsr     printString
    equs    &quot;The Liberty Bell&quot;,0

    \ Print Track Artist
    ldx     #1
    ldy     #24
    jsr     moveTextCursor

    jsr     printString
    equs    &quot;John Philip Sousa&quot;,0

    ; Set up audio
    
    ; System VIA port A to all outputs
    lda     #%11111111
    sta     SYSVIA_DDRA

    sei

    RESET_SOUND_CHIP

    ; Period to 1 on tone channel 0
    lda     #%10000001
    sound_write_slow                                ; Channel 0
    lda     #%00000000
    sound_write_slow

    ; System VIA Port A, place accumulator on wires, no handshake
    lda     #%00000000         
    sta     SYSVIA_REGB

    lda     #LO(music_data)
    ldx     #HI(music_data)

.play

    pha
    txa
    pha
    
    lda     #0
    tax
.zero_page_reset_loop
    sta     vars_start,x
    inx
    cpx     #vars_end-vars_start
    bne     zero_page_reset_loop
    
    pla
    sta     pattern_ptr+1
    pla
    sta     pattern_ptr+0

IF DEBUG
        pha:txa:pha:tya:pha

        ldx     #1
        ldy     #1
        jsr     moveTextCursor
        jsr     printString
        equs    &quot;Pattern Pointer: &quot;,0

        lda     pattern_ptr+1
        jsr     s_print_hex
        lda     pattern_ptr+0
        jsr     s_print_hex
        jsr     OSNEWL

        pla:tay:pla:tax:pla
ENDIF

    ldy     #0
    lda     (pattern_ptr),y
    sta     loop_ptr+0

    iny
    lda     (pattern_ptr),y
    sta     loop_ptr+1
    
IF DEBUG
        pha:txa:pha:tya:pha

        ldx     #1
        ldy     #2
        jsr     moveTextCursor

        jsr     printString
        equs    &quot;Loop Pointer   : &quot;,0

        lda     loop_ptr+1
        jsr     s_print_hex
        lda     loop_ptr+0
        jsr     s_print_hex
        jsr     OSNEWL

        pla:tay:pla:tax:pla
ENDIF

    lda     pattern_ptr+0
    clc
    adc     #6
    sta     pattern_ptr+0
    bcc     play_loop
    inc     pattern_ptr+1

.play_loop

    ldy     #1
    lda     (pattern_ptr),y
    bne     no_loop
    
.return_loop

    lda     loop_ptr+0
    sta     pattern_ptr+0
    lda     loop_ptr+1
    sta     pattern_ptr+1
    jmp     play_loop

.no_loop
    iny
    lda     (pattern_ptr),y
    iny
    sta     speed+0
    lda     (pattern_ptr),y
    iny
    sta     speed+1

IF DEBUG
        pha:txa:pha:tya:pha

        ldx     #1
        ldy     #4
        jsr     moveTextCursor

        jsr     printString
        equs    &quot;Speed          : &quot;,0

        lda     speed+1
        jsr     s_print_hex
        lda     speed+0
        jsr     s_print_hex
        jsr     OSNEWL

        pla:tay:pla:tax:pla
ENDIF

jmp     row

.pattern_end
    cli     ; Enable interrupts

    RESET_SOUND_CHIP

    rts

.row
    ldy     #0
    lda     (pattern_ptr),y
    bne     ch0

    sta     ch0_drum        ; Silent
    sta     ch0_duty
    sta     ch0_div_lo
    sta     ch0_div_hi
    jmp     skip_ch0

.ch0
    cmp     #$ff
    beq     pattern_end
    cmp     #$01
    beq     skip_ch0        ; Same as previous ch0 entry
    cmp     #$80
    bcc     skip_drum_0
    sta     ch0_drum

    iny
    lda     (pattern_ptr),y

.skip_drum_0
    pha
    lsr     a
    lsr     a
    lsr     a
    lsr     a
    sta     ch0_duty
    pla

    ora     #%00001111
    sta     ch0_div_hi

    iny
    lda     (pattern_ptr),y
    sta     ch0_div_lo

.skip_ch0
    iny
    lda     (pattern_ptr),y
    bne     ch1             

    sta     ch1_drum        ; Silent
    sta     ch1_duty
    sta     ch1_div_lo
    sta     ch1_div_hi
    jmp     skip_ch1

.ch1
    cmp     #$01
    beq     skip_ch1        ; Same as previous ch0 entry
    cmp     #$80
    bcc     skip_drum_1
    sta     ch1_drum

    iny
    lda     (pattern_ptr),y

.skip_drum_1
    pha
    lsr     a
    lsr     a
    lsr     a
    lsr     a
    sta     ch1_duty
    pla

    ora     #%00001111
    sta     ch1_div_hi

    iny
    lda     (pattern_ptr),y
    sta     ch1_div_lo

.skip_ch1
    iny
    lda     (pattern_ptr),y
    bne     ch2

    sta     ch2_drum        ; Silent
    sta     ch2_duty
    sta     ch2_div_lo
    sta     ch2_div_hi
    jmp     skip_ch2

.ch2
    cmp     #$01
    beq     skip_ch2        ; Same as previous ch0 entry
    cmp     #$80
    bcc     skip_drum_2
    sta     ch2_drum

    iny
    lda     (pattern_ptr),y

.skip_drum_2
    pha
    lsr     a
    lsr     a
    lsr     a
    lsr     a
    sta     ch2_duty
    pla

    ora     #%00001111
    sta     ch2_div_hi

    iny
    lda     (pattern_ptr),y
    sta     ch2_div_lo

.skip_ch2
    tya
    clc
    adc     pattern_ptr+0
    sta     pattern_ptr+0
    bcc     play_note
    inc     pattern_ptr+1

.play_note

IF DEBUG
    jsr     printRowInfo
ENDIF

    clc                             ;2  update osc

ch0_div_lo=*+1
    lda     #$0                     ;2
ch0_acc_lo=*+1
    adc     #$0                     ;2
    sta ch0_acc_lo                  ;4
ch0_div_hi=*+1
    lda     #$0                     ;2
ch0_acc_hi=*+1
    adc     #$0                     ;2
    sta     ch0_acc_hi              ;4
ch0_duty=*+1
    cmp     #$0                     ;2  compare against duty threshold
    sbc     ch0_acc_hi              ;4  A = 0 on low half-cycle, FF on hi half-cycle
    ora     #%10010000              ;2
    sta     SYSVIA_ORAS             ;4

    clc                             ;2
ch1_div_lo=*+1
    lda     #$0                     ;2
ch1_acc_lo=*+1
    adc     #$0                     ;2
    sta     ch1_acc_lo              ;4
ch1_div_hi=*+1
    lda     #$0                     ;2
ch1_acc_hi=*+1
    adc     #$0                     ;2
    sta     ch1_acc_hi              ;4
ch1_duty=*+1
    cmp     #$0                     ;2
    sbc     ch1_acc_hi              ;4
    ora     #%10010000              ;2
    sta     SYSVIA_ORAS             ;4

    clc                             ;2
ch2_div_lo=*+1
    lda     #$0                     ;2
ch2_acc_lo=*+1
    adc     #$0                     ;2
    sta     ch2_acc_lo              ;4
ch2_div_hi=*+1
    lda     #$0                     ;2
ch2_acc_hi=*+1
    adc     #$0                     ;2
    sta     ch2_acc_hi              ;4
ch2_duty=*+1
    cmp     #$0                     ;2
    sbc     ch2_acc_hi              ;4
    ora     #%10010000              ;2
    sta     SYSVIA_ORAS             ;2

    jmp     row

.s_print_hex
        pha                            ; Save A
        lsr     a
        lsr     a
        lsr     a
        lsr     a                      ; Move top nybble to bottom nybble
        jsr     printNybble
        pla
        and     #&amp;0f                   ; Mask out original bottom nybble
.printNybble
        sed
        clc
        adc     #&amp;90                   ; Produce &amp;90-&amp;99 or &amp;00-&amp;05
        adc     #&amp;40                   ; Produce &amp;30-&amp;39 or &amp;41-&amp;46
        cld
        jmp     OSWRCH                 ; Print it

.printRowInfo

        pha:txa:pha:tya:pha

        ldx     #1
        ldy     #8
        jsr     moveTextCursor

        jsr     printString
        equs    &quot;Row: &quot;,0

        lda     ch0_div_hi
        jsr     s_print_hex
        lda     ch0_div_lo
        jsr     s_print_hex

        ldx     #11
        ldy     #8
        jsr     moveTextCursor
        
        lda     ch1_div_hi
        jsr     s_print_hex
        lda     ch1_div_lo
        jsr     s_print_hex
        
        ldx     #16
        ldy     #8
        jsr     moveTextCursor

        lda     ch2_div_hi
        jsr     s_print_hex
        lda     ch2_div_lo
        jsr     s_print_hex

        pla:tay:pla:tax:pla

        rts

INCLUDE &quot;tracks\liberty_bell_tritone.6502&quot; 

.end

SAVE &quot;MAIN&quot;,start,end,init

\ ******************************************************************
\ *    Memory Info
\ ******************************************************************

PRINT &quot;-----------------------&quot;
PRINT &quot; 1-BIT TRITONE PLAYER  &quot;
PRINT &quot;-----------------------&quot;
PRINT &quot;CODE size       = &quot;, ~end-start
PRINT &quot;-----------------------&quot;
PRINT &quot;HIGH WATERMARK  = &quot;, ~P%
PRINT &quot;FREE            = &quot;, ~start+end
PRINT &quot;-----------------------&quot;

\ ******************************************************************
\ * Supporting Files
\ ******************************************************************

PUTBASIC &quot;loader.bas&quot;,&quot;LOADER&quot;
PUTFILE  &quot;screens\title.bin&quot;,&quot;TITLE&quot;,DISPLAY_START
PUTFILE  &quot;BOOT&quot;,&quot;!BOOT&quot;,$ffff</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (negative charge)]]></author>
			<pubDate>Mon, 11 Mar 2024 12:20:24 +0000</pubDate>
			<guid>http://randomflux.info/1bit/viewtopic.php?pid=3054#p3054</guid>
		</item>
	</channel>
</rss>
