Skip to content

Quick Start

Rodrigo Agurto edited this page May 30, 2026 · 2 revisions

Quick Start

Minimum

use verovio::Toolkit;

let mut tk = Toolkit::new();
tk.load_data(
    "@start:demo\n@clef:G-2\n@keysig:xF\n@key:\n@timesig:\n@data:'4G/4-\n@end:demo\n",
)?;

for page in 1..=tk.page_count() {
    let svg = tk.render_to_svg(page)?;
    std::fs::write(format!("page-{page}.svg"), svg)?;
}
# Ok::<(), verovio::Error>(())

Load formats

Verovio auto-detects MEI, MusicXML, ABC, and PAE from content:

let mei = std::fs::read_to_string("score.mei")?;
let mut tk = verovio::Toolkit::from_data(&mei)?;
// from_file / load_file delegate to Verovio's upstream loader, so
// UTF-16 MusicXML and compressed .mxl archives work transparently.
let mut tk = verovio::Toolkit::from_file("score.musicxml")?;
// .mxl bytes in memory (e.g. downloaded from a URL):
let mxl_bytes = std::fs::read("score.mxl")?;
let mut tk = verovio::Toolkit::new();
tk.load_zip_data_buffer(&mxl_bytes)?;

Force a specific input format when auto-detect is ambiguous (rare, but happens with bare PAE):

tk.set_input_from("pae")?;
tk.load_data("@clef:G-2\n@keysig:\n@timesig:4/4\n@data:'4C")?;

Render

Output Method Feature
SVG (per page) tk.render_to_svg(page)
SVG (writer) tk.render_to_svg_writer(page, &mut w)
SVG (measure-range) tk.render_svg_measure_range(from, to, "\n")
PNG tk.render_to_png(page, scale) png
PNG (all pages) tk.render_to_png_all_pages(scale) png
PDF (per page) tk.render_to_pdf(page) pdf
PDF (multi-page) tk.render_to_pdf_all_pages() pdf
MIDI (SMF bytes) tk.render_to_midi_bytes()
MIDI + policy tk.render_to_midi_bytes_with_policy(&policy)
MIDI (writer) tk.render_to_midi_writer(&mut w)
WAV (offline) tk.render_to_wav(&sf2_bytes, sample_rate) audio
Timemap (typed) tk.timemap()Vec<TimemapEvent>
MEI export tk.to_mei() / tk.to_mei_with_options(&MeiOptions)
PAE export tk.render_to_pae()

Convert formats

Loading any supported format and exporting to MEI gives you the canonical "save as MEI" pipeline. MusicXML → MEI, ABC → MEI, PAE → MEI all work the same way:

let mut tk = verovio::Toolkit::from_file("score.musicxml")?;
let mei = tk.to_mei()?;            // score-based, all pages, IDs preserved
std::fs::write("score.mei", mei)?;

For MEI-Basic output or page-scoped export, use the typed options:

use verovio::MeiOptions;
let basic = tk.to_mei_with_options(&MeiOptions {
    basic: true,           // MEI-Basic subset
    remove_ids: true,      // strip Verovio-added @xml:id attributes
    ..Default::default()   // score_based: true (matches upstream)
})?;

Inspect

let md = tk.metadata()?;            // title / composer / instruments
let measures = tk.measures()?;      // (id, start_ms, end_ms, qfrac)
let bboxes = tk.bbox_map()?;        // id -> pixel rect for hit testing
let tempo = tk.tempo_map()?;        // TempoChange list with qstamp↔ms
let timemap = tk.timemap()?;        // playback sync source of truth

See Score Reading for the full query surface.

Playback queries (cache-aware, ~100× faster than re-entering Verovio)

use verovio::lookup::{sounding_at, PlaybackCursor};

let timemap = tk.timemap()?;             // one FFI + JSON parse
let mut cursor = PlaybackCursor::new(&timemap);

for tick_ms in playback_clock() {
    let active = cursor.advance_to(tick_ms);
    // …update UI / driver from `active` (sorted ids)
}
# Ok::<(), verovio::Error>(())

See Score Reading for LoopCursor, chord_at, note_duration, events_in_range, etc.

Buffer reuse

Every allocating method has an _into variant that writes into a caller-owned buffer:

let mut svg_buf = String::new();
for page in 1..=tk.page_count() {
    tk.render_to_svg_into(page, &mut svg_buf)?;
    std::fs::write(format!("page-{page}.svg"), &svg_buf)?;
}

The C++ side still allocates a std::string per render (Verovio has no streaming overload upstream), but the Rust-side String reuses its capacity.

Clone this wiki locally