class ZXUtils::AYMusicPlayer

AY-3-8910/8912 music player

The music module player based on ZXUtils::AYMusic engine.

ZXUtils::MusicBox provides a Ruby DSL for creating music modules for the AYMusic engine.

The player expects a music module in the format produced by MusicBox::Song.to_player_module.

The format of the music module

The delta is an address of the second (most significant) delta's byte subtracted from the addressed entry. When the delta value will be added to the address of the 2nd delta's byte address it should resolve to the indicated entry address.

index_table can have 0 or more, up to 128, entries.

+---------------------------+
| track_a delta             | 2 bytes
+---------------------------+
| track_b delta             | 2 bytes
+---------------------------+
| track_c delta             | 2 bytes
+---------------------------+
| index_table entry 1 delta | 2 bytes
+---------------------------+
             ...
+---------------------------+
| index_table entry N delta | 2 bytes
+---------------------------+
|  AYMusic data for tracks, |
|  envelopes, masks, chords |
+---------------------------+

Use player from your program

  1. Call AYMusicPlayer.setup routine only once. It gets overwritten by the data it creates for the player.

  2. Call AYMusicPlayer.init to initialize music module. This may be called unlimited times.

  3. Call AYMusic.play on each tick to play the music.

  4. Call AYMusicPlayer.mute_sound to silence the AY's sound.

require 'zxutils/ay_music_player'
class Program
    include Z80
    include Z80::TAP
    include ZXUtils

    start         call player.setup
                  ld   hl, music_module
                  call player.init
    forever       halt
                  di
                  push iy
                  call player.play
                  pop  iy
                  ei
                  jr   forever
    music_module  import_file "examples/test_music.tap"
                  import AYMusicPlayer, :player
    # reserve memory here which will be used by the player
    # the end of the reserved space is indicated by the player.sincos_end label
    # there may be 0 or more bytes available between player.workspace_end and player.sincos
    # depending on the code address as player.sincos must be aligned to 256 bytes.
end

program = Program.new(0x8000)
puts program.debug
program.save_tap('miniplayer')

Constants

SinCos
SinCosTable

Public Instance Methods

init() click to toggle source

Initialize music module.

Relocates index table and sets the tracks' cursors to the initial positions. Module data is not being modified.

You may also call the init.restart entry to reset tracks to the beginning of the last initialized module.

NOTE

This routine will disable and enable interrupts before it's finished.

Modifies: af, bc, de, hl, ix and 1 stack entry.

# File lib/zxutils/ay_music_player.rb, line 129
ns :init do
                    ld   de, track_info
                    ld   a, 3
                    call relocate16
                    ld   a, 128
                    ld   de, index_table
                    call relocate16
  restart           di
                    call music.init
  track_info        data TrackInfo, 1
                    ei
  if AYMusic::READ_ONLY_CODE
                    ld   hl, index_table
                    ld   [music.music_control.index_table], hl
  end
                    ret
end
mute_sound() click to toggle source

Mutes sound.

Modifies: af, bc.

# File lib/zxutils/ay_music_player.rb, line 171
ns :mute_sound do
                    ay_init(io_ay:io_ay)
                    ret
end
setup() click to toggle source

Sets up the player.

Call this ONCE the player code has been loaded to create required tables for the music player.

NOTE

The following code gets overwritten once it is being called.

NOTE

This routine will disable and enable interrupts before it's finished.

Modifies: af, bc, de, hl, af', bc', de', hl', ix and 1 stack entry.

# File lib/zxutils/ay_music_player.rb, line 188
ns :setup do
                    call setup_tone_progress
                    ay_music_note_to_fine_tone_cursor_table_factory(music.note_to_cursor, play:music.play)
                    ay_expand_notes(music.notes, octaves:8, half_tones:12)
                    create_sincos_from_sintable(sincos, sintable:sintable)
  sintable          bytes neg_sintable256_pi_half_no_zero_lo
end