1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use atomic_float::AtomicF64;
use std::{
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc,
    },
    thread,
    time::{Duration, Instant},
};
use xsynth_core::{
    soundfont::{SampleSoundfont, SoundfontBase},
    AudioStreamParams, ChannelCount,
};
use xsynth_render::{xsynth_renderer, XSynthRenderConfig, XSynthRenderStats};

fn main() {
    let args = std::env::args().collect::<Vec<String>>();
    let (Some(midi), Some(sfz)) = (
        args.get(1)
            .cloned()
            .or_else(|| std::env::var("XSYNTH_EXAMPLE_MIDI").ok()),
        args.get(2)
            .cloned()
            .or_else(|| std::env::var("XSYNTH_EXAMPLE_SF").ok()),
    ) else {
        println!(
            "Usage: {} [midi] [sfz/sf2]",
            std::env::current_exe()
                .unwrap_or("example".into())
                .display()
        );
        return;
    };
    let out = "out.wav";

    println!("\n--- STARTING RENDER ---");

    let render_time = Instant::now();
    let position = Arc::new(AtomicF64::new(0.0));
    let voices = Arc::new(AtomicU64::new(0));

    let max_voices = Arc::new(AtomicU64::new(0));

    let callback = |stats: XSynthRenderStats| {
        position.store(stats.progress, Ordering::Relaxed);
        voices.store(stats.voice_count, Ordering::Relaxed);
        if stats.voice_count > max_voices.load(Ordering::Relaxed) {
            max_voices.store(stats.voice_count, Ordering::Relaxed);
        }
    };

    let position_thread = position.clone();
    let voices_thread = voices.clone();

    thread::spawn(move || loop {
        thread::sleep(Duration::from_millis(100));
        let pos = position_thread.load(Ordering::Relaxed);
        let time = Duration::from_secs_f64(pos);
        println!(
            "Progress: {:?}, Voice Count: {}",
            time,
            voices_thread.load(Ordering::Relaxed)
        );
    });

    let config: XSynthRenderConfig = Default::default();

    let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
        SampleSoundfont::new(
            sfz,
            AudioStreamParams::new(
                config.sample_rate,
                ChannelCount::from(config.audio_channels),
            ),
            config.sf_init_options,
        )
        .unwrap(),
    )];

    xsynth_renderer(&midi, out)
        .with_config(config)
        .add_soundfonts(soundfonts)
        .with_layer_count(Some(128))
        .with_progress_callback(callback)
        .run()
        .unwrap();

    println!("Render time: {} seconds", render_time.elapsed().as_secs());
}