VST3 Sampler using NIH-Plug - rust

I'm trying to make a NIH-Plug sample player. This wouldn't be a pitch shifting plugin, but per note a different sample. (note A1 -> A1.wav). Are there any resources, about this subject. I'm also trying to cache the samples, but it's not really succeeding.
Ultimately, I'm going to use include_dir instead of include_bytes.
Here's a PolyModSynth demo, which I'm using and trying to adapt to playing samples.
Thank you.
let C1 = include_bytes!("samples/c1.wav");
let CS1 = include_bytes!("samples/c#1.wav");
fn process(
&mut self,
buffer: &mut Buffer,
_aux: &mut AuxiliaryBuffers,
context: &mut impl ProcessContext<Self>
) -> ProcessStatus {
let mut next_event = context.next_event();
for (sample_id, wav_sample) in buffer.iter_samples().zip(wav_vec) {
// Act on the next MIDI event
while let Some(event) = next_event {
if event.timing() > (sample_id as u32) {
break;
}
// handle the MIDI event as needed
// ...
next_event = context.next_event();
}
// Set the sample value in the output buffer
for sample in channel_samples {
*sample = self.sample_value[sample_id];
}
}

Related

Avoid dropping the variable when wrapped into a struct

I have a Rodio's Sink wrapper in HAudioSink. I also implement a try_new_from_haudio function that, in short, creates a Sink instance, wrap it in HAudioSink and already starts playing the first audio.
In Sink's docs it states: "Dropping the Sink stops all sounds. You can use detach if you want the sounds to continue playing". So when try_new_from_haudiois returning, it drops the original sink and the sound is stopping when it shouldn't.
So my question here is: what should I do to avoid it dropping when I create an instance of HAudioSink? Is ManuallyDrop the way to go?
struct HAudioSink {
sink: Sink,
}
impl HAudioSink {
pub fn try_new_from_haudio<T>(haudio: HAudio<T>) -> HResult<Self>
where
T: NativeType + Float + ToPrimitive,
{
let (_stream, stream_handle) = OutputStream::try_default()?;
let sink = Sink::try_new(&stream_handle).unwrap();
let nchannels = haudio.nchannels();
let nframes = haudio.nframes();
let sr = haudio.sr();
let mut data_interleaved: Vec<f32> = Vec::with_capacity(nchannels * nframes);
let values = haudio
.inner()
.inner()
.values()
.as_any()
.downcast_ref::<PrimitiveArray<T>>()
.unwrap();
for f in 0..nframes {
for ch in 0..nchannels {
data_interleaved.push(values.value(f + ch * nframes).to_f32().unwrap());
}
}
let source = SamplesBuffer::new(u16::try_from(nchannels).unwrap(), sr, data_interleaved);
sink.append(source);
Ok(HAudioSink { sink })
}
// Sleeps the current thread until the sound ends.
pub fn sleep_until_end(&self) {
self.sink.sleep_until_end();
}
}
#[cfg(test)]
mod tests {
use super::*;
//this test doesn't work
#[test]
fn play_test() {
let sink = HAudioSink::try_new_from_file("../testfiles/gs-16b-2c-44100hz.wav").unwrap();
sink.append_from_file("../testfiles/gs-16b-2c-44100hz.wav")
.unwrap();
sink.sleep_until_end();
}
}
If I put sink.sleep_until_end() inside try_new_from_haudio, just before returning Ok, it works.
check the following link for the reproducible example of this issue: https://github.com/RustAudio/rodio/issues/476
The problem is that for the _stream too "If this is dropped playback will end & attached OutputStreamHandles will no longer work."
see the docs on OutputStream. So you have to store it alongside your Sink:
pub struct SinkWrapper {
pub sink: Sink,
pub stream: OutputStream,
}
impl SinkWrapper {
pub fn new() -> Self {
let (stream, stream_handle) = OutputStream::try_default().unwrap();
let sink = Sink::try_new(&stream_handle).unwrap();
// Add a dummy source of the sake of the example.
let source = SineWave::new(440.0)
.take_duration(Duration::from_secs_f32(1.))
.amplify(2.);
sink.append(source);
Self { sink, stream }
}
}

Reading the DS18B20 temperature sensor with this Rust function

sorry, i'm a complete newbie to Rust. I try to read the temp from the sensor mentioned above on a Raspberry Pi using the code provided on this site: https://github.com/fuchsnj/ds18b20
Actually, i want to call the function
get_temperature
but i have no idea how to declare the parameters, especially delay and one_wire_bus.
I was able to resolve all the 'namespaces' or name bindings (sorry, coming from C++) but got stuck with the parameters. Can someone give me an example how to call and use this function like this:
use ds18b20::{Resolution, Ds18b20};
use embedded_hal::blocking::delay::{DelayUs, DelayMs};
use embedded_hal::digital::v2::{OutputPin, InputPin};
use one_wire_bus::{self, OneWire, OneWireResult};
use core::fmt::Debug;
use std::io::Write;
fn main() {
let mut delay = ?????;
let mut one_wire_bus = ?????;
let mut tx = ?????; //&mut Vec::new();
let temp = get_temperature(delay, tx, one_wire_bus);
...
//do something whit the temp
...
}
This is the implementation of the function from the website
fn get_temperature<P, E>(
delay: &mut (impl DelayUs<u16> + DelayMs<u16>),
tx: &mut impl Write,
one_wire_bus: &mut OneWire<P>,
) -> OneWireResult<(), E>
where
P: OutputPin<Error=E> + InputPin<Error=E>,
E: Debug
{
// initiate a temperature measurement for all connected devices
ds18b20::start_simultaneous_temp_measurement(one_wire_bus, delay)?;
// wait until the measurement is done. This depends on the resolution you specified
// If you don't know the resolution, you can obtain it from reading the sensor data,
// or just wait the longest time, which is the 12-bit resolution (750ms)
Resolution::Bits12.delay_for_measurement_time(delay);
// iterate over all the devices, and report their temperature
let mut search_state = None;
loop {
if let Some((device_address, state)) = one_wire_bus.device_search(search_state.as_ref(), false, delay)? {
search_state = Some(state);
if device_address.family_code() != ds18b20::FAMILY_CODE {
// skip other devices
continue;
}
// You will generally create the sensor once, and save it for later
let sensor = Ds18b20::new(device_address)?;
// contains the read temperature, as well as config info such as the resolution used
let sensor_data = sensor.read_data(one_wire_bus, delay)?;
writeln!(tx, "Device at {:?} is {}°C", device_address, sensor_data.temperature);
} else {
break;
}
}
Ok(())
}

Tui-rs: flickering when drawing multiple widgets

Good evening!
I'm trying to write a very simple terminal application that draws two textboxes on screen, accepting input on one and showing output on the other, using Rust and tui-rs. The first part works perfectly, but my problems arose when i tried to draw two blocks at the same time: for some reason, it only shows the second block (in order of drawing) and if i move my mouse, it flickers between the two in a weird way. My best guess is that this is due to my drawing implementation, which somehow "clears" the screen whenever it needs to draw something, but if that's the case, i couldn't find any doc on it, and i wouldn't know how to go about working around this. I've provided some code that should be enough to replicate the issue on a smaller scale.
#![allow(unused_imports)]
#![allow(unused_variables)]
use crossterm::{
event::{self, DisableMouseCapture, EnableMouseCapture, Event},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::io
use tui::{
backend::CrosstermBackend,
layout::Rect,
widgets::{Block, Borders},
Terminal,
};
struct FirstStruct {}
impl FirstStruct {
pub fn draw(&self, term: &mut Terminal<CrosstermBackend<io::Stdout>>) -> io::Result<()> {
term.draw(|f| {
let size = f.size();
let (w, h) = (size.width / 2, size.height);
let (x, y) = (size.x, size.y);
let rect = Rect::new(x, y, w, h);
let block = Block::default()
.title("One")
.borders(Borders::ALL);
f.render_widget(block, rect)
})?;
Ok(())
}
}
struct SecondStruct { }
impl SecondStruct {
pub fn draw(&self, term: &mut Terminal<CrosstermBackend<io::Stdout>>) -> io::Result<()> {
term.draw(|f| {
let size = f.size();
let (w, h) = (size.width / 2, size.height);
let (x, y) = (size.x + w, size.y);
let rect = Rect::new(x, y, w, h);
let block = Block::default()
.title("Two")
.borders(Borders::ALL);
f.render_widget(block, rect)
})?;
Ok(())
}
}
fn main() -> io::Result<()>{
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let first = FirstStruct {};
let second = SecondStruct {};
let mut running = true;
while running {
if let Event::Key(key) = event::read()? {
running = false;
}
second.draw(&mut terminal)?;
first.draw(&mut terminal)?;
}
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
Ok(())
}
Does anybody know how i can fix this issue? Thanks in advance!!
Every time you call Terminal::draw(), you must draw everything that you want to be visible at once. Instead of passing Terminal to your own draw functions, pass the Frame that you get from Terminal::draw(). That is, replace
second.draw(&mut terminal)?;
first.draw(&mut terminal)?;
with
terminal.draw(|f| {
first.draw(f)?;
second.draw(f)?;
});
and change the signature of FirstStruct and SecondStruct to match.
Also, it would be more usual to, instead of computing the rectangle for each widget in the individual functions, decide at the top level (using Layout, perhaps) and pass Rects down to the drawing functions. That way, they can be positioned differently in different situations. What you have will work, but it's not as easy to change.
Layout code from the documentation's example, adjusted to your situation:
terminal.draw(|f| {
let chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints(
[
Constraint::Percentage(50),
Constraint::Percentage(50),
].as_ref()
)
.split(f.size());
first.draw(f, chunks[0])?;
second.draw(f, chunks[1])?;
});

What's the idiomatic way to create a iterator that owns some intermediate data and also points to it?

I'm trying to create a struct that wraps around stdin to provide something like C++'s std::cin.
I want to keep a String with the current line of the input and a SplitAsciiWhitespace iterator to its current token. When I reach the end of the iterator, I want to get a new line.
I'm not worried about error checking and I'm not interested in any crates. This is not for production code, it's just for practicing. I want to avoid using unsafe, as a way to practice the correct mindset.
The idea is that I can use it as follows:
let mut reader = Reader::new();
let x: i32 = reader.read();
let s: f32 = reader.read();
My current attempt is the following, but it doesn't compile. Can somebody give me a pointer on the proper way to do this?
struct Reader<'a> {
line: String,
token: std::str::SplitAsciiWhitespace<'a>,
}
impl<'a> Reader<'a> {
fn new() -> Self {
let line = String::new();
let token = line.split_ascii_whitespace();
Reader { line, token }
}
fn read<T: std::str::FromStr + std::default::Default>(&'a mut self) -> T {
let token = loop {
if let Some(token) = self.token.next() {
break token;
}
let stdin = io::stdin();
stdin.read_line(&mut self.line).unwrap();
self.token = self.line.split_ascii_whitespace();
};
token.parse().unwrap_or_default()
}
}
This question explains why it can't be done this way but does not provide an alternative solution. The "How do I fix it" section simply says "don't put these two things in the same struct", but I can't think of a way to do it separately while keeping a similar interface to the user.
Found a solution: keeping track of how much of the string we've read so far by using a simple index.
It does require some pointer arithmetic, but seems to work nicely.
Not sure if this counts as "idiomatic" Rust, tho.
struct Reader {
line: String,
offset: usize,
}
impl Reader {
fn new() -> Self {
Reader { line: String::new(), offset: 0 }
}
fn next<T: std::str::FromStr + std::default::Default> (&mut self) -> T {
loop {
let rem = &self.line[self.offset..];
let token = rem.split_whitespace().next();
if let Some(token) = token {
self.offset = token.as_ptr() as usize - self.line.as_ptr() as usize + token.len();
return token.parse::<T>().unwrap_or_default();
}
self.line.clear();
std::io::stdin().read_line(&mut self.line).unwrap();
self.offset = 0;
}
}
}

Is it possible to compile a Vulkano shader at runtime?

I've been using Vulkano in order to get some simple 3D graphics going on. Generally, I like to write my GLSL shaders in text and restart my program, or even changing shaders while the program is running. The examples given in Vulkano appear to use a macro to convert the GLSL to some form of SPIR-V based shader with Rust functions attached, but the GLSL is actually compiled into the binary (even when using a path to a file).
I've managed to get the crate shaderc to build my SPIR-V on the fly:
let mut f = File::open("src/grafx/vert.glsl")
.expect("Can't find file src/bin/runtime-shader/vert.glsl
This example needs to be run from the root of the example crate.");
let mut source = String::new();
f.read_to_string(&mut source);
//let source = "#version 310 es\n void EP() {}";
let mut compiler = shaderc::Compiler::new().unwrap();
let mut options = shaderc::CompileOptions::new().unwrap();
options.add_macro_definition("EP", Some("main"));
let binary_result = compiler.compile_into_spirv(
&source, shaderc::ShaderKind::Vertex,
"shader.glsl", "main", Some(&options)).unwrap();
assert_eq!(Some(&0x07230203), binary_result.as_binary().first());
let text_result = compiler.compile_into_spirv_assembly(
&source, shaderc::ShaderKind::Vertex,
"shader.glsl", "main", Some(&options)).unwrap();
assert!(text_result.as_text().starts_with("; SPIR-V\n"));
//println!("Compiled Vertex Shader: {}", text_result.as_text());
let vert_spirv = {
unsafe { ShaderModule::new(device.clone(), binary_result.as_binary_u8()) }.unwrap()
};
vert_spirv
So far, so good, we have a ShaderModule which seems to be the first step. However, we we actually need is a GraphicsEntryPoint which we can then put into our GraphicsPipeline. Apparently, GraphicsPipeline is where we string together our shaders, triangles and depth maps and all that lovely stuff.
Trouble is, I've no idea what is going on with the code that performs this feat:
pub fn shade_vertex <'a, S> (vert_spirv: &'a Arc<ShaderModule>) ->
GraphicsEntryPoint<'a, S, VertInput, VertOutput, VertLayout> {
let tn = unsafe {
vert_spirv.graphics_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
VertInput,
VertOutput,
VertLayout(ShaderStages { vertex: true, ..ShaderStages::none() }),
GraphicsShaderType::Vertex
)
};
tn
}
Specifically, what is VertInput and VertOutput? I've copied them from the example.
This is the closest example I could find that deals with loading Shaders on the fly. It looks like Input and Output are looking for entry points into the SPIR-V or something but I've no idea what to do with that. I'm hoping there is a function somewhere in the existing macro that will just take care of this for me. I've gotten this far but I seem a little stuck.
Has anyone else tried loading shaders at runtime?
I'm using wgpu, I've made my device, render_pipeline multithreaded like this:
let rx = Arc::new(Mutex::new(rx));
let window = Arc::new(Mutex::new(window));
let fs = Arc::new(Mutex::new(fs));
let fs_module = Arc::new(Mutex::new(fs_module));
let render_pipeline = Arc::new(Mutex::new(render_pipeline));
let device = Arc::new(Mutex::new(device));
used notify to listen to change events:
notify = "4.0.15"
use notify::{RecommendedWatcher, Watcher, RecursiveMode};
//mainxx
let (tx, rx) = mpsc::channel();
let mut watcher: RecommendedWatcher =
Watcher::new(tx, Duration::from_millis(500)).unwrap();
log::info!("Starting watcher on {:?}", *FRAG_SHADER_PATH);
watcher.watch((*FRAG_SHADER_PATH).clone(), RecursiveMode::NonRecursive).unwrap();
Then spawn a thread that listens to changes:
thread::spawn(move || {
log::info!("Shader watcher thread spawned");
loop {
if let Ok(notify::DebouncedEvent::Write(..)) = rx.lock().unwrap().recv() {
log::info!("Write event in fragment shader");
window.lock().unwrap().set_title("Loading shader.frag...");
*fs.lock().unwrap() = load_fs().unwrap();
*fs_module.lock().unwrap() = load_fs_module(Arc::clone(&device), &Arc::clone(&fs).lock().unwrap());
*render_pipeline.lock().unwrap() = create_render_pipeline_multithreaded(Arc::clone(&device), Arc::clone(&fs_module));
render.lock().unwrap().deref_mut()();
window.lock().unwrap().set_title(TITLE);
};
}
});
where load_fs is a closure that uses glsl_to_spirv:
let load_fs = move || -> Result<Vec<u32>, std::io::Error> {
log::info!("Loading fragment shader");
let mut buffer = String::new();
let mut f = File::open(&*FRAG_SHADER_PATH)?;
f.read_to_string(&mut buffer)?;
// Load fragment shader
wgpu::read_spirv(
glsl_to_spirv::compile(
&buffer,
glsl_to_spirv::ShaderType::Fragment
).expect("Compilation failed")
)
};
There is an updated example for this in the vulkano repository.
I followed that and the example for shaderc-rs to get to this:
fn compile_to_spirv(src: &str, kind: shaderc::ShaderKind, entry_point_name: &str) -> Vec<u32> {
let mut f = File::open(src).unwrap_or_else(|_| panic!("Could not open file {}", src));
let mut glsl = String::new();
f.read_to_string(&mut glsl)
.unwrap_or_else(|_| panic!("Could not read file {} to string", src));
let compiler = shaderc::Compiler::new().unwrap();
let mut options = shaderc::CompileOptions::new().unwrap();
options.add_macro_definition("EP", Some(entry_point_name));
compiler
.compile_into_spirv(&glsl, kind, src, entry_point_name, Some(&options))
.expect("Could not compile glsl shader to spriv")
.as_binary()
.to_vec()
}
let vs = {
unsafe {
ShaderModule::from_words(
device.clone(),
&compile_to_spirv(
"shaders/triangle/vs.glsl",
shaderc::ShaderKind::Vertex,
"main",
),
)
}
.unwrap()
};
After this, vs can be used as in the example.

Resources