Skip to content

Commit 0d1d11d

Browse files
Add ability to modify buffer window and ignore range in realtime synth (#105)
1 parent 076b930 commit 0d1d11d

File tree

8 files changed

+91
-34
lines changed

8 files changed

+91
-34
lines changed

clib/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![allow(clippy::missing_safety_doc)]
22
#![allow(clippy::result_unit_err)]
3+
#![allow(clippy::too_long_first_doc_paragraph)]
34

45
pub mod consts;
56
pub mod group;
@@ -45,3 +46,12 @@ pub extern "C" fn XSynth_GenDefault_StreamParams() -> XSynth_StreamParams {
4546
audio_channels: XSYNTH_AUDIO_CHANNELS_STEREO,
4647
}
4748
}
49+
50+
/// A helper struct to specify a range of bytes.
51+
/// - start: The start of the range
52+
/// - end: The end of the range
53+
#[repr(C)]
54+
pub struct XSynth_ByteRange {
55+
pub start: u8,
56+
pub end: u8,
57+
}

clib/src/realtime.rs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{handles::*, utils::*, XSynth_StreamParams};
1+
use crate::{handles::*, utils::*, XSynth_ByteRange, XSynth_StreamParams};
22
use xsynth_core::{
33
channel::{ChannelConfigEvent, ChannelEvent, ChannelInitOptions},
44
channel_group::SynthEvent,
@@ -17,14 +17,14 @@ use xsynth_realtime::{RealtimeSynth, XSynthRealtimeConfig};
1717
/// usually causing clicking but improving performance.
1818
/// - render_window_ms: The length of the buffer reader in ms
1919
/// - ignore_range: A range of velocities that will not be played
20-
/// LOBYTE = start (0-127), HIBYTE = end (start-127)
20+
/// (see XSynth_ByteRange)
2121
#[repr(C)]
2222
pub struct XSynth_RealtimeConfig {
2323
pub channels: u32,
2424
pub multithreading: i32,
2525
pub fade_out_killing: bool,
2626
pub render_window_ms: f64,
27-
pub ignore_range: u16,
27+
pub ignore_range: XSynth_ByteRange,
2828
}
2929

3030
/// Generates the default values for the XSynth_RealtimeConfig struct
@@ -41,7 +41,7 @@ pub extern "C" fn XSynth_GenDefault_RealtimeConfig() -> XSynth_RealtimeConfig {
4141
multithreading: -1,
4242
fade_out_killing: false,
4343
render_window_ms: 10.0,
44-
ignore_range: 0,
44+
ignore_range: XSynth_ByteRange { start: 0, end: 0 },
4545
}
4646
}
4747

@@ -72,18 +72,12 @@ pub extern "C" fn XSynth_Realtime_Create(config: XSynth_RealtimeConfig) -> XSynt
7272
fade_out_killing: config.fade_out_killing,
7373
};
7474

75-
let ignore_range = {
76-
let low = (config.ignore_range & 255) as u8;
77-
let high = (config.ignore_range >> 8) as u8;
78-
low..=high
79-
};
80-
8175
let options = XSynthRealtimeConfig {
8276
channel_init_options,
8377
render_window_ms: config.render_window_ms,
8478
format: convert_synth_format(config.channels),
8579
multithreading: convert_threadcount(config.multithreading),
86-
ignore_range,
80+
ignore_range: config.ignore_range.start..=config.ignore_range.end,
8781
};
8882

8983
let new = RealtimeSynth::open_with_default_output(options);
@@ -169,6 +163,32 @@ pub extern "C" fn XSynth_Realtime_SendConfigEventAll(
169163
}
170164
}
171165

166+
/// Sets the length of the buffer reader to the desired value in ms.
167+
///
168+
/// --Parameters--
169+
/// - handle: The handle of the realtime synthesizer instance
170+
/// - render_window_ms: The length of the buffer reader in ms
171+
#[no_mangle]
172+
pub extern "C" fn XSynth_Realtime_SetBuffer(handle: XSynth_RealtimeSynth, render_window_ms: f64) {
173+
handle.as_ref().set_buffer(render_window_ms);
174+
}
175+
176+
/// Sets the range of velocities that will be ignored.
177+
///
178+
/// --Parameters--
179+
/// - handle: The handle of the realtime synthesizer instance
180+
/// - ignore_range: The range. LOBYTE = start (0-127), HIBYTE = end (start-127)
181+
#[no_mangle]
182+
pub extern "C" fn XSynth_Realtime_SetIgnoreRange(
183+
handle: XSynth_RealtimeSynth,
184+
ignore_range: XSynth_ByteRange,
185+
) {
186+
handle
187+
.as_mut()
188+
.get_sender_mut()
189+
.set_ignore_range(ignore_range.start..=ignore_range.end);
190+
}
191+
172192
/// Sets a list of soundfonts to be used in the specified realtime synth
173193
/// instance. To load a new soundfont, see the XSynth_Soundfont_LoadNew
174194
/// function.
@@ -248,7 +268,7 @@ pub extern "C" fn XSynth_Realtime_GetStats(handle: XSynth_RealtimeSynth) -> XSyn
248268
/// - handle: The handle of the realtime synthesizer instance
249269
#[no_mangle]
250270
pub extern "C" fn XSynth_Realtime_Reset(handle: XSynth_RealtimeSynth) {
251-
handle.as_ref().get_senders().reset_synth();
271+
handle.as_mut().get_sender_mut().reset_synth();
252272
}
253273

254274
/// Drops the specified realtime synth instance.

core/src/effects/limiter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl VolumeLimiter {
7676
&'a mut self,
7777
samples: T,
7878
) -> VolumeLimiterIter<'a, 'b, T> {
79-
impl<'a, 'b, T: 'b + Iterator<Item = f32>> Iterator for VolumeLimiterIter<'a, 'b, T> {
79+
impl<'b, T: 'b + Iterator<Item = f32>> Iterator for VolumeLimiterIter<'_, 'b, T> {
8080
type Item = f32;
8181

8282
fn next(&mut self) -> Option<Self::Item> {

kdmapi/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![allow(non_snake_case)]
2+
#![allow(static_mut_refs)]
23

34
use hotwatch::{Event, EventKind, Hotwatch};
45
use std::{
@@ -59,7 +60,7 @@ pub extern "C" fn InitializeKDMAPIStream() -> i32 {
5960
let sflist = Config::<SFList>::new().load().unwrap();
6061

6162
let realtime_synth = RealtimeSynth::open_with_default_output(config.get_synth_config());
62-
let mut sender = realtime_synth.get_senders();
63+
let mut sender = realtime_synth.get_sender_ref().clone();
6364
let params = realtime_synth.stream_params();
6465

6566
sender.send_event(SynthEvent::AllChannels(ChannelEvent::Config(

realtime/examples/midi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn main() {
3939
};
4040

4141
let synth = RealtimeSynth::open_with_all_defaults();
42-
let mut sender = synth.get_senders();
42+
let mut sender = synth.get_sender_ref().clone();
4343

4444
let params = synth.stream_params();
4545

realtime/src/event_senders.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,11 @@ impl EventSender {
148148
return;
149149
}
150150

151-
let in_ignore_range = self.ignore_range.contains(vel);
152-
153151
let nps = self.nps.calculate_nps();
154-
if should_send_for_vel_and_nps(*vel, nps, self.max_nps.read()) && !in_ignore_range {
152+
153+
if should_send_for_vel_and_nps(*vel, nps, self.max_nps.read())
154+
&& !self.ignore_range.contains(vel)
155+
{
155156
self.sender.send(ChannelEvent::Audio(event)).ok();
156157
self.nps.add_note();
157158
} else {
@@ -179,16 +180,9 @@ impl EventSender {
179180
self.sender.send(ChannelEvent::Config(event)).ok();
180181
}
181182

182-
// pub fn send(&mut self, event: ChannelEvent) {
183-
// match event {
184-
// ChannelEvent::Audio(event) => {
185-
// self.send_audio(event);
186-
// }
187-
// ChannelEvent::Config(event) => {
188-
// self.send_config(event);
189-
// }
190-
// }
191-
// }
183+
pub fn set_ignore_range(&mut self, ignore_range: RangeInclusive<u8>) {
184+
self.ignore_range = ignore_range;
185+
}
192186
}
193187

194188
impl Clone for EventSender {
@@ -333,4 +327,12 @@ impl RealtimeEventSender {
333327
ChannelAudioEvent::ResetControl,
334328
)));
335329
}
330+
331+
/// Changes the range of velocities that will be ignored for the
332+
/// specific sender instance.
333+
pub fn set_ignore_range(&mut self, ignore_range: RangeInclusive<u8>) {
334+
for sender in self.senders.iter_mut() {
335+
sender.set_ignore_range(ignore_range.clone());
336+
}
337+
}
336338
}

realtime/src/realtime_synth.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ impl RealtimeSynth {
227227
let buffered = Arc::new(Mutex::new(BufferedRenderer::new(
228228
render,
229229
stream_params,
230-
(sample_rate as f64 * config.render_window_ms / 1000.0) as usize,
230+
calculate_render_size(sample_rate, config.render_window_ms),
231231
)));
232232

233233
fn build_stream<T: SizedSample + ConvertSample>(
@@ -289,13 +289,25 @@ impl RealtimeSynth {
289289
data.event_senders.send_event(event);
290290
}
291291

292-
/// Returns the event sender of the realtime synthesizer.
292+
/// Returns a reference to the event sender of the realtime synthesizer.
293+
/// This can be used to clone the sender so it can be passed in threads.
293294
///
294295
/// See the `RealtimeEventSender` documentation for more information
295296
/// on how to use.
296-
pub fn get_senders(&self) -> RealtimeEventSender {
297+
pub fn get_sender_ref(&self) -> &RealtimeEventSender {
297298
let data = self.data.as_ref().unwrap();
298-
data.event_senders.clone()
299+
&data.event_senders
300+
}
301+
302+
/// Returns a mutable reference the event sender of the realtime synthesizer.
303+
/// This can be used to modify its parameters (eg. ignore range).
304+
/// Please note that each clone will store its own distinct parameters.
305+
///
306+
/// See the `RealtimeEventSender` documentation for more information
307+
/// on how to use.
308+
pub fn get_sender_mut(&mut self) -> &mut RealtimeEventSender {
309+
let data = self.data.as_mut().unwrap();
310+
&mut data.event_senders
299311
}
300312

301313
/// Returns the statistics reader of the realtime synthesizer.
@@ -325,6 +337,14 @@ impl RealtimeSynth {
325337
let data = self.data.as_mut().unwrap();
326338
data.stream.play()
327339
}
340+
341+
/// Changes the length of the buffer reader.
342+
pub fn set_buffer(&self, render_window_ms: f64) {
343+
let data = self.data.as_ref().unwrap();
344+
let sample_rate = self.stream_params.sample_rate;
345+
let size = calculate_render_size(sample_rate, render_window_ms);
346+
data.buffered_renderer.lock().unwrap().set_render_size(size);
347+
}
328348
}
329349

330350
impl Drop for RealtimeSynth {
@@ -359,3 +379,7 @@ impl ConvertSample for u16 {
359379
((s * u16::MAX as f32) as i32 + i16::MIN as i32) as u16
360380
}
361381
}
382+
383+
fn calculate_render_size(sample_rate: u32, buffer_ms: f64) -> usize {
384+
(sample_rate as f64 * buffer_ms / 1000.0) as usize
385+
}

soundfonts/src/sfz/grammar/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ bnf! {
5959
impl<'a> OpcodeValue<'a> {
6060
pub fn as_string(&self) -> Cow<'a, str> {
6161
if self.rest.is_empty() {
62-
return Cow::Borrowed(self.first.value.text.text);
62+
Cow::Borrowed(self.first.value.text.text)
6363
} else {
6464
let mut result = String::from(self.first.value.text.text);
6565
for part in self.rest.iter() {
6666
result.push_str(part.value.text.text);
6767
}
68-
return Cow::Owned(result);
68+
Cow::Owned(result)
6969
}
7070
}
7171
}

0 commit comments

Comments
 (0)