87 lines
1.9 KiB
Plaintext
87 lines
1.9 KiB
Plaintext
/*
|
|
* sound.cm - Audio playback system for Prosperon
|
|
*
|
|
* Uses the soundwave package for audio decoding and mixing,
|
|
* and routes output to SDL audio.
|
|
*
|
|
* USAGE:
|
|
* var audio = use('sound')
|
|
* var voice = audio.play("mysound.mp3")
|
|
* voice.loop = true
|
|
* voice.vol = 0.5
|
|
* voice.stopped = true // stop it
|
|
*/
|
|
|
|
var io = use('cellfs')
|
|
var res = use('resources')
|
|
var soundwave = use('soundwave/soundwave')
|
|
var sdl_audio = use('sdl3/audio')
|
|
|
|
var audio = {}
|
|
|
|
// Output format constants
|
|
var OUTPUT_RATE = 44100
|
|
var OUTPUT_CHANNELS = 2
|
|
var FRAMES_PER_CHUNK = 1024
|
|
var BYTES_PER_SAMPLE = 4 // f32
|
|
var CHUNK_BYTES = FRAMES_PER_CHUNK * OUTPUT_CHANNELS * BYTES_PER_SAMPLE
|
|
|
|
// Create the audio player instance
|
|
var player = soundwave.create({
|
|
sample_rate: OUTPUT_RATE,
|
|
channels: OUTPUT_CHANNELS,
|
|
frames_per_chunk: FRAMES_PER_CHUNK
|
|
})
|
|
|
|
// Load and cache PCM data from a file path
|
|
audio.pcm = function pcm(file) {
|
|
file = res.find_sound(file)
|
|
if (!file) return null
|
|
|
|
// Check player's cache first
|
|
if (player.pcm_cache[file]) return player.pcm_cache[file]
|
|
|
|
var buf = io.slurp(file)
|
|
if (!buf) return null
|
|
|
|
return player.decode(buf, file)
|
|
}
|
|
|
|
// Play a sound file, returns voice object
|
|
audio.play = function play(file, opts) {
|
|
var pcm_data = audio.pcm(file)
|
|
if (!pcm_data) return null
|
|
|
|
return player.play(pcm_data, opts)
|
|
}
|
|
|
|
// Convenience: play and return stop function
|
|
audio.cry = function cry(file) {
|
|
var v = audio.play(file)
|
|
if (!v) return null
|
|
return function() { v.stopped = true }
|
|
}
|
|
|
|
// Get number of active voices
|
|
audio.voice_count = function() {
|
|
return player.voice_count()
|
|
}
|
|
|
|
// SDL audio stream setup
|
|
var feeder = sdl_audio.open_stream("playback")
|
|
feeder.resume_device()
|
|
|
|
// Audio pump - called periodically to fill the audio buffer
|
|
function pump() {
|
|
while (feeder.queued() < CHUNK_BYTES * 3) {
|
|
var mixed = player.pull(FRAMES_PER_CHUNK)
|
|
feeder.put(mixed)
|
|
}
|
|
|
|
$delay(pump, 1/240)
|
|
}
|
|
|
|
pump()
|
|
|
|
return audio
|