/* * MIDI Player - Command line tool * * Usage: cell run examples/player.ce */ 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 ") 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)) + " 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() var rendered = null while (expect >= BUFFER_FRAMES) { rendered = player.render(BUFFER_FRAMES) if (rendered) { audio[] = 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 = text(pos / dur * 100) log.console(`\r${text(pos)}s / ${dur}s (${pct}%) - ${soundfont.active_voices()} voices `, false) $delay(progress, 0.1) } pump() progress()