Skip to main content

render_note/
render_note.rs

1//! Render one note through an instrument plugin with the public API (reference for
2//! `ferraus-synth`'s `InstrumentSource::Plugin`).
3//!
4//! ```text
5//! cargo run -p ferraus-plugins --example render_note -- "<name, id, or bundle path>" out.wav [key] [param=value ...]
6//! ```
7
8use ferraus_plugins::{render_instrument_with, MidiEvent, PluginOptions, PluginRef};
9
10fn main() {
11    let args: Vec<String> = std::env::args().skip(1).collect();
12    if args.len() < 2 {
13        eprintln!("usage: render_note <plugin> <out.wav> [midi key] [param=value ...]");
14        std::process::exit(2);
15    }
16    let plugin = PluginRef::resolve(&args[0], &[]).unwrap_or_else(|e| {
17        eprintln!("{e}");
18        std::process::exit(e.exit_code)
19    });
20    let key: u8 = args.get(2).and_then(|k| k.parse().ok()).unwrap_or(60);
21    let params =
22        args.iter().skip(3).filter_map(|kv| kv.split_once('=').map(|(k, v)| (k.to_string(), v.to_string()))).collect();
23    let sr = 48000u32;
24    let events = [MidiEvent::note_on(sr as u64 / 10, 0, key, 0.8), MidiEvent::note_off(sr as u64, 0, key)];
25    let opts = PluginOptions { params, ..Default::default() };
26    match render_instrument_with(&plugin, &events, sr, 2.0, &opts) {
27        Ok(run) => {
28            let a = &run.audio;
29            let onset = a.data[0].iter().position(|v| v.abs() > 1e-4);
30            println!(
31                "{} ({}): {} frames, peak {:.3}, first sound at frame {:?} (note at {}), latency {}",
32                plugin.name,
33                plugin.format,
34                a.frames(),
35                a.peak(),
36                onset,
37                sr / 10,
38                run.latency
39            );
40            std::fs::write(&args[1], ferraus_core::wav::encode(a, 32, true).expect("encode")).expect("write");
41        }
42        Err(e) => {
43            eprintln!("{e}");
44            std::process::exit(e.exit_code);
45        }
46    }
47}