103 lines
2.4 KiB
Plaintext
103 lines
2.4 KiB
Plaintext
/*
|
|
* MIDI Player - Command line tool
|
|
*
|
|
* Usage: cell run examples/player.ce <midi_file> <soundfont_file>
|
|
*/
|
|
|
|
var io = use('cellfs')
|
|
var audio = use('sokol/audio')
|
|
var midi = use('midi')
|
|
|
|
var blob = use('blob')
|
|
var os = use('os')
|
|
|
|
if (length(args) < 2) {
|
|
log.console("Usage: cell run examples/player.ce <midi_file> <soundfont_file>")
|
|
log.console("Example: cell run examples/player.ce invent8.mid harpsichord.sf2")
|
|
$stop()
|
|
}
|
|
|
|
var midi_file = args[0]
|
|
var sf_file = args[1]
|
|
|
|
log.console("Loading soundfont: " + sf_file)
|
|
var sf_blob = io.slurp(sf_file)
|
|
if (!sf_blob) {
|
|
log.console("Error: Could not load soundfont: " + sf_file)
|
|
$stop()
|
|
}
|
|
|
|
var soundfont = midi.Soundfont(sf_blob)
|
|
log.console("Soundfont loaded, " + text(soundfont.preset_count()) + " presets")
|
|
|
|
log.console("Loading MIDI: " + midi_file)
|
|
var midi_blob = io.slurp(midi_file)
|
|
if (!midi_blob) {
|
|
log.console("Error: Could not load MIDI file: " + midi_file)
|
|
$stop()
|
|
}
|
|
|
|
var song = midi.parse(midi_blob)
|
|
log.console("MIDI loaded: " + text(song.note_count) + " notes, " + text((song.duration_ms / 1000).toFixed(1)) + " seconds")
|
|
|
|
var player = midi.Player(soundfont, song)
|
|
|
|
// Setup audio with push model
|
|
var SAMPLE_RATE = 44100
|
|
var BUFFER_FRAMES = 1024
|
|
|
|
audio.setup({
|
|
sample_rate: SAMPLE_RATE,
|
|
num_channels: 2,
|
|
buffer_frames: BUFFER_FRAMES * 4
|
|
})
|
|
|
|
if (!audio.is_valid()) {
|
|
log.console("Error: Failed to initialize audio")
|
|
$stop()
|
|
}
|
|
|
|
log.console("Playing... Press Ctrl+C to stop")
|
|
log.console("Sample rate: " + text(audio.sample_rate()) + " Hz")
|
|
player.play()
|
|
|
|
// Audio pump - push samples to audio device
|
|
function pump() {
|
|
// Push audio when buffer has room
|
|
var expect = audio.expect()
|
|
while (expect >= BUFFER_FRAMES) {
|
|
var rendered = player.render(BUFFER_FRAMES)
|
|
if (rendered) {
|
|
audio.push(rendered)
|
|
}
|
|
expect = audio.expect()
|
|
}
|
|
|
|
// Check if done
|
|
if (!player.is_playing() && soundfont.active_voices() == 0) {
|
|
log.console("\nPlayback finished")
|
|
audio.shutdown()
|
|
soundfont.close()
|
|
$stop()
|
|
return
|
|
}
|
|
|
|
$delay(pump, 0.1) // ~200Hz pump rate
|
|
}
|
|
|
|
// Progress display
|
|
function progress() {
|
|
if (!player.is_playing() && soundfont.active_voices() == 0) {
|
|
return
|
|
}
|
|
|
|
var pos = player.position_ms() / 1000
|
|
var dur = player.duration_ms() / 1000
|
|
var pct = (pos / dur * 100).toFixed(0)
|
|
log.console(`\r${pos.toFixed(1)}s / ${dur.toFixed(1)}s (${pct}%) - ${soundfont.active_voices()} voices `, false)
|
|
$delay(progress, 0.1)
|
|
}
|
|
|
|
pump()
|
|
progress()
|