class _sound_channel
var song: song
var track_index: int
var next_pattern_index: int
var sync_data: int
var events: track_event[]
var next_event_index: int
var instrument: io_instrument
var write_index: byte
var samples_per_tick: pair
var is_playing: bool
var looping: bool
end class
module sound
var _sound_channels: _sound_channel[]
var _note_to_pitch: pair[]
func init()
sound::_sound_channels <- new _sound_channel[](6)
io::jamdac_enable <- 0
var queue: ^io_audio_queue
var i: int
i <- 0
loop
sound::_sound_channels[i] <- new _sound_channel()
queue <- io::audio_queues[i]
queue.write_address <- to_address(queue.events)
queue.read_address <- queue.write_address
queue.purge_read_address <- 0
i <- i + 1
if i >= 6
do drop
end loop
queue <- io::audio_queues[0]
var new_audio_event: ^io_audio_event
new_audio_event <- queue.events[0]
new_audio_event.kind <- 7
new_audio_event.operand <- to_address(art::reverb)
new_audio_event <- queue.events[1]
new_audio_event.kind <- 3
new_audio_event.operand <- to_address(art::envelope_3)
new_audio_event <- queue.events[2]
new_audio_event.kind <- 5
new_audio_event.operand <- 3
queue.write_address <- to_address(queue.events[3])
sound::_sound_channels[0].write_index <- 3
io::jamdac_enable <- 1
kernel::trace_id(0)
loop
if queue.read_address = queue.write_address
do drop
end loop
end func
func play_track(track: track, channel_index: int)
sound::_play_track(track, channel_index, false)
end func
func loop_track(track: track, channel_index: int)
sound::_play_track(track, channel_index, true)
end func
func _play_track(track: track, channel_index: int, looping: bool)
if sound::_sound_channels = null
do return
sound::stop_channel(channel_index)
var channel: _sound_channel
channel <- sound::_sound_channels[channel_index]
channel.song <- null
channel.looping <- looping
channel.samples_per_tick <- 459
channel.is_playing <- true
channel.track_index <- 0
channel.next_pattern_index <- 0
channel.sync_data <- 0
channel.events <- track.events
channel.next_event_index <- 0
end func
func stop_channel(channel_index: int)
if sound::_sound_channels = null
do return
var channel: _sound_channel
channel <- sound::_sound_channels[channel_index]
channel.song <- null
channel.is_playing <- false
channel.events <- null
channel.instrument <- null
var queue: ^io_audio_queue
queue <- io::audio_queues[channel_index]
var write_index: byte, write_address: int, read_address: int
read_address <- queue.read_address
write_address <- queue.write_address
if read_address <> write_address then
queue.purge_read_address <- queue.write_address
end if
write_index <- channel.write_index
var new_audio_event: ^io_audio_event
new_audio_event <- queue.events[write_index]
new_audio_event.kind <- 0
new_audio_event.operand <- 0
write_index <- to_byte(write_index + 1)
if write_index >= 100
do write_index <- 0
write_address <- to_address(queue.events[write_index])
channel.write_index <- write_index
queue.write_address <- write_address
end func
func play_song(song: song)
sound::_play_song(song, false)
end func
func loop_song(song: song)
sound::_play_song(song, true)
end func
func _play_song(song: song, looping: bool)
if sound::_sound_channels = null
do return
var i: int, track_count: int
var pattern: song_pattern
var sync_data: int
pattern <- song.patterns[0]
track_count <- pattern.tracks.size
if track_count > 1 then
sync_data <- track_count
else
sync_data <- 0
end if
i <- 0
loop
if i >= track_count
do drop
sound::stop_channel(i)
var channel: _sound_channel
channel <- sound::_sound_channels[i]
channel.song <- song
channel.looping <- looping
channel.is_playing <- true
channel.track_index <- i
channel.next_pattern_index <- 1
channel.sync_data <- sync_data
channel.events <- pattern.tracks[i].events
channel.samples_per_tick <- pattern.samples_per_tick
channel.next_event_index <- 0
channel.instrument <- null
i <- i + 1
end loop
end func
func _process_channel(
| channel: _sound_channel,
| queue: ^io_audio_queue)
var write_index: byte, write_address: int, read_address: int
var temp: int
var new_audio_event: ^io_audio_event
if channel.events = null and not channel.is_playing
do return
write_index <- channel.write_index
write_address <- to_address(queue.events[write_index])
if write_address <> queue.write_address
do kernel::fail("_process_channel() write_address out of sync")
if queue.purge_read_address <> 0
do return
read_address <- queue.read_address
if channel.events <> null then
loop
if read_address <= write_address then
temp <- read_address + 500
else
temp <- read_address
end if
if temp - write_address < 30
do drop
if channel.next_event_index >= channel.events.size then
if channel.song <> null then
var patterns: song_pattern[]
patterns <- channel.song.patterns
if channel.next_pattern_index >= patterns.size then
if channel.looping then
channel.next_pattern_index <- 0
else
channel.events <- null
drop
end if
end if
var pattern: song_pattern
pattern <- patterns[channel.next_pattern_index]
channel.samples_per_tick <- pattern.samples_per_tick
channel.events <- pattern.tracks[channel.track_index].events
channel.next_pattern_index <- channel.next_pattern_index + 1
channel.next_event_index <- 0
else
if channel.looping then
channel.next_event_index <- 0
else
channel.events <- null
drop
end if
end if
if channel.sync_data <> 0 then
new_audio_event <- queue.events[write_index]
new_audio_event.kind <- 9
new_audio_event.operand <- channel.sync_data
write_index <- to_byte(write_index + 1)
if write_index >= 100
do write_index <- 0
end if
end if
var track_event: track_event
track_event <- channel.events[channel.next_event_index]
channel.next_event_index <- channel.next_event_index + 1
var wait_time_samples: int
wait_time_samples <- channel.samples_per_tick * track_event.duration_ticks
var track_event_note: byte
track_event_note <- track_event.note
if track_event_note < 254 then
wait_time_samples <- wait_time_samples - 30
new_audio_event <- queue.events[write_index]
new_audio_event.kind <- 10
new_audio_event.operand <- 0
write_index <- to_byte(write_index + 1)
if write_index >= 100
do write_index <- 0
var instrument: io_instrument
instrument <- art::instruments[track_event.instrument]
if channel.instrument <> instrument then
channel.instrument <- instrument
wait_time_samples <- wait_time_samples - 30
new_audio_event <- queue.events[write_index]
new_audio_event.kind <- 0
new_audio_event.operand <- to_address(instrument)
write_index <- to_byte(write_index + 1)
if write_index >= 100
do write_index <- 0
end if
wait_time_samples <- wait_time_samples - 30
new_audio_event <- queue.events[write_index]
new_audio_event.kind <- 1
temp <- sound::_note_to_pitch[track_event_note]
temp <- math::bit_or(temp, math::shift_left(track_event.mod_byte, 20))
new_audio_event.operand <- temp
write_index <- to_byte(write_index + 1)
if write_index >= 100
do write_index <- 0
end if
wait_time_samples <- wait_time_samples - 30
new_audio_event <- queue.events[write_index]
new_audio_event.kind <- 8
new_audio_event.operand <- wait_time_samples
write_index <- to_byte(write_index + 1)
if write_index >= 100
do write_index <- 0
write_address <- to_address(queue.events[write_index])
end loop
channel.write_index <- write_index
queue.write_address <- write_address
end if
if write_address = read_address then
channel.is_playing <- false
else
channel.is_playing <- true
end if
end func
func is_playing(channel_index: int): bool
var channel: _sound_channel
if sound::_sound_channels = null then
return false
else
channel <- sound::_sound_channels[channel_index]
return channel.is_playing
end if
end func
func think()
if sound::_sound_channels = null
do return
var i: int
i <- 0
loop
sound::_process_channel(sound::_sound_channels[i],
| io::audio_queues[i])
i <- i + 1
if i >= 6
do drop
end loop
end func
end module
data sound::_note_to_pitch
[
19, 20, 21, 23, 24, 25, 27, 29, 30, 32,
34, 36, 38, 40, 43, 45, 48, 51, 54, 57,
60, 64, 68, 72, 76, 81, 85, 91, 96, 102,
108, 114, 121, 128, 136, 144, 152, 161, 171, 181,
192, 203, 215, 228, 242, 256, 271, 287, 304, 323,
342, 362, 384, 406, 431, 456, 483, 512, 542, 575,
609, 645, 683, 724, 767, 813, 861, 912, 967, 1024,
1085, 1149, 1218, 1290, 1367, 1448, 1534, 1625, 1722, 1825,
1933, 2048, 2170, 2299, 2435, 2580, 2734, 2896, 3069, 3251,
3444, 3649, 3866, 4096, 4340, 4598, 4871, 5161, 5468, 5793,
6137, 6502, 6889, 7298, 7732, 8192, 8679, 9195, 9742, 10321,
10935, 11585, 12274, 13004, 13777, 14596, 15464, 16384, 17358, 18390,
19484, 20643, 21870, 23170, 24548, 26008, 27554, 29193
]
end data