summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs53
-rw-r--r--src/midi_input.rs2
-rw-r--r--src/soundfont.rs13
3 files changed, 48 insertions, 20 deletions
diff --git a/src/main.rs b/src/main.rs
index de6da99..20b40b7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -185,13 +185,13 @@ impl WavRecording {
}
}
- fn write(&mut self, samples: &[i16]) {
+ fn write(&mut self, samples: &[f32]) {
if samples.len() + self.data.len() > (u32::MAX / 2 - 100) as usize {
// too much data for wav file
return;
}
for x in samples {
- self.data.push(*x);
+ self.data.push(((*x) * 32767.0) as i16);
}
}
@@ -316,22 +316,46 @@ fn get_audio_stream() -> Result<(cpal::Stream, u32), String> {
.supported_output_configs()
.expect("error while querying configs");
let mut chosen_config = None;
- let srate = 44100;
+
+ // get audio configuration with 2-channel float audio,
+ // and as close to 44100Hz sample rate as possible.
+ let desired_srate = 44100;
+ let best_dist = u32::MAX;
for config in supported_configs {
if config.channels() != 2
- || config.sample_format() != cpal::SampleFormat::I16
- || config.min_sample_rate().0 > srate
- || config.max_sample_rate().0 < srate
- {
+ || config.sample_format() != cpal::SampleFormat::F32 {
continue;
}
- chosen_config = Some(config);
+ let min_srate = config.min_sample_rate().0;
+ let max_srate = config.max_sample_rate().0;
+ let dist = if min_srate > desired_srate {
+ min_srate - desired_srate
+ } else if max_srate < desired_srate {
+ desired_srate - max_srate
+ } else {
+ 0
+ };
+ if dist < best_dist {
+ chosen_config = Some(config);
+ }
}
let chosen_config = match chosen_config {
None => return Err("Couldn't get desired audio properties.".to_string()),
Some(x) => x,
};
-
+
+ let srate = {
+ let min_srate = chosen_config.min_sample_rate().0;
+ let max_srate = chosen_config.max_sample_rate().0;
+ if min_srate > desired_srate {
+ min_srate
+ } else if max_srate < desired_srate {
+ max_srate
+ } else {
+ desired_srate
+ }
+ };
+
let supp_config: cpal::SupportedStreamConfig =
chosen_config.with_sample_rate(cpal::SampleRate(srate));
let config = supp_config.into();
@@ -339,12 +363,12 @@ fn get_audio_stream() -> Result<(cpal::Stream, u32), String> {
let stream = audio_device
.build_output_stream(
&config,
- move |data: &mut [i16], _: &cpal::OutputCallbackInfo| {
+ move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
let (mut note_info, mut maybe_sf) = lock_note_info_and_soundfont();
if let Some(sf) = maybe_sf.as_mut() {
let sample_rate = config.sample_rate.0 as f64;
for x in data.iter_mut() {
- *x = 0;
+ *x = 0.0;
}
let pitch_bend = note_info.pitch_bend;
for channel in 0..CHANNEL_COUNT {
@@ -782,9 +806,6 @@ fn main() {
};
}
- let mut this = rhai::Dynamic::from(rhai::Map::new());
- call_fn_if_exists(&engine, &ast, &mut this, "pm_start", ());
-
let (stream, sample_rate) = match get_audio_stream() {
Ok(s) => s,
Err(e) => {
@@ -798,6 +819,10 @@ fn main() {
note_info.output_sample_rate = sample_rate;
}
+
+ let mut this = rhai::Dynamic::from(rhai::Map::new());
+ call_fn_if_exists(&engine, &ast, &mut this, "pm_start", ());
+
if let Err(e) = stream.play() {
eprintln!("Error starting audio stream: {}", e);
return;
diff --git a/src/midi_input.rs b/src/midi_input.rs
index dd663b9..649cead 100644
--- a/src/midi_input.rs
+++ b/src/midi_input.rs
@@ -1,3 +1,4 @@
+#[cfg(unix)]
use std::ffi::{c_char, c_int, c_void, CStr, CString};
/// Query and read from MIDI input devices.
/// Basic usage:
@@ -22,6 +23,7 @@ use std::sync::Mutex;
// a big deal to add it as a dependency
// (we only really need it for size_t, ssize_t)
extern crate libc;
+#[cfg(unix)]
use libc::{free, size_t, ssize_t};
// (snd_rawmidi_t is an opaque struct)
diff --git a/src/soundfont.rs b/src/soundfont.rs
index 7d3628b..0c9a857 100644
--- a/src/soundfont.rs
+++ b/src/soundfont.rs
@@ -1215,14 +1215,14 @@ impl SoundFont {
})
}
- /// adds sample data to `samples` which is an i16 slice containing samples LRLRLRLR...
+ /// adds sample data to `samples` which is an f32 slice containing samples LRLRLRLR...
/// (`samples` should have even length)
/// volume (0 to 1) = volume of max velocity note.
/// returns `Ok(true)` if the note should still be held. increments `request.hold_time` as needed.
pub fn add_samples_interlaced(
&mut self,
request: &mut SamplesRequest,
- samples: &mut [i16],
+ samples: &mut [f32],
sample_rate: f64,
) -> Result<bool, SampleError> {
let key = request.key;
@@ -1320,19 +1320,20 @@ impl SoundFont {
// interpolate between one sample and the next
// note: it's okay to do this even for samples where endloop = end, because
// we added an additional sample to the end -- see (***)
- let sample1 = data[s] as f32;
- let sample2 = data[s + 1] as f32;
+ let sample1 = (data[s] as f32) * (1.0 / 32767.0);
+ let sample2 = (data[s + 1] as f32) * (1.0 / 32767.0);
let mut sample = sample1 + (sample2 - sample1) * (s_frac as f32);
sample *= falloff;
falloff *= falloff_mul;
- samples[2 * i] += (amplitude * sample * (1.0 - pan)) as i16;
- samples[2 * i + 1] += (amplitude * sample * pan) as i16;
+ samples[2 * i] += amplitude * sample * (1.0 - pan);
+ samples[2 * i + 1] += amplitude * sample * pan;
t += t_inc;
}
request.falloff = falloff;
if falloff * request.volume < 1.0 / 32767.0 {
+ // no longer audible
this_held = false;
}
final_t = f64::max(final_t, t);