Frequency not updating on emulated SN7648 in JSBeeb

bbc micro/electron/atom/risc os coding queries and routines
Post Reply
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

Hi,

I am writing a game. When adding sound to the game I am seeing a problem with setting the frequency of sounds on the emulated SN7648 in JSBeeb only.

Some info.
The code runs after vsync fires in an interupt to play the next note in the sequence of sounds.
Data for frequency and volume is passed to the SN7648 using System Via registers A & B (see ASM below).

It works in jsBeeb and Horizon emulator in a simple test harness using the library. This runs in mode 7 with a simple text menu to trigger the sequences.

It works in Horizon when embedded into my game, however in JsBeeb the sequence plays but with one single frequency which is not intended to be in the sequence. The volume and timing in JSbeeb playback is correct which indicates I am writing the volume data to the SN7648 correctly, but not the frequency (or its somehow being modified).

If you have any thoughts on how to debug/resolve I would appreciate it!

Heres the code I use to play a sounds and then its assembler output so you can see variables and macros unrolled.

Code: Select all


.playtone {
    CPX #NUM_PITCHES
    BCS exit
    \\ X contains note
    \\ A contains channel
    MULTIPLY_BY_32
    CLC
    ADC pitch_cmd_table_1,X
    ORA #%10000000 \\ set the latch
    JSR writeToSN7648
    LDA pitch_cmd_table_2,X
    JSR writeToSN7648
    .exit
    RTS
}

.writeToSN7648
    \\ no interupts during this please
    SEI
    \\ enable writing to SN7648 (not keyboard)
    LDY #&FF
    STY VIA_A_6522_DIRECTION_PORT
    \\ write the data
    STA VIA_A_6522_OUTPUT_REGISTER_A
    \\ changing these values on register b (low then hi) causes data to be pushed
    \\ from the via chip to the SN7648
    LDY #&00
    STY VIA_A_6522_OUTPUT_REGISTER_B
    DELAY_FOR_SN76489
    LDY #&08
    STY VIA_A_6522_OUTPUT_REGISTER_B
    DELAY_FOR_SN76489 \\ doesnt seem to need this. but documentations say it does.
    \\ interupts allowed again.
    CLI
RTS

Code: Select all


.playtone
     2252   E0 84      CPX #&84
     2254   B0 14      BCS &226A
Macro MULTIPLY_BY_32:
Macro SHIFTLEFT:
     2256   0A         ASL A
     2257   0A         ASL A
     2258   0A         ASL A
     2259   0A         ASL A
     225A   0A         ASL A
End macro SHIFTLEFT
End macro MULTIPLY_BY_32
     225B   18         CLC
     225C   7D 7E 22   ADC &227E,X
     225F   09 80      ORA #&80
     2261   20 35 22   JSR &2235
     2264   BD 02 23   LDA &2302,X
     2267   20 35 22   JSR &2235
.exit
     226A   60         RTS
  

Code: Select all

.writeToSN7648
     2235   78         	SEI
     2236   A0 FF      	LDY #&FF
     2238   8C 43 FE   	STY &FE43
     223B   8D 41 FE   	STA &FE41
     223E   A0 00      	LDY #&00
     2240   8C 40 FE   	STY &FE40
Macro DELAY_FOR_SN76489:
     2243   08         	PHP
     2244   28         	PLP
     2245   EA         	NOP
     2246   EA         	NOP
End macro DELAY_FOR_SN76489
     2247   A0 08      	LDY #&08
     2249   8C 40 FE   	STY &FE40
Macro DELAY_FOR_SN76489:
     224C   08         	PHP
     224D   28         	PLP
     224E   EA         	NOP
     224F   EA         	NOP
End macro DELAY_FOR_SN76489
     2250   58         	CLI
     2251   60         	RTS
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

With some more debugging I realise the problem is related to the code I use to scan the keyboard to detect if keys are pressed down.

The game loop waits for Vscan to fire then waits for a timer (to chase the beam)
Every game loop I enable keyboard scanning. When this is commented out the music plays oks.

Below is the code to enable the keyboard scan. Commenting it out makes the sound play in "tune", but it no longer detects if keys are pressed down.

Code: Select all

Macro ENABLE_KEYBOARD_MANUAL_SCAN:
     12E8   78         SEI
Macro WRITE_BYTE_TO_MEMORY:
     12E9   A9 7F      LDA #&7F
     12EB   8D 43 FE   STA &FE43
End macro WRITE_BYTE_TO_MEMORY
Macro WRITE_BYTE_TO_MEMORY:
     12EE   A9 03      LDA #&03
     12F0   8D 40 FE   STA &FE40
End macro WRITE_BYTE_TO_MEMORY
     12F3   58         CLI
End macro ENABLE_KEYBOARD_MANUAL_SCAN
And I check if a key is pressed using code like this, there a number of places I use this and this code could fire during an interrupt playing sound.

Code: Select all

Macro KEY_PRESSED:
     12F4   A9 70      LDA #&70
     12F6   78         SEI
     12F7   8D 4F FE   STA &FE4F
     12FA   AD 4F FE   LDA &FE4F
     12FD   58         CLI
     12FE   30 2E      BMI &132E
End macro KEY_PRESSED
User avatar
tricky
Posts: 7693
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by tricky »

If you don't put the keyboard back into scan mode, it will still be setting bit 7 based on if the key that matches the value you wrote to the sound chip is pressed.

I'm not feeling well, so may have misread your code ;)

I usually read my keys and update sound in the same interrupt routine, so don't need the SEI, CLIs but it won't hurt.

I can't think why you would need the delay outside of having the sound writes enabled.
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

Yes this makes sense. I can't see where its gone wrong and why its *only* a problem on jsBeeb and for the frequency / tone and not volume.
I'll keep looking....
User avatar
tricky
Posts: 7693
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by tricky »

When you are not reading a key at a time, put it back in scan mode.

If I am right, then if you press the key that was last tested for, the sound chip will see what you wrote, but with the top bit set. jsbeeb might be right, I don't know the other emulator, but you could check with beebjit, b2 or b-em and maybe beebem, I haven't checked its code either though.

I don't remember what jsbeeb does, but I've seen different handling of whether a write to the slow data bus is required or just to leave multiple periferals connected.
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

Will do - thank you very much for the input and thoughts!
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

It worked straight away :) Wow - I was going to take a long time to think of that.
This seems like a jsBeeb bug. I'll try a couple of other emulators and submit a bug.
User avatar
tricky
Posts: 7693
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by tricky »

Playing the wrong sound in this situation is the correct behaviour.

By leaving the keyboard in single key mode, you are asking it to write to the slow data bus whenever that key is down, meaning that you now have two things writing to the bus at the same time. I would expect nmos to and them, but could be wrong and I don't know what your the components emulated are :)
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

I just tested on b2 and saw the same behaviour so this makes sense that its expected - the bug is on Horizon.
Thanks again for your time on this - its helped me learn.
User avatar
tricky
Posts: 7693
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by tricky »

No problem, the slow data bus is not quite as straight forward as it seems, but fine when only one thing is enabled at once.

If I hadn't worn a BBC emulator, I would probably just be turning one thing on at a time without thinking about the consequences of having multiple things on at the same time.

The other thing about the keyboard is putting it into scan mode seems to do more work, but only signals it by flagging an interrupt.

I think the Thursday night Dev ABUG is on zoom this week if you are interested; you can just lurk if you like :)
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

Thanks for the invite - send me the details and if I am free I'll join.
Out of interest do you know of a look up table for *tuned* frequencies for the SN7648.
I am using this macro to generate a look up table but it feels pretty out of tune. I found it online (probably in this forum!)

Code: Select all

NUM_PITCHES = 132
.pitch_cmd_table_1 org P% + NUM_PITCHES
.pitch_cmd_table_2 org P% + NUM_PITCHES
{
    for i, 0, NUM_PITCHES-1
        midi = i/3 + 48
        freq = 440 * 2^((midi-69)/12)
        pitch10 = 4000000 / (32 * freq)
        command1 = (pitch10 and &0f) or &80
        command2 = pitch10 >> 4
        org pitch_cmd_table_1 + i
        equb command1
        org pitch_cmd_table_2 + i
        equb command2
    next
}
Coeus
Posts: 3557
Joined: Mon Jul 25, 2016 12:05 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by Coeus »

anthonylime wrote: Wed Jan 17, 2024 3:14 pm Out of interest do you know of a look up table for *tuned* frequencies for the SN7648.
The values used in the OS are documented here: https://tobylobster.github.io/mos/mos/S-s16.html#SP16 along with the ideal and actual note frequencies.

On the calculations you were doing, why the i/3 in looping through the pitches?
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

Coeus wrote: Fri Jan 19, 2024 5:31 pm The values used in the OS are documented here:
Thanks for the reference to that document -That site is a really useful resource and a great piece of work.
It seems to only have one octave so its not enough for what I want to do.
Coeus wrote: Fri Jan 19, 2024 5:31 pm On the calculations you were doing, why the i/3 in looping through the pitches?
I can't remember where I got this code but I think I probably unknowingly or accidentally included that divide. Lazy copy and paste coding! :)
Removing it got me to nice semi-tone intervals. Below is the code that (to my ears) works.

I have read that the 7648 gets out of tune further up and notice the correction to the OS lookup table.
Am I likely to have the same effects with the notes generated by this code?

Code: Select all

NUM_PITCHES = 5*12
.pitch_cmd_table_1 org P% + NUM_PITCHES
.pitch_cmd_table_2 org P% + NUM_PITCHES
{
    for i, 0, NUM_PITCHES-1
        midi = i
        freq = 122 * 2^(i/12)
        pitch10 = 4000000 / (32 * freq)
        command1 = (pitch10 and &0f) or &80
        command2 = pitch10 >> 4
        org pitch_cmd_table_1 + i
        equb command1
        org pitch_cmd_table_2 + i
        equb command2
    next
}
Coeus
Posts: 3557
Joined: Mon Jul 25, 2016 12:05 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by Coeus »

anthonylime wrote: Sat Jan 20, 2024 7:38 am It seems to only have one octave so its not enough for what I want to do.
Each octave going upwards is exactly twice the frequency and each octave downwards is half the frequency so the same would apply to the values to be used with the sound chip (though in the other direction) so, though I haven't checked, I suspect the OS is doing that by shifting the values according to which octave is required before programming them into the chip.
anthonylime wrote: Sat Jan 20, 2024 7:38 am I have read that the 7648 gets out of tune further up and notice the correction to the OS lookup table.
Am I likely to have the same effects with the notes generated by this code?
I am not sure why that would be so. I'd try it and see and in the meantime I'll do some searching.
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

Coeus wrote: Sat Jan 20, 2024 12:55 pm I suspect the OS is doing that by shifting the values according to which octave is required
Thinking about it as the tone gets higher by an octave the OS can shift the values right.
But rounding errors as you do that a few times will start to put it out of tune.
The macro I am using to generate the table will use more memory but is *probably* more accurate
Coeus
Posts: 3557
Joined: Mon Jul 25, 2016 12:05 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by Coeus »

anthonylime wrote: Sat Jan 20, 2024 1:37 pm Thinking about it as the tone gets higher by an octave the OS can shift the values right.
But rounding errors as you do that a few times will start to put it out of tune.
The macro I am using to generate the table will use more memory but is *probably* more accurate
That could be it - as the frequency gets higher the divisor to be programmed gets smaller meaning it has fewer bits of precision. But, if that is the case, the same would be true using a full-table approach, unless the OS was holding the values for one active at less that ten bits precision.

But, on the loss of precision, our perception of pitch is logarithmic so even if the upper notes are numerically further away from their ideal frequency that doesn't necessarily mean we would perceive them as being more out of tune.
User avatar
BigEd
Posts: 6261
Joined: Sun Jan 24, 2010 10:24 am
Location: West Country
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by BigEd »

You can avoid rounding the same value multiple times - that'll be very slightly better than rounding each time you shift. But the best you can do isn't great, in any case, with this sound chip.
User avatar
anthonylime
Posts: 14
Joined: Mon Sep 04, 2023 6:55 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by anthonylime »

I think for the sake of making some progress with the game I’ll use this macro and the in-memory table. When/if I start facing memory problems this is something to return to.

Thanks for the input. This thread has helped me so much.
alecb
Posts: 12
Joined: Thu Feb 22, 2024 9:22 pm
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by alecb »

"I usually read my keys and update sound in the same interrupt routine, so don't need the SEI, CLIs but it won't hurt."

Hi 'Tricky' I'm very interested in sample code for how you do this. I'm writing a two player game and want to support 2 keyboard players as well as 1 Keyboard one joystick, or both joystick. In the 2 keyboard player mode I need 4 directional keys for each player and reading keys from the input buffer is unreliable. Do you have a sample code for the interrupt routine method you mention that I could take a look at perchance?
User avatar
tricky
Posts: 7693
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by tricky »

I'm sure I've posted lots, but I'll try and post something small later.
Basically you sei, set the snow data bus to %rwwwwwww, write the key code and then immediately read back and pressed/unpressed will be in the top bits. Repeat for each key and cli when you have all the values you want.
User avatar
tricky
Posts: 7693
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: Frequency not updating on emulated SN7648 in JSBeeb

Post by tricky »

Code: Select all

.keys_to_scan \\ somewhere in ZP, doesn;t have to be apart from ldx keys_to_scan,y
	EQUB &61, &42, &00, &49
	
	
.read_keys \\ anywhere in memory - don;t need SEI, CLI if in interupt code
{
	ldy #3 \\ number of leys - 1
	lda #0
	SEI
	ldx #3   : stx SysViaRegB \\ write "disable" keyboard auto scan - allows reading keys - could have reused Y as it is 3
	ldx #&7F : stx SysViaDDRA \\ when keyboard selected, write key val to b0-6 and read key state (1=down) from b7
.read_key
	ldx keys_to_scan,y : stx SysViaRegA : asl SysViaRegA : ror A : dey : bpl read_key
	ldx #3+8 : stx SysViaRegB \\ back to auto scan - the default, stops whatever is on the data bus from forcing b7
	CLI
}
\\ A has a bitmask of keys pressed.
This is from an old piece of testcode, still not near PC, but hopefully it works.
Post Reply

Return to “programming”