Files
cell-midi/examples/player.ce
2026-01-18 11:23:41 -06:00

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()