Struct xsynth_render::XSynthRenderBuilder
source · pub struct XSynthRenderBuilder<'a, StatsCallback: FnMut(XSynthRenderStats)> { /* private fields */ }
Expand description
Helper struct to create an XSynthRender object and render a MIDI file.
Initialize using the xsynth_renderer
function.
Implementations§
source§impl<'a, ProgressCallback: FnMut(XSynthRenderStats)> XSynthRenderBuilder<'a, ProgressCallback>
impl<'a, ProgressCallback: FnMut(XSynthRenderStats)> XSynthRenderBuilder<'a, ProgressCallback>
pub fn with_config(self, config: XSynthRenderConfig) -> Self
pub fn with_channel_count(self, channels: u32) -> Self
pub fn with_parallelism(self, options: ParallelismOptions) -> Self
sourcepub fn use_limiter(self, use_limiter: bool) -> Self
pub fn use_limiter(self, use_limiter: bool) -> Self
Examples found in repository?
examples/render_dialog.rs (line 112)
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
println!("--- FILE PATHS ---");
let midi_path = read_input("Enter MIDI path");
let sf_path = read_input("Enter SFZ/SF2 path");
let out_path = read_input("Enter output path");
println!("\n--- RENDER OPTIONS ---");
let sample_rate: u32 = read_input("Enter sample rate (in Hz)").parse().unwrap();
let use_threadpool = read_input_bool("Use threadpool? (y/n)");
let use_limiter = read_input_bool("Use audio limiter? (y/n)");
let layers = match read_input("Enter layer count").parse::<usize>().unwrap() {
0 => None,
voices => Some(voices),
};
io::stdout().lock().flush().unwrap();
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();
let length = get_midi_length(&midi_path);
thread::spawn(move || loop {
let pos = position_thread.load(Ordering::Relaxed);
let progress = (pos / length) * 100.0 + 0.0004;
print!("\rProgress: [");
let bars = progress as u8 / 5;
for _ in 0..bars {
print!("=");
}
for _ in 0..(20 - bars) {
print!(" ");
}
print!("] {progress:.3}% | ");
print!("Voice Count: {}", voices_thread.load(Ordering::Relaxed));
if progress >= 100.0 {
break;
}
});
let config = XSynthRenderConfig {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(sample_rate, 2.into()),
parallelism: if use_threadpool {
Default::default()
} else {
ParallelismOptions {
channel: ThreadCount::None,
key: ThreadCount::None,
}
},
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(
sf_path,
config.group_options.audio_params,
Default::default(),
)
.unwrap(),
)];
xsynth_renderer(config, &midi_path, &out_path)
.use_limiter(use_limiter)
.add_soundfonts(soundfonts)
.with_layer_count(layers)
.with_progress_callback(callback)
.run()
.unwrap();
println!(
"\n\n--- RENDER FINISHED ---\nRender time: {} seconds | Max Voice Count: {} voices",
render_time.elapsed().as_secs(),
max_voices.load(Ordering::Relaxed)
);
pause();
}
pub fn with_sample_rate(self, sample_rate: u32) -> Self
pub fn with_audio_channels(self, audio_channels: u16) -> Self
sourcepub fn _with_audio_format(self, audio_format: XSynthRenderAudioFormat) -> Self
pub fn _with_audio_format(self, audio_format: XSynthRenderAudioFormat) -> Self
Unused because only WAV is supported
sourcepub fn with_layer_count(self, layers: Option<usize>) -> Self
pub fn with_layer_count(self, layers: Option<usize>) -> Self
Examples found in repository?
examples/render.rs (line 87)
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 90 91 92 93
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 {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(48000, 2.into()),
parallelism: Default::default(),
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(sfz, config.group_options.audio_params, Default::default()).unwrap(),
)];
xsynth_renderer(config, &midi, out)
.add_soundfonts(soundfonts)
.with_layer_count(Some(128))
.with_progress_callback(callback)
.run()
.unwrap();
println!("Render time: {} seconds", render_time.elapsed().as_secs());
}
More examples
examples/render_dialog.rs (line 114)
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
println!("--- FILE PATHS ---");
let midi_path = read_input("Enter MIDI path");
let sf_path = read_input("Enter SFZ/SF2 path");
let out_path = read_input("Enter output path");
println!("\n--- RENDER OPTIONS ---");
let sample_rate: u32 = read_input("Enter sample rate (in Hz)").parse().unwrap();
let use_threadpool = read_input_bool("Use threadpool? (y/n)");
let use_limiter = read_input_bool("Use audio limiter? (y/n)");
let layers = match read_input("Enter layer count").parse::<usize>().unwrap() {
0 => None,
voices => Some(voices),
};
io::stdout().lock().flush().unwrap();
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();
let length = get_midi_length(&midi_path);
thread::spawn(move || loop {
let pos = position_thread.load(Ordering::Relaxed);
let progress = (pos / length) * 100.0 + 0.0004;
print!("\rProgress: [");
let bars = progress as u8 / 5;
for _ in 0..bars {
print!("=");
}
for _ in 0..(20 - bars) {
print!(" ");
}
print!("] {progress:.3}% | ");
print!("Voice Count: {}", voices_thread.load(Ordering::Relaxed));
if progress >= 100.0 {
break;
}
});
let config = XSynthRenderConfig {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(sample_rate, 2.into()),
parallelism: if use_threadpool {
Default::default()
} else {
ParallelismOptions {
channel: ThreadCount::None,
key: ThreadCount::None,
}
},
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(
sf_path,
config.group_options.audio_params,
Default::default(),
)
.unwrap(),
)];
xsynth_renderer(config, &midi_path, &out_path)
.use_limiter(use_limiter)
.add_soundfonts(soundfonts)
.with_layer_count(layers)
.with_progress_callback(callback)
.run()
.unwrap();
println!(
"\n\n--- RENDER FINISHED ---\nRender time: {} seconds | Max Voice Count: {} voices",
render_time.elapsed().as_secs(),
max_voices.load(Ordering::Relaxed)
);
pause();
}
sourcepub fn add_soundfonts(self, soundfonts: Vec<Arc<dyn SoundfontBase>>) -> Self
pub fn add_soundfonts(self, soundfonts: Vec<Arc<dyn SoundfontBase>>) -> Self
Examples found in repository?
examples/render.rs (line 86)
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 90 91 92 93
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 {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(48000, 2.into()),
parallelism: Default::default(),
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(sfz, config.group_options.audio_params, Default::default()).unwrap(),
)];
xsynth_renderer(config, &midi, out)
.add_soundfonts(soundfonts)
.with_layer_count(Some(128))
.with_progress_callback(callback)
.run()
.unwrap();
println!("Render time: {} seconds", render_time.elapsed().as_secs());
}
More examples
examples/render_dialog.rs (line 113)
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
println!("--- FILE PATHS ---");
let midi_path = read_input("Enter MIDI path");
let sf_path = read_input("Enter SFZ/SF2 path");
let out_path = read_input("Enter output path");
println!("\n--- RENDER OPTIONS ---");
let sample_rate: u32 = read_input("Enter sample rate (in Hz)").parse().unwrap();
let use_threadpool = read_input_bool("Use threadpool? (y/n)");
let use_limiter = read_input_bool("Use audio limiter? (y/n)");
let layers = match read_input("Enter layer count").parse::<usize>().unwrap() {
0 => None,
voices => Some(voices),
};
io::stdout().lock().flush().unwrap();
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();
let length = get_midi_length(&midi_path);
thread::spawn(move || loop {
let pos = position_thread.load(Ordering::Relaxed);
let progress = (pos / length) * 100.0 + 0.0004;
print!("\rProgress: [");
let bars = progress as u8 / 5;
for _ in 0..bars {
print!("=");
}
for _ in 0..(20 - bars) {
print!(" ");
}
print!("] {progress:.3}% | ");
print!("Voice Count: {}", voices_thread.load(Ordering::Relaxed));
if progress >= 100.0 {
break;
}
});
let config = XSynthRenderConfig {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(sample_rate, 2.into()),
parallelism: if use_threadpool {
Default::default()
} else {
ParallelismOptions {
channel: ThreadCount::None,
key: ThreadCount::None,
}
},
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(
sf_path,
config.group_options.audio_params,
Default::default(),
)
.unwrap(),
)];
xsynth_renderer(config, &midi_path, &out_path)
.use_limiter(use_limiter)
.add_soundfonts(soundfonts)
.with_layer_count(layers)
.with_progress_callback(callback)
.run()
.unwrap();
println!(
"\n\n--- RENDER FINISHED ---\nRender time: {} seconds | Max Voice Count: {} voices",
render_time.elapsed().as_secs(),
max_voices.load(Ordering::Relaxed)
);
pause();
}
sourcepub fn with_progress_callback<F: FnMut(XSynthRenderStats)>(
self,
stats_callback: F,
) -> XSynthRenderBuilder<'a, F>
pub fn with_progress_callback<F: FnMut(XSynthRenderStats)>( self, stats_callback: F, ) -> XSynthRenderBuilder<'a, F>
Sets a callback function to be used to update the render statistics.
Examples found in repository?
examples/render.rs (line 88)
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 90 91 92 93
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 {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(48000, 2.into()),
parallelism: Default::default(),
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(sfz, config.group_options.audio_params, Default::default()).unwrap(),
)];
xsynth_renderer(config, &midi, out)
.add_soundfonts(soundfonts)
.with_layer_count(Some(128))
.with_progress_callback(callback)
.run()
.unwrap();
println!("Render time: {} seconds", render_time.elapsed().as_secs());
}
More examples
examples/render_dialog.rs (line 115)
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
println!("--- FILE PATHS ---");
let midi_path = read_input("Enter MIDI path");
let sf_path = read_input("Enter SFZ/SF2 path");
let out_path = read_input("Enter output path");
println!("\n--- RENDER OPTIONS ---");
let sample_rate: u32 = read_input("Enter sample rate (in Hz)").parse().unwrap();
let use_threadpool = read_input_bool("Use threadpool? (y/n)");
let use_limiter = read_input_bool("Use audio limiter? (y/n)");
let layers = match read_input("Enter layer count").parse::<usize>().unwrap() {
0 => None,
voices => Some(voices),
};
io::stdout().lock().flush().unwrap();
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();
let length = get_midi_length(&midi_path);
thread::spawn(move || loop {
let pos = position_thread.load(Ordering::Relaxed);
let progress = (pos / length) * 100.0 + 0.0004;
print!("\rProgress: [");
let bars = progress as u8 / 5;
for _ in 0..bars {
print!("=");
}
for _ in 0..(20 - bars) {
print!(" ");
}
print!("] {progress:.3}% | ");
print!("Voice Count: {}", voices_thread.load(Ordering::Relaxed));
if progress >= 100.0 {
break;
}
});
let config = XSynthRenderConfig {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(sample_rate, 2.into()),
parallelism: if use_threadpool {
Default::default()
} else {
ParallelismOptions {
channel: ThreadCount::None,
key: ThreadCount::None,
}
},
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(
sf_path,
config.group_options.audio_params,
Default::default(),
)
.unwrap(),
)];
xsynth_renderer(config, &midi_path, &out_path)
.use_limiter(use_limiter)
.add_soundfonts(soundfonts)
.with_layer_count(layers)
.with_progress_callback(callback)
.run()
.unwrap();
println!(
"\n\n--- RENDER FINISHED ---\nRender time: {} seconds | Max Voice Count: {} voices",
render_time.elapsed().as_secs(),
max_voices.load(Ordering::Relaxed)
);
pause();
}
sourcepub fn run(self) -> Result<(), XSynthRenderError>
pub fn run(self) -> Result<(), XSynthRenderError>
Examples found in repository?
examples/render.rs (line 89)
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 90 91 92 93
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 {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(48000, 2.into()),
parallelism: Default::default(),
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(sfz, config.group_options.audio_params, Default::default()).unwrap(),
)];
xsynth_renderer(config, &midi, out)
.add_soundfonts(soundfonts)
.with_layer_count(Some(128))
.with_progress_callback(callback)
.run()
.unwrap();
println!("Render time: {} seconds", render_time.elapsed().as_secs());
}
More examples
examples/render_dialog.rs (line 116)
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
println!("--- FILE PATHS ---");
let midi_path = read_input("Enter MIDI path");
let sf_path = read_input("Enter SFZ/SF2 path");
let out_path = read_input("Enter output path");
println!("\n--- RENDER OPTIONS ---");
let sample_rate: u32 = read_input("Enter sample rate (in Hz)").parse().unwrap();
let use_threadpool = read_input_bool("Use threadpool? (y/n)");
let use_limiter = read_input_bool("Use audio limiter? (y/n)");
let layers = match read_input("Enter layer count").parse::<usize>().unwrap() {
0 => None,
voices => Some(voices),
};
io::stdout().lock().flush().unwrap();
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();
let length = get_midi_length(&midi_path);
thread::spawn(move || loop {
let pos = position_thread.load(Ordering::Relaxed);
let progress = (pos / length) * 100.0 + 0.0004;
print!("\rProgress: [");
let bars = progress as u8 / 5;
for _ in 0..bars {
print!("=");
}
for _ in 0..(20 - bars) {
print!(" ");
}
print!("] {progress:.3}% | ");
print!("Voice Count: {}", voices_thread.load(Ordering::Relaxed));
if progress >= 100.0 {
break;
}
});
let config = XSynthRenderConfig {
group_options: ChannelGroupConfig {
channel_init_options: Default::default(),
channel_count: 16,
drums_channels: vec![9],
audio_params: AudioStreamParams::new(sample_rate, 2.into()),
parallelism: if use_threadpool {
Default::default()
} else {
ParallelismOptions {
channel: ThreadCount::None,
key: ThreadCount::None,
}
},
},
use_limiter: true,
audio_format: XSynthRenderAudioFormat::Wav,
};
let soundfonts: Vec<Arc<dyn SoundfontBase>> = vec![Arc::new(
SampleSoundfont::new(
sf_path,
config.group_options.audio_params,
Default::default(),
)
.unwrap(),
)];
xsynth_renderer(config, &midi_path, &out_path)
.use_limiter(use_limiter)
.add_soundfonts(soundfonts)
.with_layer_count(layers)
.with_progress_callback(callback)
.run()
.unwrap();
println!(
"\n\n--- RENDER FINISHED ---\nRender time: {} seconds | Max Voice Count: {} voices",
render_time.elapsed().as_secs(),
max_voices.load(Ordering::Relaxed)
);
pause();
}
Auto Trait Implementations§
impl<'a, StatsCallback> Freeze for XSynthRenderBuilder<'a, StatsCallback>where
StatsCallback: Freeze,
impl<'a, StatsCallback> !RefUnwindSafe for XSynthRenderBuilder<'a, StatsCallback>
impl<'a, StatsCallback> Send for XSynthRenderBuilder<'a, StatsCallback>where
StatsCallback: Send,
impl<'a, StatsCallback> Sync for XSynthRenderBuilder<'a, StatsCallback>where
StatsCallback: Sync,
impl<'a, StatsCallback> Unpin for XSynthRenderBuilder<'a, StatsCallback>where
StatsCallback: Unpin,
impl<'a, StatsCallback> !UnwindSafe for XSynthRenderBuilder<'a, StatsCallback>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more