Give an accepted action a sound. The same caller changes its picture and triggers this effect; a second version performs the action with the trigger removed. Listen to both.
Working effect
Trigger omitted
Take the effect
The reusable effect
; OSWORD7 copies this eight-byte SOUND block into MOS's sound system.
; Flush channel 1, amplitude -15, pitch 100, duration 2 twentieths of a second.
; MOS services audio asynchronously. Call only from main, not inside IRQ.
; Changes A/X/Y/flags. Caller owns channel 1; no music arbitration here.
trigger_sound:
lda #7
ldx #<sound_block
ldy #>sound_block
jmp OSWORD
sound_block: !word 17,-15,100,2The SOUND block is eight bytes: channel 17 flushes and uses channel 1, amplitude -15, pitch 100, duration 2. OSWORD 7 copies it into MOS audio state. Playback is asynchronous; call from main with MOS IRQ services intact. A/X/Y/flags change.
Define OSWORD=$FFF1, include the routine and its eight-byte block, then JSR trigger_sound from main. The MOS copies the block; its IRQ-driven sound system handles playback after the call. Channel 17 requests a flush of channel 1’s queue. That policy deliberately replaces a previous effect on that channel.
Change it and recognise a mistake
Change the SOUND block. Queuing versus flushing is a deliberate channel policy; copying the block gives the OS its own queued parameters.
The omitted-trigger control still accepts the action but fails the same audio guard as the working caller. Keyboard clicks or other machine output are not enough: the BASIC checks compare against a separate rejected-command recording.
The working implementation above repairs that omission. If an effect instead drones on, check the mute/service path and that its state is initialised. Servicing twice makes a counted effect shorter; servicing only after input can leave it running while the player waits. Those are lifecycle decisions to test when adapting it.
Run the caller
Build bbc-micro/patterns/assembly/input/mos-controls, type the generated build/loader.bas in the recorded BASIC, then RUN. Move with Q/A/O/P; Space restarts. Holding a direction keeps moving; holding Space must allow movement after the first restart.

Where setup, trigger and service belong
; BBC Model B MOS 1.20/BASIC II. Typed loader, then CALL &3000.
; Q/A/O/P move, Space restarts. MOS owns IRQ and SOUND queue; reset to leave.
*=$3000
OSWRCH=$ffee
OSWORD=$fff1
start:
cli
jsr reset_game
main_loop:
jsr wait_frame
jsr read_controls
jsr detect_edges
jsr update_player
jsr draw_screen
inc updates
frame_done:
jmp main_loop
updates: !byte 0
!source "state.inc"
!source "rules.inc"
!source "input.inc"
!source "draw.inc"
!source "sound.inc"
!source "../../framework/game-loop/frame.inc"
!source "collision.inc"Compare blocking, serviced and queued sound when choosing the next step.
Verification and sources
Target: BBC Model B MOS 1.20/BASIC II, MODE 6. These callers were executed with released Emu198x 0.44.1; assembly uses Asm198x 0.0.71. The sample folder contains reproduction instructions and retained observations. The independent checker binds source, native captures and actual output; its rejection tests exercise wrong state, missing files and false audio claims.
This qualifies the named emulator/firmware path. Pitch accuracy, original hardware and other peripherals require their own observations. The muted MOS run is an explicit diagnostic RAM patch to RTS at trigger_sound, restored after the check.
Acorn, BBC Microcomputer Advanced User Guide / Electron technical documentation: OSBYTE &81 negative INKEY and OSWORD &07 SOUND block; MOS IRQ ownership.