From a44fe9cd193a6d33dda1e17e72b0331a64a17b32 Mon Sep 17 00:00:00 2001 From: Yruama_Lairba Date: Wed, 26 Jan 2022 01:53:37 +0100 Subject: [PATCH 01/18] implement correct pointer behaviour for ports --- core/src/port.rs | 29 +++++++++++++++++++---------- core/src/port/audio.rs | 40 +++++++++++++++++++++++++++------------- core/src/port/control.rs | 25 ++++++++++++++----------- core/src/port/cv.rs | 40 ++++++++++++++++++++++------------------ 4 files changed, 82 insertions(+), 52 deletions(-) diff --git a/core/src/port.rs b/core/src/port.rs index 0c7c16e6..f3a7b04d 100644 --- a/core/src/port.rs +++ b/core/src/port.rs @@ -21,9 +21,9 @@ pub use lv2_core_derive::*; /// A port can read input or create a pointer to the output, but the exact type of input/output (pointer) depends on the type of port. This trait generalizes these types and behaviour. pub trait PortType { /// The type of input read by the port. - type InputPortType: Sized; + type InputPortType: ?Sized; /// The type of output reference created by the port. - type OutputPortType: Sized; + type OutputPortType: ?Sized; /// Read data from the pointer or create a reference to the input. /// @@ -32,7 +32,10 @@ pub trait PortType { /// # Safety /// /// This method is unsafe because one needs to de-reference a raw pointer to implement this method. - unsafe fn input_from_raw(pointer: NonNull, sample_count: u32) -> Self::InputPortType; + unsafe fn input_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *const Self::InputPortType; /// Create a reference to the data where output should be written to. /// @@ -41,7 +44,10 @@ pub trait PortType { /// # Safety /// /// This method is unsafe because one needs to de-reference a raw pointer to implement this method. - unsafe fn output_from_raw(pointer: NonNull, sample_count: u32) -> Self::OutputPortType; + unsafe fn output_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *mut Self::OutputPortType; } /// Abstraction of safe port handles. @@ -60,7 +66,7 @@ pub trait PortHandle: Sized { /// /// Fields of this type can be dereferenced to the input type of the port type. pub struct InputPort { - port: T::InputPortType, + port: *const T::InputPortType, } impl Deref for InputPort { @@ -68,11 +74,14 @@ impl Deref for InputPort { #[inline] fn deref(&self) -> &Self::Target { - &self.port + unsafe { &*self.port } } } -impl PortHandle for InputPort { +impl PortHandle for InputPort +where + T: PortType, +{ #[inline] unsafe fn from_raw(pointer: *mut c_void, sample_count: u32) -> Option { Some(Self { @@ -85,7 +94,7 @@ impl PortHandle for InputPort { /// /// Fields of this type can be dereferenced to the output type of the port type. pub struct OutputPort { - port: T::OutputPortType, + port: *mut T::OutputPortType, } impl Deref for OutputPort { @@ -93,14 +102,14 @@ impl Deref for OutputPort { #[inline] fn deref(&self) -> &Self::Target { - &self.port + unsafe { &*self.port } } } impl DerefMut for OutputPort { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.port + unsafe { &mut *self.port } } } diff --git a/core/src/port/audio.rs b/core/src/port/audio.rs index ac755e90..2f3c51c1 100644 --- a/core/src/port/audio.rs +++ b/core/src/port/audio.rs @@ -66,16 +66,22 @@ unsafe impl UriBound for Audio { } impl PortType for Audio { - type InputPortType = &'static [f32]; - type OutputPortType = &'static mut [f32]; + type InputPortType = [f32]; + type OutputPortType = [f32]; #[inline] - unsafe fn input_from_raw(pointer: NonNull, sample_count: u32) -> Self::InputPortType { + unsafe fn input_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *const Self::InputPortType { std::slice::from_raw_parts(pointer.as_ptr() as *const f32, sample_count as usize) } #[inline] - unsafe fn output_from_raw(pointer: NonNull, sample_count: u32) -> Self::OutputPortType { + unsafe fn output_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *mut Self::OutputPortType { std::slice::from_raw_parts_mut(pointer.as_ptr() as *mut f32, sample_count as usize) } } @@ -132,11 +138,15 @@ unsafe impl UriBound for InPlaceAudio { } impl PortType for InPlaceAudio { - type InputPortType = &'static [Cell]; - type OutputPortType = &'static [Cell]; + type InputPortType = [Cell]; + type OutputPortType = [Cell]; #[inline] - unsafe fn input_from_raw(pointer: NonNull, sample_count: u32) -> Self::InputPortType { + unsafe fn input_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *const Self::InputPortType { + //std::slice::from_raw_parts(pointer.as_ptr() as *const Cell, sample_count as usize) Cell::from_mut(std::slice::from_raw_parts_mut( pointer.as_ptr() as *mut f32, sample_count as usize, @@ -145,11 +155,15 @@ impl PortType for InPlaceAudio { } #[inline] - unsafe fn output_from_raw(pointer: NonNull, sample_count: u32) -> Self::OutputPortType { - Cell::from_mut(std::slice::from_raw_parts_mut( - pointer.as_ptr() as *mut f32, - sample_count as usize, - )) - .as_slice_of_cells() + unsafe fn output_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *mut Self::OutputPortType { + std::slice::from_raw_parts_mut(pointer.as_ptr() as *mut Cell, sample_count as usize) + //Cell::from_mut(std::slice::from_raw_parts_mut( + // pointer.as_ptr() as *mut f32, + // sample_count as usize, + //)) + //.as_slice_of_cells() } } diff --git a/core/src/port/control.rs b/core/src/port/control.rs index 4f9c953f..3cc378dc 100644 --- a/core/src/port/control.rs +++ b/core/src/port/control.rs @@ -66,16 +66,16 @@ unsafe impl UriBound for Control { impl PortType for Control { type InputPortType = f32; - type OutputPortType = &'static mut f32; + type OutputPortType = f32; #[inline] - unsafe fn input_from_raw(pointer: NonNull, _sample_count: u32) -> f32 { - *(pointer.cast().as_ref()) + unsafe fn input_from_raw(pointer: NonNull, _sample_count: u32) -> *const f32 { + pointer.as_ptr() as *const f32 } #[inline] - unsafe fn output_from_raw(pointer: NonNull, _sample_count: u32) -> &'static mut f32 { - (pointer.as_ptr() as *mut f32).as_mut().unwrap() + unsafe fn output_from_raw(pointer: NonNull, _sample_count: u32) -> *mut f32 { + pointer.as_ptr() as *mut f32 } } @@ -130,19 +130,22 @@ unsafe impl UriBound for InPlaceControl { } impl PortType for InPlaceControl { - type InputPortType = &'static Cell; - type OutputPortType = &'static Cell; + type InputPortType = Cell; + type OutputPortType = Cell; #[inline] - unsafe fn input_from_raw(pointer: NonNull, _sample_count: u32) -> Self::InputPortType { - Cell::from_mut(&mut *(pointer.as_ptr() as *mut f32)) + unsafe fn input_from_raw( + pointer: NonNull, + _sample_count: u32, + ) -> *const Self::InputPortType { + pointer.as_ptr() as _ } #[inline] unsafe fn output_from_raw( pointer: NonNull, _sample_count: u32, - ) -> Self::OutputPortType { - Cell::from_mut(&mut *(pointer.as_ptr() as *mut f32)) + ) -> *mut Self::OutputPortType { + pointer.as_ptr() as _ } } diff --git a/core/src/port/cv.rs b/core/src/port/cv.rs index 9455aa0c..592f3f26 100644 --- a/core/src/port/cv.rs +++ b/core/src/port/cv.rs @@ -79,16 +79,22 @@ unsafe impl UriBound for CV { } impl PortType for CV { - type InputPortType = &'static [f32]; - type OutputPortType = &'static mut [f32]; + type InputPortType = [f32]; + type OutputPortType = [f32]; #[inline] - unsafe fn input_from_raw(pointer: NonNull, sample_count: u32) -> Self::InputPortType { + unsafe fn input_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *const Self::InputPortType { std::slice::from_raw_parts(pointer.as_ptr() as *const f32, sample_count as usize) } #[inline] - unsafe fn output_from_raw(pointer: NonNull, sample_count: u32) -> Self::OutputPortType { + unsafe fn output_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *mut Self::OutputPortType { std::slice::from_raw_parts_mut(pointer.as_ptr() as *mut f32, sample_count as usize) } } @@ -158,24 +164,22 @@ unsafe impl UriBound for InPlaceCV { } impl PortType for InPlaceCV { - type InputPortType = &'static [Cell]; - type OutputPortType = &'static [Cell]; + type InputPortType = [Cell]; + type OutputPortType = [Cell]; #[inline] - unsafe fn input_from_raw(pointer: NonNull, sample_count: u32) -> Self::InputPortType { - Cell::from_mut(std::slice::from_raw_parts_mut( - pointer.as_ptr() as *mut f32, - sample_count as usize, - )) - .as_slice_of_cells() + unsafe fn input_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *const Self::InputPortType { + std::slice::from_raw_parts(pointer.as_ptr() as *const Cell, sample_count as usize) } #[inline] - unsafe fn output_from_raw(pointer: NonNull, sample_count: u32) -> Self::OutputPortType { - Cell::from_mut(std::slice::from_raw_parts_mut( - pointer.as_ptr() as *mut f32, - sample_count as usize, - )) - .as_slice_of_cells() + unsafe fn output_from_raw( + pointer: NonNull, + sample_count: u32, + ) -> *mut Self::OutputPortType { + std::slice::from_raw_parts_mut(pointer.as_ptr() as *mut Cell, sample_count as usize) } } From a8682a2098d77d6af1e6744a5852f68122cdd904 Mon Sep 17 00:00:00 2001 From: Yruama_Lairba Date: Wed, 26 Jan 2022 01:55:15 +0100 Subject: [PATCH 02/18] mark todo!() for Atom port to avoid compile error --- atom/src/port.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/atom/src/port.rs b/atom/src/port.rs index 155c4df4..ab70cd10 100644 --- a/atom/src/port.rs +++ b/atom/src/port.rs @@ -110,15 +110,23 @@ impl PortType for AtomPort { type OutputPortType = PortWriter<'static>; #[inline] - unsafe fn input_from_raw(pointer: NonNull, _sample_count: u32) -> PortReader<'static> { - let header = AtomHeader::from_raw(pointer.cast().as_ref()); - PortReader::new(UnidentifiedAtom::from_header(header)) + unsafe fn input_from_raw( + pointer: NonNull, + _sample_count: u32, + ) -> *const PortReader<'static> { + todo!(); + //let header = AtomHeader::from_raw(pointer.cast().as_ref()); + //PortReader::new(UnidentifiedAtom::from_header(header)) } #[inline] - unsafe fn output_from_raw(pointer: NonNull, _sample_count: u32) -> PortWriter<'static> { - let header = AtomHeader::from_raw_mut(pointer.cast().as_mut()); - PortWriter::new(UnidentifiedAtom::from_header_mut(header).body_mut()) + unsafe fn output_from_raw( + pointer: NonNull, + _sample_count: u32, + ) -> *mut PortWriter<'static> { + todo!(); + //let header = AtomHeader::from_raw_mut(pointer.cast().as_mut()); + //PortWriter::new(UnidentifiedAtom::from_header_mut(header).body_mut()) } } From 8767840e715b46b6e59035449564f8f89b589ddc Mon Sep 17 00:00:00 2001 From: Yruama_Lairba Date: Sat, 5 Feb 2022 20:27:47 +0100 Subject: [PATCH 03/18] fix doc, proc macro need to be availlable only in doc --- core/src/port.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/src/port.rs b/core/src/port.rs index f3a7b04d..c844b968 100644 --- a/core/src/port.rs +++ b/core/src/port.rs @@ -13,9 +13,6 @@ use std::ffi::c_void; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; -#[cfg(feature = "lv2-core-derive")] -pub use lv2_core_derive::*; - /// Generalization of port types. /// /// A port can read input or create a pointer to the output, but the exact type of input/output (pointer) depends on the type of port. This trait generalizes these types and behaviour. @@ -135,7 +132,8 @@ impl PortHandle for Option { /// # Implementing /// /// The most convenient way to create a port collections is to define a struct with port types from the [`port`](index.html) module and then simply derive `PortCollection` for it. An example: -/// +/// ``` +/// # pub use lv2_core_derive::*; /// use lv2_core::port::*; /// /// #[derive(PortCollection)] @@ -146,6 +144,7 @@ impl PortHandle for Option { /// control_output: OutputPort, /// optional_control_input: Option>, /// } +/// ``` /// /// Please note that port indices are mapped in the order of occurrence; In our example, the implementation will treat `audio_input` as port `0`, `audio_output` as port `1` and so on. Therefore, your plugin definition and your port collection have to match. Otherwise, undefined behaviour will occur. pub trait PortCollection: Sized { From 40456395805e1b4d66ffd8d5a05a01dcbbddb69f Mon Sep 17 00:00:00 2001 From: Yruama_Lairba Date: Sat, 2 Apr 2022 15:36:34 +0200 Subject: [PATCH 04/18] Fix, re export of FeatureCollection alongside trait --- core/src/feature/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/feature/mod.rs b/core/src/feature/mod.rs index 3871d1eb..86fea5f2 100644 --- a/core/src/feature/mod.rs +++ b/core/src/feature/mod.rs @@ -9,6 +9,8 @@ pub use cache::FeatureCache; pub use core_features::*; pub use descriptor::FeatureDescriptor; +pub use lv2_core_derive::FeatureCollection; + use std::ffi::c_void; /// All threading contexts of LV2 interface methods. From 2e3ab00bf5a01d57a4b7814869835c474ca38d24 Mon Sep 17 00:00:00 2001 From: Yruama_Lairba Date: Sat, 2 Apr 2022 15:51:04 +0200 Subject: [PATCH 05/18] refix, conditional re export --- core/src/feature/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/feature/mod.rs b/core/src/feature/mod.rs index 86fea5f2..d001e55d 100644 --- a/core/src/feature/mod.rs +++ b/core/src/feature/mod.rs @@ -9,6 +9,7 @@ pub use cache::FeatureCache; pub use core_features::*; pub use descriptor::FeatureDescriptor; +#[cfg(feature = "lv2-core-derive")] pub use lv2_core_derive::FeatureCollection; use std::ffi::c_void; From 17625a86f74f84a6e2c207893d01700a4b158983 Mon Sep 17 00:00:00 2001 From: Yruama_Lairba Date: Sat, 2 Jul 2022 18:04:29 +0200 Subject: [PATCH 06/18] Create RCell and RwCell for inplace port. --- core/src/port.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/core/src/port.rs b/core/src/port.rs index c844b968..94c1b651 100644 --- a/core/src/port.rs +++ b/core/src/port.rs @@ -9,10 +9,74 @@ pub use audio::*; pub use control::*; pub use cv::*; +use std::cell::Cell; use std::ffi::c_void; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; +/// A readonly cell. Used to give read only access for input port with inplace processing support. +/// +/// This cell is used to give read only access to data when a writable alias may exist for the +/// underlying memory location. This is used by inplace input port because it's allow inplace +/// processing while preventing to write data through the current input port. +#[repr(transparent)] +pub struct RCell { + value: Cell, +} + +impl RCell { + /// Returns a copy of the contained value. + #[inline] + pub fn get(&self) -> T { + self.value.get() + } +} + +impl RCell<[T]> { + /// Returns a `&[RCell]` from a `&RCell<[T]>` + pub fn as_slice_of_cells(&self) -> &[RCell] { + // SAFETY: `RCell` has the same memory layout as `T`. + unsafe { &*(self as *const RCell<[T]> as *const [RCell]) } + } +} + +/// A read/write cell. Used to give read/write access for output port with inplace processing +/// support. +/// +/// This cell is used to give read and write access to data when an alias may exist for the +/// underlying memory location. It works by giving interior mutability, like [`std::cell::Cell`]. +/// This is used by inplace output because it's allow inplace processing. +// Note: technically, a std::Cell could be used, but custom cell is better to express the specific +// usage. +#[repr(transparent)] +pub struct RwCell { + value: Cell, +} + +impl RwCell { + /// Returns a copy of the contained value. + #[inline] + pub fn get(&self) -> T { + self.value.get() + } +} + +impl RwCell { + ///Sets the contained value. + #[inline] + pub fn set(&self, val: T) { + self.value.set(val); + } +} + +impl RwCell<[T]> { + /// Returns a `&[RwCell]` from a `&RwCell<[T]>` + pub fn as_slice_of_cells(&self) -> &[RwCell] { + // SAFETY: `RwCell` has the same memory layout as `T`. + unsafe { &*(self as *const RwCell<[T]> as *const [RwCell]) } + } +} + /// Generalization of port types. /// /// A port can read input or create a pointer to the output, but the exact type of input/output (pointer) depends on the type of port. This trait generalizes these types and behaviour. From dbd3cab7c00e75bc78ddbd9cf61371595daddc56 Mon Sep 17 00:00:00 2001 From: Yruama_Lairba Date: Sat, 2 Jul 2022 18:36:45 +0200 Subject: [PATCH 07/18] Redesign of audio ports (input, output, inplace, not inplace) --- core/src/port/audio.rs | 281 +++++++++++++++++++---------------------- 1 file changed, 128 insertions(+), 153 deletions(-) diff --git a/core/src/port/audio.rs b/core/src/port/audio.rs index 2f3c51c1..ae2fe86d 100644 --- a/core/src/port/audio.rs +++ b/core/src/port/audio.rs @@ -1,169 +1,144 @@ -use crate::port::PortType; -use std::cell::Cell; -use std::ffi::c_void; -use std::ptr::NonNull; -use urid::UriBound; +//! TODO! +//! Audio ports definition. Audio ports are connected to an array of float audio samples. +//! +//! Ports of this type are connected to a buffer of float audio samples, represented as a slice. +//! +//! Audio samples are normalized between -1.0 and 1.0, though there is no requirement for samples to be strictly within this range. +//! +//! See the [LV2 reference](https://lv2plug.in/ns/lv2core#AudioPort) for more information. +//! +//! # Example +//! +//! This very simple amplifier plugin multiplies the input sample by 2 and outputs the result. +//! +//! ``` +//! # use lv2_core::prelude::*; +//! # use urid::*; +//! # #[uri("http://lv2plug.in/plugins.rs/simple_amp")] +//! # struct SimpleAmp; +//! #[derive(PortCollection)] +//! struct SimpleAmpPorts { +//! input: InputPort