├── pd-sys ├── .gitignore ├── examples │ └── helloworld │ │ ├── Makefile.toml │ │ ├── .cargo │ │ └── config │ │ ├── test.pd │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ └── lib.rs ├── wrappers │ ├── wrapper.h │ ├── wrapper-instance.h │ ├── wrapper-doubleprecision.h │ └── wrapper-instance-doubleprecision.h ├── Cargo.toml ├── README.md ├── LICENSE.txt ├── src │ ├── lib.rs │ └── ffi.rs └── build.rs ├── external ├── .gitignore ├── src │ ├── obj.rs │ ├── pd.rs │ ├── lib.rs │ ├── method.rs │ ├── external.rs │ ├── post.rs │ ├── inlet.rs │ ├── clock.rs │ ├── alloc.rs │ ├── symbol.rs │ ├── outlet.rs │ ├── atom.rs │ ├── builder.rs │ ├── class.rs │ └── wrapper.rs ├── Cargo.toml └── build.rs ├── macros ├── examples │ ├── helloall │ │ ├── .gitignore │ │ ├── Makefile.toml │ │ ├── .cargo │ │ │ └── config │ │ ├── Cargo.toml │ │ ├── test.pd │ │ ├── src │ │ │ └── lib.rs │ │ └── Cargo.lock │ ├── xfade │ │ ├── Makefile.toml │ │ ├── .cargo │ │ │ └── config │ │ ├── Cargo.toml │ │ ├── test.pd │ │ ├── src │ │ │ └── lib.rs │ │ └── Cargo.lock │ ├── counter │ │ ├── Makefile.toml │ │ ├── .cargo │ │ │ └── config │ │ ├── test.pd │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── Cargo.lock │ ├── hellodsp │ │ ├── Makefile.toml │ │ ├── .cargo │ │ │ └── config │ │ ├── Cargo.toml │ │ ├── test.pd │ │ ├── src │ │ │ └── lib.rs │ │ └── Cargo.lock │ ├── helloworld │ │ ├── Makefile.toml │ │ ├── .cargo │ │ │ └── config │ │ ├── test.pd │ │ ├── Cargo.toml │ │ ├── src │ │ │ └── lib.rs │ │ └── Cargo.lock │ └── complex_counter │ │ ├── Makefile.toml │ │ ├── .cargo │ │ └── config │ │ ├── Cargo.toml │ │ ├── test.pd │ │ ├── src │ │ └── lib.rs │ │ └── Cargo.lock ├── Cargo.toml ├── Cargo.lock ├── README.md └── src │ └── lib.rs ├── .gitignore ├── .gitmodules ├── utils ├── README.md └── Makefile.toml └── README.md /pd-sys/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | -------------------------------------------------------------------------------- /external/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | -------------------------------------------------------------------------------- /macros/examples/helloall/.gitignore: -------------------------------------------------------------------------------- 1 | *.dek* 2 | -------------------------------------------------------------------------------- /macros/examples/xfade/Makefile.toml: -------------------------------------------------------------------------------- 1 | ../../../utils/Makefile.toml -------------------------------------------------------------------------------- /macros/examples/counter/Makefile.toml: -------------------------------------------------------------------------------- 1 | ../../../utils/Makefile.toml -------------------------------------------------------------------------------- /macros/examples/helloall/Makefile.toml: -------------------------------------------------------------------------------- 1 | ../../../utils/Makefile.toml -------------------------------------------------------------------------------- /macros/examples/hellodsp/Makefile.toml: -------------------------------------------------------------------------------- 1 | ../../../utils/Makefile.toml -------------------------------------------------------------------------------- /macros/examples/helloworld/Makefile.toml: -------------------------------------------------------------------------------- 1 | ../../../utils/Makefile.toml -------------------------------------------------------------------------------- /pd-sys/examples/helloworld/Makefile.toml: -------------------------------------------------------------------------------- 1 | ../../../utils/Makefile.toml -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.l_* 3 | *.d_* 4 | *.m_* 5 | *.o_* 6 | *.pd_* 7 | -------------------------------------------------------------------------------- /macros/examples/complex_counter/Makefile.toml: -------------------------------------------------------------------------------- 1 | ../../../utils/Makefile.toml -------------------------------------------------------------------------------- /pd-sys/wrappers/wrapper.h: -------------------------------------------------------------------------------- 1 | #include "../../third-party/pure-data/src/m_pd.h" 2 | -------------------------------------------------------------------------------- /external/src/obj.rs: -------------------------------------------------------------------------------- 1 | pub trait AsObject { 2 | fn as_obj(&mut self) -> *mut pd_sys::t_object; 3 | } 4 | -------------------------------------------------------------------------------- /macros/examples/xfade/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] 3 | -------------------------------------------------------------------------------- /pd-sys/wrappers/wrapper-instance.h: -------------------------------------------------------------------------------- 1 | #define PDINSTANCE 2 | #include "../../third-party/pure-data/src/m_pd.h" 3 | -------------------------------------------------------------------------------- /macros/examples/counter/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] 3 | -------------------------------------------------------------------------------- /macros/examples/helloall/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] 3 | -------------------------------------------------------------------------------- /macros/examples/hellodsp/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] 3 | -------------------------------------------------------------------------------- /macros/examples/helloworld/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] 3 | -------------------------------------------------------------------------------- /pd-sys/examples/helloworld/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] 3 | -------------------------------------------------------------------------------- /macros/examples/complex_counter/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] 3 | -------------------------------------------------------------------------------- /pd-sys/wrappers/wrapper-doubleprecision.h: -------------------------------------------------------------------------------- 1 | #define PD_FLOATSIZE 64 2 | #include "../../third-party/pure-data/src/m_pd.h" 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "puredata-sys/pure-data"] 2 | path = third-party/pure-data 3 | url = https://github.com/pure-data/pure-data.git 4 | -------------------------------------------------------------------------------- /pd-sys/wrappers/wrapper-instance-doubleprecision.h: -------------------------------------------------------------------------------- 1 | #define PD_FLOATSIZE 64 2 | #define PDINSTANCE 3 | #include "../../third-party/pure-data/src/m_pd.h" 4 | -------------------------------------------------------------------------------- /external/src/pd.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::CString; 2 | 3 | pub fn sample_rate() -> pd_sys::t_float { 4 | unsafe { pd_sys::sys_getsr() } 5 | } 6 | 7 | pub fn post(s: CString) { 8 | unsafe { 9 | pd_sys::post(s.as_ptr()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /macros/examples/helloworld/test.pd: -------------------------------------------------------------------------------- 1 | #N canvas 2 74 1916 1004 10; 2 | #X declare -path .; 3 | #X obj 336 70 declare -path .; 4 | #X obj 89 90 helloworld; 5 | #X obj 89 62 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 6 | -1; 7 | #X connect 2 0 1 0; 8 | -------------------------------------------------------------------------------- /utils/README.md: -------------------------------------------------------------------------------- 1 | # Utils 2 | 3 | ## Makefile.toml 4 | 5 | Build targets to help with building, packaging and running pd-sys and pd-ext externals. 6 | 7 | Uses [cargo-make](https://github.com/sagiegurari/cargo-make) 0.22.1 or higher+ 8 | ``` 9 | cargo install --force cargo-make 10 | ``` 11 | -------------------------------------------------------------------------------- /external/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub extern crate pd_sys; 2 | pub mod alloc; 3 | pub mod atom; 4 | pub mod builder; 5 | pub mod class; 6 | pub mod clock; 7 | pub mod external; 8 | pub mod inlet; 9 | pub mod method; 10 | pub mod obj; 11 | pub mod outlet; 12 | pub mod pd; 13 | pub mod post; 14 | pub mod symbol; 15 | pub mod wrapper; 16 | -------------------------------------------------------------------------------- /macros/examples/counter/test.pd: -------------------------------------------------------------------------------- 1 | #N canvas 2 74 1916 1004 10; 2 | #X declare -path .; 3 | #X obj 336 70 declare -path .; 4 | #X obj 89 62 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 5 | -1; 6 | #X floatatom 89 113 5 0 0 0 - - -, f 5; 7 | #X obj 89 90 counter 3; 8 | #X connect 1 0 3 0; 9 | #X connect 3 0 2 0; 10 | -------------------------------------------------------------------------------- /pd-sys/examples/helloworld/test.pd: -------------------------------------------------------------------------------- 1 | #N canvas 541 74 860 615 10; 2 | #X declare -path .; 3 | #X obj 412 209 declare -path .; 4 | #X obj 347 298 helloworld; 5 | #X obj 336 232 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 6 | -1 -1; 7 | #X msg 388 249 helloworld 4; 8 | #X connect 2 0 1 0; 9 | #X connect 3 0 1 0; 10 | -------------------------------------------------------------------------------- /pd-sys/examples/helloworld/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "helloworld" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "helloworld" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pd-sys = "0.1.0" 13 | 14 | [profile.release] 15 | lto = true 16 | panic = "abort" 17 | -------------------------------------------------------------------------------- /macros/examples/counter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "counter" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "counter" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pd-sys = "0.1.0" 13 | pd-ext = { path = "../../../external" } 14 | pd-ext-macros = { path = "../.." } 15 | -------------------------------------------------------------------------------- /macros/examples/helloall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "helloall" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "helloall" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pd-sys = "0.1.0" 13 | pd-ext = { path = "../../../external" } 14 | pd-ext-macros = { path = "../.." } 15 | -------------------------------------------------------------------------------- /macros/examples/hellodsp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hellodsp" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "hellodsp_tilde" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pd-sys = "0.1.0" 13 | pd-ext = { path = "../../../external" } 14 | pd-ext-macros = { path = "../.." } 15 | -------------------------------------------------------------------------------- /macros/examples/helloworld/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "helloworld" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "helloworld" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pd-sys = "0.1.0" 13 | pd-ext = { path = "../../../external" } 14 | pd-ext-macros = { path = "../.." } 15 | -------------------------------------------------------------------------------- /pd-sys/examples/helloworld/README.md: -------------------------------------------------------------------------------- 1 | # HelloWorld 2 | 3 | A minimal example based on the HOWTO [my first external: helloworld](https://github.com/pure-data/externals-howto#my-first-external-helloworld) example. 4 | 5 | Can be built with `cargo build` or, for more features.. use `cargo-make` and read the details 6 | of that in the [README.md](../../../utils/README.md) for that. 7 | -------------------------------------------------------------------------------- /macros/examples/complex_counter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "complex_counter" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "complex_counter" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pd-sys = "0.1.0" 13 | pd-ext = { path = "../../../external" } 14 | pd-ext-macros = { path = "../.." } 15 | -------------------------------------------------------------------------------- /macros/examples/xfade/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xfade" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "xfade_tilde" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pd-sys = "0.1.0" 13 | pd-ext = { path = "../../../external" } 14 | pd-ext-macros = { path = "../.." } 15 | itertools = "0.8.0" 16 | num = "0.2.0" 17 | -------------------------------------------------------------------------------- /macros/examples/helloall/test.pd: -------------------------------------------------------------------------------- 1 | #N canvas 0 24 1680 1004 10; 2 | #X declare -path .; 3 | #X obj 336 70 declare -path .; 4 | #X obj 98 256 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 5 | -1; 6 | #X obj 154 331 print got; 7 | #X msg 179 281 list 1 2 3 4; 8 | #X msg 177 243 foo bar 1 2; 9 | #X msg 137 198 bar xxx; 10 | #X obj 154 308 hello/all; 11 | #X connect 1 0 6 0; 12 | #X connect 3 0 6 0; 13 | #X connect 4 0 6 0; 14 | #X connect 5 0 6 0; 15 | #X connect 6 0 2 0; 16 | -------------------------------------------------------------------------------- /macros/examples/xfade/test.pd: -------------------------------------------------------------------------------- 1 | #N canvas 2 74 1916 1004 10; 2 | #X declare -path xfade; 3 | #X msg 135 73 \; pd dsp 1; 4 | #X obj 352 171 xfade~, f 12; 5 | #X obj 356 99 osc~ 400; 6 | #X obj 439 89 osc~ 702; 7 | #X obj 462 133 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 8 | -1 -1 0 1; 9 | #X obj 346 225 dac~; 10 | #X obj 755 36 declare -path xfade; 11 | #X connect 1 0 5 0; 12 | #X connect 1 0 5 1; 13 | #X connect 2 0 1 0; 14 | #X connect 3 0 1 1; 15 | #X connect 4 0 1 2; 16 | -------------------------------------------------------------------------------- /macros/examples/complex_counter/test.pd: -------------------------------------------------------------------------------- 1 | #N canvas 2 74 1916 1004 10; 2 | #X declare -path .; 3 | #X obj 336 70 declare -path .; 4 | #X obj 89 62 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 5 | -1; 6 | #X floatatom 89 113 5 0 0 0 - - -, f 5; 7 | #X msg 122 49 set 23; 8 | #X msg 174 47 reset; 9 | #X obj 149 121 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 10 | -1 -1; 11 | #X obj 89 90 counter 0 3 -1; 12 | #X connect 1 0 6 0; 13 | #X connect 3 0 6 0; 14 | #X connect 4 0 6 0; 15 | #X connect 6 0 2 0; 16 | #X connect 6 1 5 0; 17 | -------------------------------------------------------------------------------- /external/src/method.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::CString; 2 | 3 | //an alias for the methods that pure data wants for registration with its API 4 | pub type PdMethod = unsafe extern "C" fn(); 5 | pub type PdCallbackMethod = unsafe extern "C" fn(*mut T); 6 | pub type PdDspMethod = unsafe extern "C" fn(*mut T, *mut *mut pd_sys::t_signal); 7 | pub type PdDspPerform = unsafe extern "C" fn(*mut pd_sys::t_int) -> *mut pd_sys::t_int; 8 | 9 | pub type B = unsafe extern "C" fn(*mut T); 10 | pub type SelList = 11 | unsafe extern "C" fn(*mut T, *mut pd_sys::t_symbol, std::os::raw::c_int, *const pd_sys::t_atom); 12 | 13 | include!(concat!(env!("OUT_DIR"), "/method-gen.rs")); 14 | -------------------------------------------------------------------------------- /external/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pd-ext" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | build = "build.rs" 7 | license = "BSD-3-Clause" 8 | homepage = "https://github.com/x37v/puredata-rust" 9 | keywords = ["audio", "sound", "music", "puredata", "multimedia"] 10 | categories = ["multimedia::audio", "multimedia::video", "multimedia::images"] 11 | description = "Rustified wrappers around and bindings for pd-sys for building Pure Data Externals" 12 | 13 | [dependencies] 14 | pd-sys = "0.1.0" 15 | field-offset = "0.1.1" 16 | 17 | [build-dependencies] 18 | quote = "0.6.13" 19 | syn = "0.15.42" 20 | proc-macro2 = "0.4.30" 21 | -------------------------------------------------------------------------------- /macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pd-ext-macros" 3 | version = "0.1.1" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | license = "BSD-3-Clause" 7 | homepage = "https://github.com/x37v/puredata-rust" 8 | keywords = ["audio", "sound", "music", "puredata", "multimedia"] 9 | categories = ["multimedia::audio", "multimedia::video", "multimedia::images"] 10 | description = "Macros for building Pure Data Externals with pd-ext and pd-sys" 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | 16 | [dependencies] 17 | #extra-traits for debugging 18 | syn = { version = "0.15.39", features=["full", "extra-traits"] } 19 | quote = "0.6.13" 20 | proc-macro2 = "0.4.30" 21 | -------------------------------------------------------------------------------- /macros/examples/helloworld/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pd_ext::builder::ControlExternalBuilder; 2 | use pd_ext::external::ControlExternal; 3 | use pd_ext::pd; 4 | use pd_ext_macros::external; 5 | use std::ffi::CString; 6 | 7 | //based on https://github.com/pure-data/externals-howto#my-first-external-helloworld 8 | external! { 9 | //the struct doesn't need to keep track of anything 10 | pub struct HelloWorld; 11 | 12 | impl ControlExternal for HelloWorld { 13 | fn new(_builder: &mut dyn ControlExternalBuilder) -> Result { 14 | Ok(Self { }) 15 | } 16 | } 17 | 18 | impl HelloWorld { 19 | #[bang] //indicates that a bang in Pd should call this 20 | pub fn bang(&mut self) { 21 | pd::post(CString::new("Hello world !!").unwrap()); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pd-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pd-sys" 3 | version = "0.1.0" 4 | authors = ["Alex Norman "] 5 | edition = "2018" 6 | license = "BSD-3-Clause" 7 | readme = "README.md" 8 | homepage = "https://github.com/x37v/puredata-rust" 9 | description = "FFI bindings for the Pure Data (Pd) multimedia programming language" 10 | keywords = ["audio", "sound", "music", "puredata", "multimedia"] 11 | categories = ["multimedia::audio", "multimedia::video", "multimedia::images"] 12 | include = [ 13 | "src/*.rs", 14 | "Cargo.toml", 15 | "README.md", 16 | "LICENSE.txt" 17 | ] 18 | build = false #disable to rebuild 19 | 20 | #[build-dependencies] 21 | #bindgen = "0.49.0" 22 | 23 | [features] 24 | default = [] 25 | 26 | #use double precision, experimental 27 | doubleprecision = [] 28 | 29 | #expose the instance interface, likely only useful from libpd? 30 | instance = [] 31 | 32 | -------------------------------------------------------------------------------- /pd-sys/README.md: -------------------------------------------------------------------------------- 1 | # Pure Data Rust Sys 2 | 3 | The `pd-sys` crate provides Rust FFI bindings for [Pure Data](https://puredata.info/) aka *pd*, a graphical multi-media programming language. 4 | The bindings are exclusively based on [m_pd.h](https://github.com/pure-data/pure-data/blob/master/src/m_pd.h) and most likely to be used 5 | for building plugins aka *externals*. 6 | 7 | 8 | ## Compile time features 9 | 10 | * **doubleprecision** - enable double precision *f64* floats. Experimental. 11 | * **instance** - enable the pd *instance* interfaces. Experimental. Maybe only useful from within [libpd](https://github.com/libpd/libpd)? 12 | 13 | 14 | ## Examples 15 | 16 | See [examples/helloworld/](examples/helloworld) for an example of how to use **pd-sys** to create an *external*. 17 | 18 | 19 | ## License 20 | 21 | This project is licensed with the ["Modified BSD License"](LICENSE.txt) 22 | Pure Data is licensed with the ["Standard Improved BSD License"](https://github.com/pure-data/pure-data/blob/master/LICENSE.txt) 23 | -------------------------------------------------------------------------------- /macros/examples/counter/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pd_ext::builder::ControlExternalBuilder; 2 | use pd_ext::external::ControlExternal; 3 | use pd_ext::outlet::{OutletSend, OutletType}; 4 | use pd_ext_macros::external; 5 | 6 | //based on https://github.com/pure-data/externals-howto#a-simple-external-counter 7 | external! { 8 | #[repr(packed)] 9 | pub struct Counter { 10 | count: isize, 11 | outlet: Box 12 | } 13 | 14 | impl ControlExternal for Counter { 15 | fn new(builder: &mut dyn ControlExternalBuilder) -> Result { 16 | let count = if let Some(atom) = builder.creation_args().iter().next() { 17 | atom.get_int().unwrap_or(0) as isize 18 | } else { 19 | 0isize 20 | }; 21 | let outlet = builder.new_message_outlet(OutletType::Float); 22 | Ok(Self { count, outlet }) 23 | } 24 | } 25 | 26 | impl Counter { 27 | #[bang] 28 | pub fn bang(&mut self) { 29 | let f = self.count as pd_sys::t_float; 30 | self.count = self.count.wrapping_add(1); 31 | self.outlet.send_float(f); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /external/src/external.rs: -------------------------------------------------------------------------------- 1 | use crate::builder::*; 2 | 3 | pub trait ControlExternal: Sized { 4 | fn new(builder: &mut dyn ControlExternalBuilder) -> Result; 5 | } 6 | 7 | pub trait SignalGenerator: Send { 8 | fn generate(&mut self, frames: usize, outputs: &mut [&mut [pd_sys::t_float]]); 9 | //called when dsp is set up, can be used to setup resources 10 | fn setup_generate(&mut self, _frames: usize, _outputs: usize) {} 11 | } 12 | 13 | pub trait SignalProcessor: Send { 14 | fn process( 15 | &mut self, 16 | frames: usize, 17 | inputs: &[&mut [pd_sys::t_float]], 18 | outputs: &mut [&mut [pd_sys::t_float]], 19 | ); 20 | //called when dsp is set up, can be used to setup resources 21 | fn setup_process(&mut self, _frames: usize, _inputs: usize, _outputs: usize) {} 22 | } 23 | 24 | pub trait SignalGeneratorExternal: Sized { 25 | fn new( 26 | builder: &mut dyn SignalGeneratorExternalBuilder, 27 | ) -> Result<(Self, Box), String>; 28 | } 29 | 30 | //has 1 default signal inlet 31 | pub trait SignalProcessorExternal: Sized { 32 | fn new( 33 | builder: &mut dyn SignalProcessorExternalBuilder, 34 | ) -> Result<(Self, Box), String>; 35 | } 36 | -------------------------------------------------------------------------------- /external/src/post.rs: -------------------------------------------------------------------------------- 1 | use crate::obj::AsObject; 2 | 3 | pub trait PdPost { 4 | fn post(&self, s: String); 5 | fn post_error(&self, s: String); 6 | } 7 | 8 | pub struct Post { 9 | x_obj: *mut pd_sys::t_object, 10 | } 11 | 12 | impl Post { 13 | pub fn new(owner: &mut dyn AsObject) -> Self { 14 | Self { 15 | x_obj: owner.as_obj(), 16 | } 17 | } 18 | pub fn error(s: String) { 19 | for l in s.lines() { 20 | let c = std::ffi::CString::new(l); 21 | if let Ok(c) = c { 22 | unsafe { 23 | pd_sys::error(c.as_ptr()); 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | impl PdPost for Post { 31 | fn post(&self, s: String) { 32 | for l in s.lines() { 33 | let c = std::ffi::CString::new(l); 34 | if let Ok(c) = c { 35 | unsafe { 36 | pd_sys::post(c.as_ptr()); 37 | } 38 | } 39 | } 40 | } 41 | fn post_error(&self, s: String) { 42 | for l in s.lines() { 43 | let c = std::ffi::CString::new(l); 44 | if let Ok(c) = c { 45 | unsafe { 46 | pd_sys::pd_error(std::mem::transmute::<_, _>(self.x_obj), c.as_ptr()); 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /pd-sys/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2019 Alex Norman 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /macros/examples/hellodsp/test.pd: -------------------------------------------------------------------------------- 1 | #N canvas 2 74 1916 1004 10; 2 | #X declare -path hellodsp; 3 | #X obj 347 298 hellodsp~; 4 | #X obj 336 232 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 5 | -1 -1; 6 | #X floatatom 651 144 5 0 0 0 - - -, f 5; 7 | #X obj 330 439 snapshot~; 8 | #X floatatom 330 463 5 0 0 0 - - -, f 5; 9 | #X obj 559 311 metro 20; 10 | #X obj 561 278 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 11 | 1; 12 | #X obj 393 440 snapshot~; 13 | #X floatatom 393 464 5 0 0 0 - - -, f 5; 14 | #X obj 460 438 snapshot~; 15 | #X floatatom 460 462 5 0 0 0 - - -, f 5; 16 | #X obj 560 225 loadbang; 17 | #X floatatom 466 142 5 0 0 0 - - -, f 5; 18 | #X obj 461 177 sig~; 19 | #X floatatom 507 140 5 0 0 0 - - -, f 5; 20 | #X obj 502 175 sig~; 21 | #X msg 135 73 \; pd dsp 1; 22 | #X floatatom 559 135 5 0 0 0 - - -, f 5; 23 | #X obj 554 170 sig~; 24 | #X msg 376 154 foo; 25 | #X msg 372 76 bar 3; 26 | #X msg 414 79 baz asdf; 27 | #X msg 346 124 foo 3234 asd; 28 | #X obj 755 36 declare -path hellodsp; 29 | #X connect 0 0 3 0; 30 | #X connect 0 1 7 0; 31 | #X connect 0 2 9 0; 32 | #X connect 1 0 0 0; 33 | #X connect 3 0 4 0; 34 | #X connect 5 0 3 0; 35 | #X connect 5 0 7 0; 36 | #X connect 5 0 9 0; 37 | #X connect 6 0 5 0; 38 | #X connect 7 0 8 0; 39 | #X connect 9 0 10 0; 40 | #X connect 11 0 6 0; 41 | #X connect 12 0 13 0; 42 | #X connect 13 0 0 0; 43 | #X connect 14 0 15 0; 44 | #X connect 15 0 0 1; 45 | #X connect 17 0 18 0; 46 | #X connect 18 0 0 2; 47 | #X connect 19 0 0 0; 48 | #X connect 20 0 0 0; 49 | #X connect 21 0 0 0; 50 | #X connect 22 0 0 0; 51 | -------------------------------------------------------------------------------- /macros/examples/helloall/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pd_ext::builder::ControlExternalBuilder; 2 | use pd_ext::external::ControlExternal; 3 | use pd_ext::outlet::{OutletSend, OutletType}; 4 | use pd_ext::pd; 5 | use pd_ext_macros::external; 6 | use std::ffi::CString; 7 | 8 | external! { 9 | #[name="hello/all"] //allows us to change the default name from "helloall" 10 | pub struct HelloAll { 11 | outlet: Box 12 | } 13 | 14 | impl ControlExternal for HelloAll { 15 | fn new(builder: &mut dyn ControlExternalBuilder) -> Result { 16 | let outlet = builder.new_message_outlet(OutletType::AnyThing); 17 | Ok(Self { outlet }) 18 | } 19 | } 20 | 21 | impl HelloAll { 22 | #[bang] //indicates that a bang in Pd should call this 23 | pub fn bang(&mut self) { 24 | pd::post(CString::new("Hello world !!").unwrap()); 25 | } 26 | 27 | #[list] //indicates that a list in Pd should call this 28 | pub fn list(&mut self, list: &[pd_ext::atom::Atom]) { 29 | let s = CString::new("toast").unwrap().into(); 30 | self.outlet.send_anything(s, &list); 31 | self.outlet.send_symbol(s); 32 | } 33 | 34 | #[anything] 35 | pub fn foo(&mut self, sel: pd_ext::symbol::Symbol, list: &[pd_ext::atom::Atom]) { 36 | self.outlet.send_symbol(sel); 37 | self.outlet.send_list(&list); 38 | } 39 | 40 | #[sel] 41 | pub fn bar(&mut self, s: pd_ext::symbol::Symbol) { 42 | self.outlet.send_symbol(s); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /macros/examples/xfade/src/lib.rs: -------------------------------------------------------------------------------- 1 | use itertools::izip; 2 | use pd_ext::builder::SignalProcessorExternalBuilder; 3 | use pd_ext::external::{SignalProcessor, SignalProcessorExternal}; 4 | use pd_ext_macros::external; 5 | use std::ops::Deref; 6 | 7 | //based on pan~ from: https://github.com/pure-data/externals-howto#a-signal-external-pan 8 | struct XFadeProcessor { 9 | //a passive float input, the xfade position 10 | pos: Box + Send>, 11 | } 12 | 13 | impl SignalProcessor for XFadeProcessor { 14 | //compute the audio 15 | fn process( 16 | &mut self, 17 | _frames: usize, 18 | inputs: &[&mut [pd_sys::t_float]], 19 | outputs: &mut [&mut [pd_sys::t_float]], 20 | ) { 21 | //read the value of our position setting 22 | let pos = num::clamp(**self.pos, 0f32.into(), 1f32.into()); 23 | 24 | //compute! 25 | let lpan = 1f32 - pos; 26 | let rpan = pos; 27 | for (o, l, r) in izip!(outputs[0].iter_mut(), inputs[0].iter(), inputs[1].iter()) { 28 | *o = *l * lpan + *r * rpan; 29 | } 30 | } 31 | } 32 | 33 | external! { 34 | pub struct XFade; 35 | 36 | impl SignalProcessorExternal for XFade { 37 | //build the object 38 | fn new(builder: &mut dyn SignalProcessorExternalBuilder) -> Result<(Self, Box), String> { 39 | //2 signal inlets (1 default) 40 | //1 float inlet (position) 41 | //1 signal outlet 42 | builder.new_signal_inlet(); 43 | let pos = builder.new_passive_float_inlet(0f32); 44 | builder.new_signal_outlet(); 45 | Ok((Self, Box::new(XFadeProcessor { pos }))) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pd-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | 5 | #[cfg(all(feature = "doubleprecision", feature = "instance"))] 6 | include!("./ffi-instance-doubleprecision.rs"); 7 | #[cfg(all(feature = "doubleprecision", not(feature = "instance")))] 8 | include!("./ffi-doubleprecision.rs"); 9 | #[cfg(all(not(feature = "doubleprecision"), feature = "instance"))] 10 | include!("./ffi-instance.rs"); 11 | #[cfg(not(any(feature = "doubleprecision", feature = "instance")))] 12 | include!("./ffi.rs"); 13 | 14 | use std::fmt; 15 | 16 | impl fmt::Display for &mut crate::_symbol { 17 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 18 | unsafe { 19 | let c = std::ffi::CStr::from_ptr(self.s_name); 20 | if let Ok(c) = c.to_str() { 21 | write!(f, "{}", c) 22 | } else { 23 | Err(std::fmt::Error {}) 24 | } 25 | } 26 | } 27 | } 28 | 29 | impl std::convert::From for &mut crate::_symbol { 30 | fn from(s: std::ffi::CString) -> Self { 31 | unsafe { 32 | let s = crate::gensym(s.as_ptr()); 33 | &mut *s 34 | } 35 | } 36 | } 37 | 38 | impl std::convert::From for &crate::_symbol { 39 | fn from(s: std::ffi::CString) -> Self { 40 | unsafe { 41 | let s = crate::gensym(s.as_ptr()); 42 | &*s 43 | } 44 | } 45 | } 46 | 47 | impl crate::_symbol { 48 | pub fn as_ptr(&mut self) -> *mut crate::_symbol { 49 | self as *mut crate::_symbol 50 | } 51 | } 52 | 53 | impl std::cmp::PartialEq for crate::_symbol { 54 | fn eq(&self, other: &Self) -> bool { 55 | let s = self as *const _; 56 | let o = other as *const _; 57 | s == o 58 | } 59 | } 60 | 61 | impl std::cmp::Eq for crate::_symbol {} 62 | -------------------------------------------------------------------------------- /macros/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "pd-ext-macros" 5 | version = "0.1.1" 6 | dependencies = [ 7 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 8 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 9 | "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", 10 | ] 11 | 12 | [[package]] 13 | name = "proc-macro2" 14 | version = "0.4.30" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | dependencies = [ 17 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 18 | ] 19 | 20 | [[package]] 21 | name = "quote" 22 | version = "0.6.13" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | dependencies = [ 25 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "syn" 30 | version = "0.15.44" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | dependencies = [ 33 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 36 | ] 37 | 38 | [[package]] 39 | name = "unicode-xid" 40 | version = "0.1.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | 43 | [metadata] 44 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 45 | "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 46 | "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" 47 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 48 | -------------------------------------------------------------------------------- /external/src/inlet.rs: -------------------------------------------------------------------------------- 1 | use crate::obj::AsObject; 2 | 3 | pub trait InletSignal {} 4 | 5 | pub struct SignalInlet { 6 | ptr: *mut pd_sys::_inlet, 7 | } 8 | 9 | pub mod passive { 10 | use crate::obj::AsObject; 11 | use std::boxed::Box; 12 | use std::ops::Deref; 13 | 14 | pub struct FloatInlet { 15 | value: Box, 16 | inlet: *mut pd_sys::_inlet, 17 | } 18 | 19 | //to be able to use passive floats in DSP it must be Send 20 | //PD must assume it is Sync too.. 21 | unsafe impl Sync for FloatInlet {} 22 | unsafe impl Send for FloatInlet {} 23 | 24 | impl FloatInlet { 25 | pub fn new(owner: &mut dyn AsObject, initial_value: pd_sys::t_float) -> Self { 26 | let value = Box::new(initial_value); 27 | unsafe { 28 | let value = Box::into_raw(value); 29 | let inlet = pd_sys::floatinlet_new(owner.as_obj(), value); 30 | let value = Box::from_raw(value); 31 | Self { inlet, value } 32 | } 33 | } 34 | } 35 | 36 | impl Deref for FloatInlet { 37 | type Target = pd_sys::t_float; 38 | 39 | fn deref(&self) -> &pd_sys::t_float { 40 | self.value.deref() 41 | } 42 | } 43 | 44 | impl Drop for FloatInlet { 45 | fn drop(&mut self) { 46 | unsafe { 47 | pd_sys::inlet_free(self.inlet); 48 | } 49 | } 50 | } 51 | } 52 | 53 | impl SignalInlet { 54 | pub fn new(owner: &mut dyn AsObject) -> Self { 55 | unsafe { 56 | let obj = owner.as_obj(); 57 | Self { 58 | ptr: pd_sys::inlet_new( 59 | obj, 60 | &mut (*obj).te_g.g_pd, 61 | &mut pd_sys::s_signal, 62 | &mut pd_sys::s_signal, 63 | ), 64 | } 65 | } 66 | } 67 | } 68 | 69 | impl Drop for SignalInlet { 70 | fn drop(&mut self) { 71 | unsafe { 72 | pd_sys::inlet_free(self.ptr); 73 | } 74 | } 75 | } 76 | 77 | impl InletSignal for SignalInlet {} 78 | -------------------------------------------------------------------------------- /macros/examples/hellodsp/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pd_ext::builder::SignalProcessorExternalBuilder; 2 | use pd_ext::external::{SignalProcessor, SignalProcessorExternal}; 3 | use pd_ext::pd; 4 | 5 | use pd_ext_macros::external; 6 | 7 | use std::ffi::CString; 8 | 9 | struct Processor; 10 | 11 | impl SignalProcessor for Processor { 12 | fn process( 13 | &mut self, 14 | _frames: usize, 15 | inputs: &[&mut [pd_sys::t_float]], 16 | outputs: &mut [&mut [pd_sys::t_float]], 17 | ) { 18 | for (output, input) in outputs.iter_mut().zip(inputs.iter()) { 19 | output.copy_from_slice(input); 20 | } 21 | } 22 | } 23 | 24 | external! { 25 | pub struct HelloDSP; 26 | 27 | impl HelloDSP { 28 | #[bang] 29 | pub fn bang(&mut self) { 30 | let m = CString::new(format!("hello").to_string()).expect("CString::new failed"); 31 | pd::post(m); 32 | } 33 | 34 | #[sel(defaults=1)] 35 | pub fn foo(&mut self, arg1: pd_sys::t_float, arg2: pd_ext::symbol::Symbol) { 36 | let m = 37 | CString::new(format!("got foo {} {}", arg1, arg2).to_string()).expect("CString::new failed"); 38 | pd::post(m); 39 | } 40 | 41 | #[sel(defaults=1)] 42 | pub fn bar(&mut self, arg1: pd_sys::t_float) { 43 | let m = 44 | CString::new(format!("got bar {}", arg1).to_string()).expect("CString::new failed"); 45 | pd::post(m); 46 | } 47 | 48 | #[sel(defaults=1)] 49 | pub fn baz(&mut self, arg1: pd_ext::symbol::Symbol) { 50 | let m = 51 | CString::new(format!("got baz {}", arg1)).expect("CString::new failed"); 52 | pd::post(m); 53 | } 54 | } 55 | 56 | impl SignalProcessorExternal for HelloDSP { 57 | fn new(builder: &mut dyn SignalProcessorExternalBuilder) -> Result<(Self, Box), String> { 58 | builder.new_signal_outlet(); 59 | builder.new_signal_outlet(); 60 | builder.new_signal_outlet(); 61 | builder.new_signal_inlet(); 62 | builder.new_signal_inlet(); 63 | Ok((Self { }, Box::new(Processor))) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /external/src/clock.rs: -------------------------------------------------------------------------------- 1 | use crate::obj::AsObject; 2 | 3 | /* 4 | EXTERN t_clock *clock_new(void *owner, t_method fn); 5 | EXTERN void clock_set(t_clock *x, double systime); 6 | EXTERN void clock_delay(t_clock *x, double delaytime); 7 | EXTERN void clock_unset(t_clock *x); 8 | EXTERN void clock_setunit(t_clock *x, double timeunit, int sampflag); 9 | EXTERN double clock_getlogicaltime(void); 10 | EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */ 11 | EXTERN double clock_gettimesince(double prevsystime); 12 | EXTERN double clock_gettimesincewithunits(double prevsystime, 13 | double units, int sampflag); 14 | EXTERN double clock_getsystimeafter(double delaytime); 15 | EXTERN void clock_free(t_clock *x); 16 | */ 17 | 18 | //TODO figure out units and provide those as enum 19 | 20 | pub struct Clock(*mut pd_sys::_clock); 21 | 22 | impl Clock { 23 | pub fn logical_time() -> f64 { 24 | unsafe { pd_sys::clock_getlogicaltime() } 25 | } 26 | 27 | pub fn sys_time_after(delaytime: f64) -> f64 { 28 | unsafe { pd_sys::clock_getsystimeafter(delaytime) } 29 | } 30 | 31 | pub fn time_since(prev: f64) -> f64 { 32 | unsafe { pd_sys::clock_gettimesince(prev) } 33 | } 34 | 35 | pub fn new(owner: &mut dyn AsObject, method: crate::method::PdCallbackMethod) -> Self { 36 | unsafe { 37 | Self(pd_sys::clock_new( 38 | std::mem::transmute::<_, _>(owner.as_obj()), 39 | Some(std::mem::transmute::<_, _>(method)), 40 | )) 41 | } 42 | } 43 | 44 | /// call back at a delayed time 45 | pub fn delay(&mut self, delay: f64) { 46 | unsafe { 47 | pd_sys::clock_delay(self.0, delay); 48 | } 49 | } 50 | 51 | /// call back at an absolute time 52 | pub fn set(&mut self, absolute: f64) { 53 | unsafe { 54 | pd_sys::clock_set(self.0, absolute); 55 | } 56 | } 57 | 58 | /// cancel the clock (unset) 59 | pub fn cancel(&mut self) { 60 | unsafe { 61 | pd_sys::clock_unset(self.0); 62 | } 63 | } 64 | } 65 | 66 | impl Drop for Clock { 67 | fn drop(&mut self) { 68 | unsafe { 69 | pd_sys::clock_free(self.0); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pd-sys/examples/helloworld/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(clippy::transmute_ptr_to_ptr)] 2 | use std::ffi::CString; 3 | 4 | static mut HELLOWORLD_CLASS: Option<*mut pd_sys::_class> = None; 5 | 6 | #[repr(C)] 7 | pub struct HelloWorld { 8 | x_obj: pd_sys::t_object, 9 | } 10 | 11 | impl HelloWorld { 12 | pub extern "C" fn got_float(&mut self, f: pd_sys::t_float) { 13 | unsafe { 14 | let m = 15 | CString::new(format!("got float {}", f).to_string()).expect("CString::new failed"); 16 | pd_sys::post(m.as_ptr()); 17 | } 18 | } 19 | 20 | fn bang(&mut self) { 21 | let m = CString::new("HELLO WORLD!!").expect("CString::new failed"); 22 | unsafe { 23 | pd_sys::post(m.as_ptr()); 24 | } 25 | } 26 | 27 | pub unsafe extern "C" fn bang_trampoline(s: *mut Self) { 28 | let obj = &mut *(s as *mut Self); 29 | obj.bang(); 30 | } 31 | 32 | pub extern "C" fn new_pd() -> *mut ::std::os::raw::c_void { 33 | unsafe { 34 | let obj = std::mem::transmute::<*mut pd_sys::t_pd, *mut Self>(pd_sys::pd_new( 35 | HELLOWORLD_CLASS.unwrap(), 36 | )); 37 | obj as *mut ::std::os::raw::c_void 38 | } 39 | } 40 | } 41 | 42 | #[no_mangle] 43 | pub unsafe extern "C" fn helloworld_setup() { 44 | let name = CString::new("helloworld").expect("CString::new failed"); 45 | let c = pd_sys::class_new( 46 | pd_sys::gensym(name.as_ptr()), 47 | Some(std::mem::transmute::< 48 | extern "C" fn() -> *mut ::std::os::raw::c_void, 49 | unsafe extern "C" fn() -> *mut ::std::os::raw::c_void, 50 | >(HelloWorld::new_pd)), 51 | None, 52 | std::mem::size_of::(), 53 | 0, 54 | 0, 55 | ); 56 | HELLOWORLD_CLASS = Some(c); 57 | pd_sys::class_addbang( 58 | c, 59 | Some(std::mem::transmute::< 60 | unsafe extern "C" fn(*mut HelloWorld), 61 | unsafe extern "C" fn(), 62 | >(HelloWorld::bang_trampoline)), 63 | ); 64 | pd_sys::class_addmethod( 65 | c, 66 | Some(std::mem::transmute::< 67 | extern "C" fn(&mut HelloWorld, pd_sys::t_float), 68 | unsafe extern "C" fn(), 69 | >(HelloWorld::got_float)), 70 | pd_sys::gensym(name.as_ptr()), 71 | pd_sys::t_atomtype::A_DEFFLOAT, 72 | 0, 73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pure Data Externals in Pure Rust 2 | 3 | Does not require any C, builds entirely with Cargo. 4 | 5 | ## Requirements 6 | 7 | * [Rust and Cargo](https://www.rust-lang.org/tools/install), at least rust 1.34 8 | * [Pure Data](https://puredata.info), to run, not to build. 9 | 10 | ## Crates/Subdirs 11 | 12 | * [pd-sys](pd-sys) The basic generated bindings to `m_pd.h`, all you need to roll your own interface to puredata. 13 | * [external](external) The Rust specific wrappers and ease of use methods for creating externals. 14 | * [macros](macros) The macros that generate all the guts for externals you don't want to have to deal with yourself, used the examples. 15 | * [macros/examples](macros/examples) See below. 16 | * [utils](utils/README.md) Utilities for building and packaging externals. 17 | 18 | ## Examples 19 | 20 | The examples can all be built with `cargo build` but you can also use `cargo-make` for more helpful features. 21 | See [utils/README.md](utils/README.md) for more details on the `cargo-make` setup. 22 | 23 | * [helloworld](macros/examples/helloworld/src/lib.rs) based on the HOWTO [my first external: helloworld](https://github.com/pure-data/externals-howto#my-first-external-helloworld) example 24 | * [counter](macros/examples/counter/src/lib.rs) based on the HOWTO [a simple external: counter](https://github.com/pure-data/externals-howto#a-simple-external-counter) example 25 | * [complex_counter](macros/examples/complex_counter/src/lib.rs) based on the HOWTO [a complex external: counter](https://github.com/pure-data/externals-howto#a-complex-external-counter) example 26 | * [xfade](macros/examples/xfade/src/lib.rs) based on the, misnamed, HOWTO [a signal-external pan~](https://github.com/pure-data/externals-howto#a-signal-external-pan) example 27 | 28 | ``` 29 | cd macros/examples/helloworld && cargo build 30 | ``` 31 | 32 | or 33 | 34 | ``` 35 | cd macros/examples/helloworld && cargo make run 36 | ``` 37 | 38 | If you want to see what code the macro actually produces, use `cargo-expand`. 39 | 40 | ## TODO 41 | 42 | * Documentation 43 | * Expose pointer methods 44 | * Support more creation argument configurations 45 | * Clean up macros 46 | * [crates.io](https://crates.io/) release 47 | 48 | ## References 49 | 50 | * [Pure Data](https://puredata.info) 51 | * [HOWTO write an External for Pure Data](https://github.com/pure-data/externals-howto) 52 | 53 | ## Links 54 | 55 | * [kmtr pd_ext_rust](https://github.com/kmtr/pd_ext_rust): another Pure Data External solution for rust, requires C. 56 | * [RustAudio](https://github.com/RustAudio) 57 | -------------------------------------------------------------------------------- /pd-sys/build.rs: -------------------------------------------------------------------------------- 1 | //used to rebuild the ffi, disabled by default 2 | use std::path::PathBuf; 3 | 4 | fn main() { 5 | let vars = [ 6 | "s_pointer", 7 | "s_float", 8 | "s_symbol", 9 | "s_bang", 10 | "s_list", 11 | "s_anything", 12 | "s_signal", 13 | "s__N", 14 | "s__X", 15 | "s_x", 16 | "s_y", 17 | "s_", 18 | "CLASS.*", 19 | ]; 20 | let funcs = [ 21 | "gensym", 22 | "atom_.*", 23 | "binbuf_.*", 24 | "clock_.*", 25 | "pd_.*", 26 | "gpointer_.*", 27 | ".*inlet.*", 28 | ".*outlet.*", 29 | "glob_.*", 30 | "canvas_.*", 31 | "sys_.*", 32 | "signal.*", 33 | "symbol.*", 34 | "class_.*", 35 | "obj_.*", 36 | "plus_perform", 37 | "zero_perform", 38 | "copy_perform", 39 | "dsp_.*", 40 | "ilog2", 41 | "mayer_.*", 42 | "resample.*", 43 | "garray_.*", 44 | "value_.*", 45 | ".*bytes", 46 | "post", 47 | "startpost", 48 | "poststring", 49 | "postfloat", 50 | "postatom", 51 | "endpost", 52 | "error", 53 | "verbose", 54 | "bug", 55 | "pd_error", 56 | "logpost", 57 | ]; 58 | let types = ["t_atomtype", "t_symbol", "t_signal", "t_floatarg"]; 59 | 60 | let variants = [ 61 | None, 62 | Some("doubleprecision"), 63 | Some("instance"), 64 | Some("instance-doubleprecision"), 65 | ]; 66 | 67 | for v in variants.iter() { 68 | let (header, filename) = match v { 69 | Some(s) => (format!("wrapper-{}.h", s), format!("ffi-{}.rs", s)), 70 | None => ("wrapper.h".to_string(), "ffi.rs".to_string()), 71 | }; 72 | let mut builder = bindgen::Builder::default() 73 | .header(format!("wrappers/{}", header)) 74 | .constified_enum_module("t_atomtype") 75 | .rustfmt_bindings(true); 76 | 77 | builder = vars.iter().fold(builder, |b, i| b.whitelist_var(i)); 78 | builder = funcs.iter().fold(builder, |b, i| b.whitelist_function(i)); 79 | builder = types.iter().fold(builder, |b, i| b.whitelist_type(i)); 80 | 81 | let bindings = builder.generate().expect("Unable to generate bindings"); 82 | 83 | //let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()); 84 | let out_path = PathBuf::from("src"); 85 | bindings 86 | .write_to_file(out_path.join(filename)) 87 | .expect("Couldn't write bindings!"); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /utils/Makefile.toml: -------------------------------------------------------------------------------- 1 | # vim: set ts=4 sw=4 expandtab: 2 | [config] 3 | additional_profiles = [ "release" ] 4 | 5 | [env] 6 | PLATFORM_DYLIB_EXT = { source = "${CARGO_MAKE_RUST_TARGET_OS}", default_value = "so", mapping = {"macos" = "dylib", "windows" = "dll" } } 7 | PLATFORM_EXTERNAL_PREFIX = { source = "${CARGO_MAKE_RUST_TARGET_OS}", default_value = "l", mapping = {"linux" = "l", "macos" = "d", "windows" = "m", "openbsd" = "o", "freebsd" = "l" } } 8 | PLATFORM_EXTERNAL_SUFFIX = { source = "${CARGO_MAKE_RUST_TARGET_ARCH}", default_value = "ERROR", mapping = {"x86" = "i386", "x86_64" = "amd64", "arm" = "arm", "aarch64" = "arm64", "powerpc" = "ppc" } } 9 | PLATFORM_EXTERNAL_EXT = "${PLATFORM_EXTERNAL_PREFIX}_${PLATFORM_EXTERNAL_SUFFIX}" 10 | 11 | [env.development] 12 | BUILD_ARGS = "build" 13 | PROFILE_TARGET_DIR = "target/debug" 14 | 15 | [env.release] 16 | BUILD_ARGS = "build|--release" 17 | PROFILE_TARGET_DIR = "target/release" 18 | 19 | [tasks.echo] 20 | script = [ 21 | ''' 22 | echo PLATFORM_DYLIB_EXT: ${PLATFORM_DYLIB_EXT} 23 | echo PLATFORM_EXTERNAL_EXT: ${PLATFORM_EXTERNAL_EXT} 24 | ''' 25 | ] 26 | 27 | [tasks.build] 28 | args = ["@@split(BUILD_ARGS,|)"] 29 | 30 | [tasks.clean] 31 | dependencies = ["clean-artifacts"] 32 | command = "cargo" 33 | args = ["clean"] 34 | 35 | [tasks.post-build] 36 | dependencies = ["move"] 37 | 38 | [tasks.clean-artifacts] 39 | script_runner = "@shell" 40 | script = [ "rm -rf ${CARGO_MAKE_CRATE_FS_NAME} *.dek*" ] 41 | 42 | [tasks.package] 43 | dependencies = ["move"] 44 | command = "deken" 45 | args = ["package", "-v", "${CARGO_MAKE_CRATE_VERSION}", "${CARGO_MAKE_CRATE_FS_NAME}"] 46 | 47 | [tasks.platform-env.linux] 48 | env = { "PLATFORM_EXTERNAL_EXT" = "pd_linux", "PLATFORM_DYLIB_EXT" = "so" } 49 | private = true 50 | 51 | [tasks.platform-env.mac] 52 | env = { "PLATFORM_EXTERNAL_EXT" = "pd_darwin", "PLATFORM_DYLIB_EXT" = "dylib" } 53 | private = true 54 | 55 | [tasks.name-env] 56 | env = { "LIB_TILDE" = "${PROFILE_TARGET_DIR}/lib${CARGO_MAKE_CRATE_FS_NAME}_tilde.${PLATFORM_DYLIB_EXT}", "LIB" = "${PROFILE_TARGET_DIR}/lib${CARGO_MAKE_CRATE_FS_NAME}.${PLATFORM_DYLIB_EXT}", "EXTERNAL_TILDE" = "${CARGO_MAKE_CRATE_FS_NAME}~.${PLATFORM_EXTERNAL_EXT}", "EXTERNAL" = "${CARGO_MAKE_CRATE_FS_NAME}.${PLATFORM_EXTERNAL_EXT}" } 57 | private = true 58 | 59 | [tasks.move] 60 | dependencies = ["build", "name-env"] 61 | script_runner = "@shell" 62 | script = [ 63 | ''' 64 | mkdir -p ${CARGO_MAKE_CRATE_FS_NAME} 65 | [ -f ${LIB_TILDE} ] && rsync -a ${LIB_TILDE} ${CARGO_MAKE_CRATE_FS_NAME}/${EXTERNAL_TILDE} || rsync -a ${LIB} ${CARGO_MAKE_CRATE_FS_NAME}/${EXTERNAL} 66 | ''' 67 | ] 68 | 69 | [tasks.run.linux] 70 | dependencies = ["move"] 71 | command = "pd" 72 | args = ["test.pd"] 73 | 74 | [tasks.run.mac] 75 | dependencies = ["move"] 76 | command = "open" 77 | args = ["test.pd"] 78 | -------------------------------------------------------------------------------- /external/src/alloc.rs: -------------------------------------------------------------------------------- 1 | use std::mem::size_of; 2 | use std::ops::{Deref, DerefMut}; 3 | use std::slice; 4 | 5 | ///A slice allocated and freed using pd_sys 6 | #[repr(transparent)] 7 | pub struct Slice(pub &'static mut [T]); 8 | 9 | impl Slice where T: 'static + Copy {} 10 | 11 | impl Default for Slice 12 | where 13 | T: 'static + Sized + Copy, 14 | { 15 | fn default() -> Self { 16 | Self(&mut []) 17 | } 18 | } 19 | 20 | impl Slice 21 | where 22 | T: 'static + Sized + Copy + Default, 23 | { 24 | /// Create a new slice. 25 | /// 26 | /// # Arguments 27 | /// 28 | /// * `len` - the new slice length. 29 | /// 30 | /// # Remarks 31 | /// 32 | /// This will set all the current content to `Default::default()` for `T`. 33 | pub fn new(len: usize) -> Self { 34 | let mut s = Self::default(); 35 | s.resize(len); 36 | s 37 | } 38 | 39 | /// Resize the slice. 40 | /// 41 | /// # Arguments 42 | /// 43 | /// * `len` - the new slice length. 44 | /// 45 | /// # Remarks 46 | /// 47 | /// If actually resized, this will set all the content to `Default::default()` for `T`. 48 | pub fn resize(&mut self, len: usize) { 49 | if self.0.len() != len { 50 | //TODO use resizebytes? 51 | self.cleanup(); 52 | self.alloc(len); 53 | } 54 | } 55 | 56 | fn alloc(&mut self, len: usize) { 57 | if len == 0 { 58 | self.0 = &mut []; 59 | } else { 60 | unsafe { 61 | let bytes = pd_sys::getbytes(len * size_of::()); 62 | let bytes = std::mem::transmute::<_, *mut T>(bytes); 63 | self.0 = slice::from_raw_parts_mut(bytes, len); 64 | } 65 | for i in self.0.iter_mut() { 66 | *i = Default::default(); 67 | } 68 | } 69 | } 70 | } 71 | 72 | impl Deref for Slice 73 | where 74 | T: 'static + Sized + Copy, 75 | { 76 | type Target = [T]; 77 | 78 | fn deref(&self) -> &Self::Target { 79 | &self.0 80 | } 81 | } 82 | 83 | impl DerefMut for Slice 84 | where 85 | T: 'static + Sized + Copy, 86 | { 87 | fn deref_mut(&mut self) -> &mut Self::Target { 88 | &mut self.0 89 | } 90 | } 91 | 92 | impl Slice 93 | where 94 | T: 'static + Sized + Copy, 95 | { 96 | fn cleanup(&mut self) { 97 | if self.0.len() > 0 { 98 | unsafe { 99 | pd_sys::freebytes( 100 | self.0.as_mut_ptr() as *mut ::std::os::raw::c_void, 101 | self.0.len() * size_of::(), 102 | ); 103 | self.0 = slice::from_raw_parts_mut(std::ptr::null_mut(), 0) 104 | } 105 | } 106 | } 107 | } 108 | 109 | impl Drop for Slice 110 | where 111 | T: 'static + Sized + Copy, 112 | { 113 | fn drop(&mut self) { 114 | self.cleanup(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /macros/examples/complex_counter/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pd_ext::builder::ControlExternalBuilder; 2 | use pd_ext::external::ControlExternal; 3 | use pd_ext::outlet::{OutletSend, OutletType}; 4 | use pd_ext_macros::external; 5 | 6 | //https://github.com/pure-data/externals-howto#a-complex-external-counter 7 | external! { 8 | pub struct Counter { 9 | count: isize, 10 | step: isize, 11 | range: (isize, isize), 12 | count_outlet: Box, 13 | wrap_outlet: Box, 14 | } 15 | 16 | impl ControlExternal for Counter { 17 | fn new(builder: &mut dyn ControlExternalBuilder) -> Result { 18 | 19 | //parse the args 20 | let mut step = 1; 21 | let mut range = (0, 1); 22 | let mut args = builder.creation_args().iter(); 23 | if let Some(atom) = args.next() { 24 | range.0 = atom.get_int().unwrap_or(0) as isize; 25 | if let Some(atom) = args.next() { 26 | range.1 = atom.get_int().unwrap_or(1) as isize; 27 | if let Some(atom) = args.next() { 28 | step = atom.get_int().unwrap_or(1) as isize; 29 | } 30 | } 31 | } 32 | 33 | //reorder if needed 34 | if range.0 > range.1 { 35 | range = (range.1, range.0); 36 | } 37 | 38 | let count_outlet = builder.new_message_outlet(OutletType::Float); 39 | let wrap_outlet = builder.new_message_outlet(OutletType::Bang); 40 | Ok(Self { count: 0, step, range, count_outlet, wrap_outlet }) 41 | } 42 | } 43 | 44 | impl Counter { 45 | #[bang] 46 | pub fn bang(&mut self) { 47 | let f = self.count as pd_sys::t_float; 48 | self.count = self.count.wrapping_add(self.step); 49 | 50 | if self.range.0 != self.range.1 { 51 | //if we're stepping up 52 | if self.step > 0 { 53 | //and count has exceeded the upper range 54 | if self.count > self.range.1 { 55 | self.count = self.range.0; //set to lower 56 | self.wrap_outlet.send_bang(); 57 | } 58 | } else { 59 | if self.count < self.range.0 { 60 | self.count = self.range.1; //set to upper 61 | self.wrap_outlet.send_bang(); 62 | } 63 | } 64 | } 65 | 66 | self.count_outlet.send_float(f); 67 | } 68 | 69 | #[sel(defaults=1)] 70 | pub fn set(&mut self, v: pd_sys::t_float) { 71 | self.count = v as isize; 72 | } 73 | 74 | #[sel] 75 | pub fn reset(&mut self) { 76 | self.count = self.range.0; 77 | } 78 | 79 | #[sel(defaults=2)] 80 | pub fn bound(&mut self, bottom: pd_sys::t_float, top: pd_sys::t_float) { 81 | self.range = 82 | if bottom > top { 83 | (top as isize, bottom as isize) 84 | } else { 85 | (bottom as isize, top as isize) 86 | }; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /macros/examples/counter/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "counter" 5 | version = "0.1.0" 6 | dependencies = [ 7 | "pd-ext 0.1.0", 8 | "pd-ext-macros 0.1.1", 9 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 10 | ] 11 | 12 | [[package]] 13 | name = "field-offset" 14 | version = "0.1.1" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | 17 | [[package]] 18 | name = "pd-ext" 19 | version = "0.1.0" 20 | dependencies = [ 21 | "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "pd-ext-macros" 30 | version = "0.1.1" 31 | dependencies = [ 32 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 33 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 35 | ] 36 | 37 | [[package]] 38 | name = "pd-sys" 39 | version = "0.1.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | 42 | [[package]] 43 | name = "proc-macro2" 44 | version = "0.4.30" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | dependencies = [ 47 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 48 | ] 49 | 50 | [[package]] 51 | name = "quote" 52 | version = "0.6.13" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | dependencies = [ 55 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 56 | ] 57 | 58 | [[package]] 59 | name = "syn" 60 | version = "0.15.43" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | dependencies = [ 63 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "unicode-xid" 70 | version = "0.1.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [metadata] 74 | "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" 75 | "checksum pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d277c9097b9df013dd6c0712ec0f55fbcd0cf78c6e5c2e509c022d0c353fedc" 76 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 77 | "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 78 | "checksum syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ee06ea4b620ab59a2267c6b48be16244a3389f8bfa0986bdd15c35b890b00af3" 79 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 80 | -------------------------------------------------------------------------------- /macros/examples/helloall/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "field-offset" 5 | version = "0.1.1" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "helloall" 10 | version = "0.1.0" 11 | dependencies = [ 12 | "pd-ext 0.1.0", 13 | "pd-ext-macros 0.1.1", 14 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 15 | ] 16 | 17 | [[package]] 18 | name = "pd-ext" 19 | version = "0.1.0" 20 | dependencies = [ 21 | "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "pd-ext-macros" 30 | version = "0.1.1" 31 | dependencies = [ 32 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 33 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 35 | ] 36 | 37 | [[package]] 38 | name = "pd-sys" 39 | version = "0.1.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | 42 | [[package]] 43 | name = "proc-macro2" 44 | version = "0.4.30" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | dependencies = [ 47 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 48 | ] 49 | 50 | [[package]] 51 | name = "quote" 52 | version = "0.6.13" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | dependencies = [ 55 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 56 | ] 57 | 58 | [[package]] 59 | name = "syn" 60 | version = "0.15.43" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | dependencies = [ 63 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "unicode-xid" 70 | version = "0.1.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [metadata] 74 | "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" 75 | "checksum pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d277c9097b9df013dd6c0712ec0f55fbcd0cf78c6e5c2e509c022d0c353fedc" 76 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 77 | "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 78 | "checksum syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ee06ea4b620ab59a2267c6b48be16244a3389f8bfa0986bdd15c35b890b00af3" 79 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 80 | -------------------------------------------------------------------------------- /macros/examples/hellodsp/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "field-offset" 5 | version = "0.1.1" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "hellodsp" 10 | version = "0.1.0" 11 | dependencies = [ 12 | "pd-ext 0.1.0", 13 | "pd-ext-macros 0.1.1", 14 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 15 | ] 16 | 17 | [[package]] 18 | name = "pd-ext" 19 | version = "0.1.0" 20 | dependencies = [ 21 | "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "pd-ext-macros" 30 | version = "0.1.1" 31 | dependencies = [ 32 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 33 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 35 | ] 36 | 37 | [[package]] 38 | name = "pd-sys" 39 | version = "0.1.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | 42 | [[package]] 43 | name = "proc-macro2" 44 | version = "0.4.30" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | dependencies = [ 47 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 48 | ] 49 | 50 | [[package]] 51 | name = "quote" 52 | version = "0.6.13" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | dependencies = [ 55 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 56 | ] 57 | 58 | [[package]] 59 | name = "syn" 60 | version = "0.15.43" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | dependencies = [ 63 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "unicode-xid" 70 | version = "0.1.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [metadata] 74 | "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" 75 | "checksum pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d277c9097b9df013dd6c0712ec0f55fbcd0cf78c6e5c2e509c022d0c353fedc" 76 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 77 | "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 78 | "checksum syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ee06ea4b620ab59a2267c6b48be16244a3389f8bfa0986bdd15c35b890b00af3" 79 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 80 | -------------------------------------------------------------------------------- /macros/examples/helloworld/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "field-offset" 5 | version = "0.1.1" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "helloworld" 10 | version = "0.1.0" 11 | dependencies = [ 12 | "pd-ext 0.1.0", 13 | "pd-ext-macros 0.1.1", 14 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 15 | ] 16 | 17 | [[package]] 18 | name = "pd-ext" 19 | version = "0.1.0" 20 | dependencies = [ 21 | "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "pd-ext-macros" 30 | version = "0.1.1" 31 | dependencies = [ 32 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 33 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 35 | ] 36 | 37 | [[package]] 38 | name = "pd-sys" 39 | version = "0.1.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | 42 | [[package]] 43 | name = "proc-macro2" 44 | version = "0.4.30" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | dependencies = [ 47 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 48 | ] 49 | 50 | [[package]] 51 | name = "quote" 52 | version = "0.6.13" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | dependencies = [ 55 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 56 | ] 57 | 58 | [[package]] 59 | name = "syn" 60 | version = "0.15.43" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | dependencies = [ 63 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "unicode-xid" 70 | version = "0.1.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [metadata] 74 | "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" 75 | "checksum pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d277c9097b9df013dd6c0712ec0f55fbcd0cf78c6e5c2e509c022d0c353fedc" 76 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 77 | "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 78 | "checksum syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ee06ea4b620ab59a2267c6b48be16244a3389f8bfa0986bdd15c35b890b00af3" 79 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 80 | -------------------------------------------------------------------------------- /macros/examples/complex_counter/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "complex_counter" 5 | version = "0.1.0" 6 | dependencies = [ 7 | "pd-ext 0.1.0", 8 | "pd-ext-macros 0.1.1", 9 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 10 | ] 11 | 12 | [[package]] 13 | name = "field-offset" 14 | version = "0.1.1" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | 17 | [[package]] 18 | name = "pd-ext" 19 | version = "0.1.0" 20 | dependencies = [ 21 | "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "pd-ext-macros" 30 | version = "0.1.1" 31 | dependencies = [ 32 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 33 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 35 | ] 36 | 37 | [[package]] 38 | name = "pd-sys" 39 | version = "0.1.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | 42 | [[package]] 43 | name = "proc-macro2" 44 | version = "0.4.30" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | dependencies = [ 47 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 48 | ] 49 | 50 | [[package]] 51 | name = "quote" 52 | version = "0.6.13" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | dependencies = [ 55 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 56 | ] 57 | 58 | [[package]] 59 | name = "syn" 60 | version = "0.15.43" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | dependencies = [ 63 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "unicode-xid" 70 | version = "0.1.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [metadata] 74 | "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" 75 | "checksum pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d277c9097b9df013dd6c0712ec0f55fbcd0cf78c6e5c2e509c022d0c353fedc" 76 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 77 | "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 78 | "checksum syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ee06ea4b620ab59a2267c6b48be16244a3389f8bfa0986bdd15c35b890b00af3" 79 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 80 | -------------------------------------------------------------------------------- /external/src/symbol.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use std::ffi::OsStr; 4 | use std::hash::{Hash, Hasher}; 5 | 6 | #[cfg(unix)] 7 | use std::os::unix::ffi::OsStrExt; 8 | 9 | #[repr(transparent)] 10 | pub struct Symbol(*mut pd_sys::t_symbol); 11 | 12 | impl Symbol { 13 | pub fn inner(&self) -> *mut pd_sys::t_symbol { 14 | self.0 15 | } 16 | } 17 | 18 | impl std::convert::TryFrom<*mut pd_sys::t_symbol> for Symbol { 19 | type Error = &'static str; 20 | fn try_from(s: *mut pd_sys::t_symbol) -> Result { 21 | if s.is_null() { 22 | Err("null ptr") 23 | } else { 24 | Ok(Self(s)) 25 | } 26 | } 27 | } 28 | 29 | impl std::convert::TryFrom<&'static str> for Symbol { 30 | type Error = &'static str; 31 | fn try_from(s: &'static str) -> Result { 32 | match std::ffi::CString::new(s) { 33 | Ok(i) => Ok(i.into()), 34 | Err(_) => Err("fail"), 35 | } 36 | } 37 | } 38 | 39 | impl std::convert::From for Symbol { 40 | fn from(s: std::ffi::CString) -> Self { 41 | unsafe { Self(pd_sys::gensym(s.as_ptr())) } 42 | } 43 | } 44 | 45 | impl<'a> std::convert::Into<&'a std::ffi::CStr> for &Symbol { 46 | fn into(self) -> &'a std::ffi::CStr { 47 | unsafe { std::ffi::CStr::from_ptr((*self.0).s_name) } 48 | } 49 | } 50 | 51 | //https://stackoverflow.com/questions/46342644/how-can-i-get-a-path-from-a-raw-c-string-cstr-or-const-u8 52 | #[cfg(unix)] 53 | impl<'a> std::convert::Into<&'a std::path::Path> for &Symbol { 54 | fn into(self) -> &'a std::path::Path { 55 | let slice: &std::ffi::CStr = self.into(); 56 | let osstr = OsStr::from_bytes(slice.to_bytes()); 57 | osstr.as_ref() 58 | } 59 | } 60 | 61 | #[cfg(windows)] 62 | impl<'a> std::convert::Into<&'a std::path::Path> for &Symbol { 63 | fn into(self) -> &'a std::path::Path { 64 | let slice: &std::ffi::CStr = self.into(); 65 | let str = ::std::str::from_utf8(slice.to_bytes()) 66 | .expect("failed to get utf8 from puredata::symbol"); 67 | let path: &Path = str.as_ref(); 68 | } 69 | } 70 | 71 | impl std::convert::AsRef for Symbol { 72 | fn as_ref(&self) -> &std::ffi::CStr { 73 | self.into() 74 | } 75 | } 76 | 77 | impl Into for Symbol { 78 | fn into(self) -> String { 79 | unsafe { std::ffi::CStr::from_ptr((*self.0).s_name) } 80 | .to_str() 81 | .unwrap() 82 | .to_owned() 83 | } 84 | } 85 | 86 | impl std::convert::AsRef for Symbol { 87 | fn as_ref(&self) -> &std::path::Path { 88 | self.into() 89 | } 90 | } 91 | 92 | impl fmt::Display for Symbol { 93 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 94 | unsafe { 95 | let c = std::ffi::CStr::from_ptr((*self.0).s_name); 96 | if let Ok(c) = c.to_str() { 97 | write!(f, "{}", c) 98 | } else { 99 | Err(std::fmt::Error {}) 100 | } 101 | } 102 | } 103 | } 104 | 105 | impl Hash for Symbol { 106 | fn hash(&self, state: &mut H) 107 | where 108 | H: Hasher, 109 | { 110 | std::ptr::hash(self.0, state); 111 | state.finish(); 112 | } 113 | } 114 | 115 | impl std::cmp::PartialEq for Symbol { 116 | fn eq(&self, other: &Self) -> bool { 117 | let s = self.0 as *const _; 118 | let o = other.0 as *const _; 119 | s == o 120 | } 121 | } 122 | 123 | impl std::cmp::Eq for Symbol {} 124 | 125 | impl Copy for Symbol {} 126 | impl Clone for Symbol { 127 | fn clone(&self) -> Self { 128 | Self(self.0) 129 | } 130 | } 131 | 132 | //pd sends symbols between threads, must be thread safe 133 | unsafe impl Send for Symbol {} 134 | unsafe impl Sync for Symbol {} 135 | -------------------------------------------------------------------------------- /macros/README.md: -------------------------------------------------------------------------------- 1 | # pd-ext-macros 2 | 3 | At this point there is one macro `external!` that can wrap a `struct` and its `impl` blocks. 4 | If the `struct` implements one of the external `trait`s from `pd-ext`, you should 5 | have automatically generated trampolines and setup for your pure data external. 6 | 7 | Look at the [external traits](../external/src/external.rs) for details on what 8 | kind of externals you can generate. 9 | 10 | Currently, the puredata class is named after a lower case version the wrapped 11 | `struct`'s name, so the example below will generate a class called *counter*. 12 | 13 | BTW, the wrapper that the `external!` macro uses removes any need to manage 14 | signal setup; the `dsp` and `perform` methods are managed for you, you just need 15 | to implement the `generate` or `process` method from the appropriate `trait` 16 | to be able to use signals. See [wrapper](../external/src/wrapper.rs) if you 17 | want to see how that is done. 18 | 19 | ```rust 20 | external! { 21 | pub struct Counter { 22 | ... 23 | } 24 | 25 | impl ControlExternal for Counter { 26 | fn new(builder: &mut dyn ControlExternalBuilder) -> Self { 27 | ... 28 | } 29 | } 30 | } 31 | ``` 32 | 33 | 34 | ## Atrributes 35 | 36 | At this point there a few attributes you can add to an `impl` block to register methods 37 | in the puredata space. 38 | 39 | ### #[bang] 40 | 41 | ```rust 42 | external! { 43 | pub struct Counter { 44 | } 45 | ... 46 | 47 | impl Counter { 48 | #[bang] 49 | pub fn bang(&mut self) { 50 | } 51 | ... 52 | } 53 | } 54 | ``` 55 | 56 | This will generate a `bang` method in the pure data space for your external. 57 | If your external gets a `bang` on its left (aka hot) inlet, this method will 58 | be called. 59 | 60 | ### #[sel] 61 | 62 | A selector method, automatically generates the signature based on the method 63 | signature. 64 | 65 | There are 2 optional parameters: 66 | 67 | 1. `name="value"` 68 | This will ignore the name of the `rust` method and use the selector `value` to 69 | trigger this method. 70 | 71 | 2. `defaults=number` 72 | This will identify that `number` of the arguments, starting from the back 73 | should be filled in with default values if the argument isn't provided. 74 | 75 | The example below shows 3 bound selector methods: 76 | 77 | 1. `|reset(` takes no arguments 78 | 2. `|set v(` takes 0 or 1 float argument, if no arguments are provided, `v` will be `0.0` 79 | 3. `|bar v(` takes 1 argument, a symbol. 80 | 81 | 82 | ```rust 83 | external! { 84 | pub struct Counter { 85 | } 86 | ... 87 | 88 | impl Counter { 89 | #[sel] 90 | pub fn reset(&mut self) { 91 | } 92 | 93 | #[sel(defaults=1, name="set")] 94 | pub fn foo(&mut self, v: puredata_sys::t_float) { 95 | } 96 | 97 | #[sel] 98 | pub fn bar(&mut self, s: pd_ext::symbol::Symbol) { 99 | } 100 | ... 101 | } 102 | } 103 | ``` 104 | 105 | ### #[list] 106 | 107 | A list method, a var-args list of atoms. 108 | 109 | ```rust 110 | external! { 111 | pub struct HelloAll { 112 | ... 113 | 114 | impl HelloAll { 115 | ... 116 | 117 | #[list] //indicates that a list in Pd should call this 118 | pub fn list(&mut self, list: &[pd_ext::atom::Atom]) { 119 | } 120 | 121 | } 122 | } 123 | ``` 124 | 125 | ### #[anything] 126 | 127 | A message method, a selector symbol and a var-args list of atoms. 128 | 129 | ```rust 130 | external! { 131 | pub struct HelloAll { 132 | ... 133 | 134 | impl HelloAll { 135 | ... 136 | 137 | #[anything] 138 | pub fn foo(&mut self, sel: pd_ext::symbol::Symbol, list: &[pd_ext::atom::Atom]) { 139 | } 140 | 141 | } 142 | } 143 | ``` 144 | 145 | ## TODO 146 | 147 | * Libraries of externals 148 | * Allow explicit external naming 149 | * Bind other types of methods 150 | * More error checking during code generation 151 | 152 | -------------------------------------------------------------------------------- /external/src/outlet.rs: -------------------------------------------------------------------------------- 1 | use crate::obj::AsObject; 2 | use crate::symbol::Symbol; 3 | 4 | pub trait OutletSend { 5 | fn send_bang(&self); 6 | fn send_float(&self, v: pd_sys::t_float); 7 | fn send_symbol(&self, v: Symbol); 8 | fn send_list(&self, v: &[crate::atom::Atom]); 9 | fn send_anything(&self, sel: Symbol, v: &[crate::atom::Atom]); 10 | } 11 | 12 | //marker traits 13 | pub trait OutletSignal {} 14 | 15 | #[derive(Copy, Clone)] 16 | pub enum OutletType { 17 | Bang, 18 | Float, 19 | Symbol, 20 | Pointer, 21 | List, 22 | AnyThing, 23 | } 24 | 25 | pub struct Outlet { 26 | //outlet_type: OutletType, 27 | ptr: *mut pd_sys::_outlet, 28 | } 29 | 30 | pub struct SignalOutlet { 31 | ptr: *mut pd_sys::_outlet, 32 | } 33 | 34 | impl Outlet { 35 | pub fn new(outlet_type: OutletType, owner: &mut dyn AsObject) -> Self { 36 | unsafe { 37 | let ptr = match outlet_type { 38 | OutletType::Bang => pd_sys::outlet_new(owner.as_obj(), &mut pd_sys::s_bang), 39 | OutletType::Float => pd_sys::outlet_new(owner.as_obj(), &mut pd_sys::s_float), 40 | OutletType::Symbol => pd_sys::outlet_new(owner.as_obj(), &mut pd_sys::s_symbol), 41 | OutletType::Pointer => pd_sys::outlet_new(owner.as_obj(), &mut pd_sys::s_pointer), 42 | OutletType::List => pd_sys::outlet_new(owner.as_obj(), &mut pd_sys::s_list), 43 | OutletType::AnyThing => pd_sys::outlet_new( 44 | owner.as_obj(), 45 | std::ptr::null_mut() as *mut pd_sys::t_symbol, 46 | ), 47 | }; 48 | Self { 49 | /*outlet_type,*/ ptr, 50 | } 51 | } 52 | } 53 | } 54 | 55 | impl OutletSend for Outlet { 56 | fn send_bang(&self) { 57 | unsafe { 58 | pd_sys::outlet_bang(self.ptr); 59 | } 60 | } 61 | 62 | fn send_float(&self, v: pd_sys::t_float) { 63 | unsafe { 64 | pd_sys::outlet_float(self.ptr, v); 65 | } 66 | } 67 | 68 | fn send_symbol(&self, v: Symbol) { 69 | unsafe { 70 | pd_sys::outlet_symbol(self.ptr, v.inner()); 71 | } 72 | } 73 | 74 | fn send_list(&self, v: &[crate::atom::Atom]) { 75 | unsafe { 76 | let argc = v.len() as std::os::raw::c_int; 77 | let argv = v.as_ptr() as *const pd_sys::t_atom; 78 | //XXX pd doesn't indicate const or mut but shouldn't be modifying 79 | let argv = std::mem::transmute::<_, *mut pd_sys::t_atom>(argv); 80 | pd_sys::outlet_list(self.ptr, &mut pd_sys::s_list, argc, argv); 81 | } 82 | } 83 | 84 | fn send_anything(&self, sel: Symbol, v: &[crate::atom::Atom]) { 85 | unsafe { 86 | let argc = v.len() as std::os::raw::c_int; 87 | let argv = v.as_ptr() as *const pd_sys::t_atom; 88 | //XXX pd doesn't indicate const or mut but shouldn't be modifying 89 | let argv = std::mem::transmute::<_, *mut pd_sys::t_atom>(argv); 90 | pd_sys::outlet_anything(self.ptr, sel.inner(), argc, argv); 91 | } 92 | } 93 | } 94 | 95 | impl Drop for Outlet { 96 | fn drop(&mut self) { 97 | unsafe { 98 | pd_sys::outlet_free(self.ptr); 99 | } 100 | } 101 | } 102 | 103 | impl SignalOutlet { 104 | pub fn new(owner: &mut dyn AsObject) -> Self { 105 | let obj = owner.as_obj(); 106 | unsafe { 107 | Self { 108 | ptr: pd_sys::outlet_new(obj, &mut pd_sys::s_signal), 109 | } 110 | } 111 | } 112 | } 113 | 114 | impl OutletSignal for SignalOutlet {} 115 | 116 | impl Drop for SignalOutlet { 117 | fn drop(&mut self) { 118 | unsafe { 119 | pd_sys::outlet_free(self.ptr); 120 | } 121 | } 122 | } 123 | 124 | #[cfg(test)] 125 | mod tests { 126 | use super::*; 127 | impl OutletSend for () { 128 | fn send_bang(&self) {} 129 | fn send_float(&self, _v: pd_sys::t_float) {} 130 | fn send_symbol(&self, _v: Symbol) {} 131 | fn send_list(&self, _v: &[crate::atom::Atom]) {} 132 | fn send_anything(&self, _sel: Symbol, _v: &[crate::atom::Atom]) {} 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /external/src/atom.rs: -------------------------------------------------------------------------------- 1 | use crate::symbol::Symbol; 2 | use std::convert::TryInto; 3 | 4 | #[repr(transparent)] 5 | pub struct Atom(pub pd_sys::t_atom); 6 | 7 | impl Atom { 8 | pub fn slice_from_raw_parts( 9 | argv: *const pd_sys::t_atom, 10 | argc: std::os::raw::c_int, 11 | ) -> &'static [Atom] { 12 | unsafe { 13 | let (argv, argc) = if argv.is_null() { 14 | (std::ptr::null(), 0) 15 | } else { 16 | ( 17 | std::mem::transmute::<_, *const crate::atom::Atom>(argv), 18 | if argc < 0 as std::os::raw::c_int { 19 | 0usize 20 | } else { 21 | argc as usize 22 | }, 23 | ) 24 | }; 25 | std::slice::from_raw_parts(argv, argc) 26 | } 27 | } 28 | 29 | pub fn get_type(&self) -> pd_sys::t_atomtype::Type { 30 | self.0.a_type 31 | } 32 | 33 | pub fn is_type(&self, t: pd_sys::t_atomtype::Type) -> bool { 34 | self.get_type() == t 35 | } 36 | 37 | pub fn as_ptr(&self) -> *const pd_sys::t_atom { 38 | &self.0 as *const pd_sys::t_atom 39 | } 40 | pub fn get_symbol(&self) -> Option { 41 | assert!(!self.as_ptr().is_null()); 42 | unsafe { 43 | match self.0.a_type { 44 | pd_sys::t_atomtype::A_DEFSYM | pd_sys::t_atomtype::A_SYMBOL => { 45 | pd_sys::atom_getsymbol(self.as_ptr()).try_into().ok() 46 | } 47 | _ => None, 48 | } 49 | } 50 | } 51 | pub fn get_float(&self) -> Option { 52 | assert!(!self.as_ptr().is_null()); 53 | unsafe { 54 | match self.0.a_type { 55 | pd_sys::t_atomtype::A_DEFFLOAT | pd_sys::t_atomtype::A_FLOAT => { 56 | Some(pd_sys::atom_getfloat(self.as_ptr())) 57 | } 58 | _ => None, 59 | } 60 | } 61 | } 62 | pub fn get_int(&self) -> Option { 63 | assert!(!self.as_ptr().is_null()); 64 | unsafe { 65 | match self.0.a_type { 66 | //pd does the cast 67 | pd_sys::t_atomtype::A_DEFFLOAT | pd_sys::t_atomtype::A_FLOAT => { 68 | Some(pd_sys::atom_getint(self.as_ptr())) 69 | } 70 | _ => None, 71 | } 72 | } 73 | } 74 | 75 | pub fn set_semi(&mut self) { 76 | self.0.a_type = pd_sys::t_atomtype::A_SEMI; 77 | self.0.a_w.w_index = 0; 78 | } 79 | 80 | pub fn set_comma(&mut self) { 81 | self.0.a_type = pd_sys::t_atomtype::A_COMMA; 82 | self.0.a_w.w_index = 0; 83 | } 84 | 85 | pub fn set_pointer(&mut self, v: &mut pd_sys::t_gpointer) { 86 | self.0.a_type = pd_sys::t_atomtype::A_POINTER; 87 | self.0.a_w.w_gpointer = v as *mut pd_sys::t_gpointer; 88 | } 89 | 90 | pub fn set_float(&mut self, v: pd_sys::t_float) { 91 | self.0.a_type = pd_sys::t_atomtype::A_FLOAT; 92 | self.0.a_w.w_float = v; 93 | } 94 | 95 | pub fn set_symbol(&mut self, v: Symbol) { 96 | self.0.a_type = pd_sys::t_atomtype::A_SYMBOL; 97 | self.0.a_w.w_symbol = v.inner(); 98 | } 99 | 100 | pub fn set_dollar(&mut self, v: std::os::raw::c_int) { 101 | self.0.a_type = pd_sys::t_atomtype::A_DOLLAR; 102 | self.0.a_w.w_index = v; 103 | } 104 | 105 | pub fn set_dollarsym(&mut self, v: Symbol) { 106 | self.0.a_type = pd_sys::t_atomtype::A_DOLLSYM; 107 | self.0.a_w.w_symbol = v.inner(); 108 | } 109 | } 110 | 111 | impl Copy for Atom {} 112 | impl Clone for Atom { 113 | fn clone(&self) -> Self { 114 | let a = pd_sys::_atom { 115 | a_type: self.0.a_type, 116 | a_w: self.0.a_w, 117 | }; 118 | Self(a) 119 | } 120 | } 121 | 122 | impl std::convert::From for Atom { 123 | fn from(v: usize) -> Self { 124 | let mut s = Self::default(); 125 | s.set_float(v as pd_sys::t_float); 126 | s 127 | } 128 | } 129 | 130 | impl std::convert::From for Atom { 131 | fn from(v: f64) -> Self { 132 | let mut s = Self::default(); 133 | s.set_float(v as pd_sys::t_float); 134 | s 135 | } 136 | } 137 | 138 | impl std::convert::From for Atom { 139 | fn from(v: f32) -> Self { 140 | let mut s = Self::default(); 141 | s.set_float(v as pd_sys::t_float); 142 | s 143 | } 144 | } 145 | 146 | impl std::convert::From for Atom { 147 | fn from(v: crate::symbol::Symbol) -> Self { 148 | let mut s = Self::default(); 149 | s.set_symbol(v); 150 | s 151 | } 152 | } 153 | 154 | impl std::convert::TryInto for Atom { 155 | type Error = String; 156 | fn try_into(self) -> Result { 157 | if let Some(s) = self.get_symbol() { 158 | Ok(s.into()) 159 | } else if let Some(f) = self.get_float() { 160 | Ok(f.to_string()) 161 | } else { 162 | Err(format!( 163 | "don't know how to convert {} to string", 164 | self.0.a_type 165 | )) 166 | } 167 | } 168 | } 169 | 170 | impl Default for Atom { 171 | fn default() -> Self { 172 | let a = pd_sys::_atom { 173 | a_type: pd_sys::t_atomtype::A_FLOAT, 174 | a_w: { 175 | pd_sys::word { 176 | w_float: 0f32.into(), 177 | } 178 | }, 179 | }; 180 | Self(a) 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /external/src/builder.rs: -------------------------------------------------------------------------------- 1 | use crate::atom::Atom; 2 | use crate::inlet::passive::FloatInlet; 3 | use crate::inlet::*; 4 | use crate::obj::AsObject; 5 | use crate::outlet::{Outlet, OutletSend, OutletSignal, OutletType, SignalOutlet}; 6 | use crate::post::{PdPost, Post}; 7 | use crate::symbol::Symbol; 8 | use std::ops::Deref; 9 | 10 | pub type BoxInletSignal = Box; 11 | pub type BoxOutletSignal = Box; 12 | pub type BoxFloatInlet = Box; 13 | 14 | pub type IntoBuiltControl = Vec>; 15 | pub type IntoBuiltGenerator = (Vec>, Vec); 16 | pub type IntoBuiltProcessor = ( 17 | Vec>, 18 | Vec, 19 | Vec, 20 | ); 21 | 22 | pub trait ControlExternalBuilder { 23 | fn obj(&mut self) -> &mut dyn AsObject; 24 | fn poster(&mut self) -> Box; 25 | fn instance_name(&self) -> &Option; 26 | fn creation_args(&self) -> &[Atom]; 27 | fn new_passive_float_inlet( 28 | &mut self, 29 | initial_value: pd_sys::t_float, 30 | ) -> Box + Send>; 31 | fn new_float_inlet(&mut self, func: Box); 32 | fn new_message_outlet(&mut self, t: OutletType) -> Box; 33 | } 34 | 35 | pub trait SignalGeneratorExternalBuilder: ControlExternalBuilder { 36 | fn new_signal_outlet(&mut self); 37 | } 38 | 39 | pub trait SignalProcessorExternalBuilder: SignalGeneratorExternalBuilder { 40 | fn new_signal_inlet(&mut self); 41 | } 42 | 43 | pub struct Builder<'a, T> { 44 | obj: &'a mut dyn AsObject, 45 | args: &'a [Atom], 46 | name: Option, 47 | signal_inlets: Vec, 48 | signal_outlets: Vec, 49 | float_inlets: Vec>, 50 | } 51 | 52 | impl<'a, T> Builder<'a, T> { 53 | pub fn new(obj: &'a mut dyn AsObject, args: &'a [Atom], name: Option) -> Self { 54 | Self { 55 | obj, 56 | name, 57 | args, 58 | signal_inlets: Vec::new(), 59 | signal_outlets: Vec::new(), 60 | float_inlets: Vec::new(), 61 | } 62 | } 63 | 64 | pub fn signal_inlets(&self) -> usize { 65 | self.signal_inlets.len() 66 | } 67 | 68 | pub fn signal_outlets(&self) -> usize { 69 | self.signal_outlets.len() 70 | } 71 | } 72 | 73 | impl<'a, T> Into> for Builder<'a, T> { 74 | fn into(self) -> IntoBuiltControl { 75 | (self.float_inlets) 76 | } 77 | } 78 | 79 | impl<'a, T> Into> for Builder<'a, T> { 80 | fn into(self) -> IntoBuiltGenerator { 81 | (self.float_inlets, self.signal_outlets) 82 | } 83 | } 84 | 85 | impl<'a, T> Into> for Builder<'a, T> { 86 | fn into(self) -> IntoBuiltProcessor { 87 | (self.float_inlets, self.signal_outlets, self.signal_inlets) 88 | } 89 | } 90 | 91 | impl<'a, T> ControlExternalBuilder for Builder<'a, T> { 92 | fn obj(&mut self) -> &mut dyn AsObject { 93 | self.obj 94 | } 95 | 96 | fn poster(&mut self) -> Box { 97 | Box::new(Post::new(self.obj())) 98 | } 99 | 100 | fn instance_name(&self) -> &Option { 101 | &self.name 102 | } 103 | 104 | fn creation_args(&self) -> &[Atom] { 105 | &self.args 106 | } 107 | 108 | fn new_passive_float_inlet( 109 | &mut self, 110 | initial_value: pd_sys::t_float, 111 | ) -> Box + Send> { 112 | Box::new(FloatInlet::new(self.obj, initial_value)) 113 | } 114 | 115 | fn new_float_inlet(&mut self, func: Box) { 116 | self.float_inlets.push(func); 117 | } 118 | 119 | fn new_message_outlet(&mut self, t: OutletType) -> Box { 120 | Box::new(Outlet::new(t, self.obj)) 121 | } 122 | } 123 | 124 | impl<'a, T> SignalGeneratorExternalBuilder for Builder<'a, T> { 125 | fn new_signal_outlet(&mut self) { 126 | self.signal_outlets 127 | .push(Box::new(SignalOutlet::new(self.obj))); 128 | } 129 | } 130 | 131 | impl<'a, T> SignalProcessorExternalBuilder for Builder<'a, T> { 132 | fn new_signal_inlet(&mut self) { 133 | self.signal_inlets 134 | .push(Box::new(SignalInlet::new(self.obj))); 135 | } 136 | } 137 | 138 | #[cfg(test)] 139 | mod tests { 140 | 141 | /* 142 | pub struct A; 143 | pub struct TestBuilder 144 | where 145 | T: Sized, 146 | { 147 | float_inlets: Vec>, 148 | } 149 | 150 | impl A { 151 | pub fn print_float(&mut self, f: pd_sys::t_float) { 152 | println!("{}", f); 153 | } 154 | } 155 | 156 | impl TestBuilder 157 | where 158 | T: Sized, 159 | { 160 | pub fn call_floats<'a>(&mut self, a: &'a mut T, f: pd_sys::t_float) { 161 | for cb in &self.float_inlets { 162 | (cb)(a, f); 163 | } 164 | } 165 | 166 | pub fn new() -> Self { 167 | Self { 168 | float_inlets: Vec::new(), 169 | } 170 | } 171 | } 172 | 173 | impl ExternalBuilder for TestBuilder { 174 | fn new_passive_float_inlet( 175 | &mut self, 176 | initial_value: pd_sys::t_float, 177 | ) -> Box> { 178 | Box::new(Box::new(initial_value)) 179 | } 180 | 181 | fn new_float_inlet(&mut self, func: Box) { 182 | self.float_inlets.push(func); 183 | } 184 | 185 | fn new_outlet(&mut self, t: OutletType) -> Box { 186 | Box::new(()) 187 | } 188 | } 189 | 190 | #[test] 191 | fn can_build() { 192 | let mut a = A; 193 | let mut builder = TestBuilder::new(); 194 | 195 | builder.new_float_inlet(Box::new(|a: &mut A, f: pd_sys::t_float| { 196 | a.print_float(f); 197 | })); 198 | builder.call_floats(&mut a, 4f32); 199 | } 200 | */ 201 | } 202 | -------------------------------------------------------------------------------- /external/src/class.rs: -------------------------------------------------------------------------------- 1 | use crate::method; 2 | use crate::method::{ClassNewMethod, Method, PdDspMethod, PdMethod}; 3 | use std::ffi::CString; 4 | use std::marker::PhantomData; 5 | use std::os::raw::c_int; 6 | 7 | pub struct Class { 8 | pd_class: *mut pd_sys::_class, 9 | phantom: PhantomData, 10 | } 11 | 12 | pub enum SignalClassType { 13 | NoInput(PdDspMethod), 14 | WithInput(PdDspMethod, usize), //method, byte offset of translation float field in struct T 15 | } 16 | 17 | impl Class { 18 | pub fn register_new( 19 | name: CString, 20 | creator: ClassNewMethod, 21 | destroyer: Option, 22 | ) -> Self { 23 | unsafe { 24 | let mut args = [0; 6]; 25 | let creator = std::mem::transmute::< 26 | _, 27 | unsafe extern "C" fn() -> *mut ::std::os::raw::c_void, 28 | >(match creator { 29 | ClassNewMethod::VarArgs(m) => { 30 | args[0] = pd_sys::t_atomtype::A_GIMME; 31 | m 32 | } 33 | _ => unimplemented!(), 34 | }); 35 | let destroyer = match destroyer { 36 | None => None, 37 | Some(d) => Some(std::mem::transmute::< 38 | unsafe extern "C" fn(*mut T), 39 | unsafe extern "C" fn(), 40 | >(d)), 41 | }; 42 | let flags = pd_sys::CLASS_DEFAULT; 43 | let name: &mut pd_sys::t_symbol = name.into(); 44 | Self { 45 | pd_class: pd_sys::class_new( 46 | name.as_ptr(), 47 | Some(creator), 48 | destroyer, 49 | std::mem::size_of::(), 50 | flags as i32, 51 | args[0], 52 | args[1], 53 | args[2], 54 | args[3], 55 | args[4], 56 | args[5], 57 | 0, 58 | ), 59 | phantom: PhantomData, 60 | } 61 | } 62 | } 63 | 64 | fn register_dsp(&mut self, dsp_method: PdDspMethod) { 65 | let dsp = CString::new("dsp").expect("failed to allocate 'dsp' cstring"); 66 | unsafe { 67 | pd_sys::class_addmethod( 68 | self.pd_class, 69 | Some(std::mem::transmute::, PdMethod>( 70 | dsp_method, 71 | )), 72 | pd_sys::gensym(dsp.as_ptr()), 73 | pd_sys::t_atomtype::A_CANT, 74 | 0, 75 | ); 76 | } 77 | } 78 | 79 | pub fn register_dsp_new( 80 | name: CString, 81 | creator: ClassNewMethod, 82 | dsp_method: SignalClassType, 83 | destroyer: Option, 84 | ) -> Self { 85 | let mut s = Self::register_new(name, creator, destroyer); 86 | match dsp_method { 87 | SignalClassType::NoInput(m) => { 88 | s.register_dsp(m); 89 | } 90 | SignalClassType::WithInput(m, onset) => { 91 | s.register_dsp(m); 92 | unsafe { 93 | pd_sys::class_domainsignalin(s.pd_class, onset as c_int); 94 | } 95 | } 96 | } 97 | s 98 | } 99 | 100 | fn add_sel_method( 101 | &self, 102 | sel: CString, 103 | m: pd_sys::t_method, 104 | types: &mut [pd_sys::t_atomtype::Type], 105 | defaults: usize, 106 | ) { 107 | //fill in defaults 108 | let l = types.len(); 109 | assert!(l >= defaults); 110 | for i in l - defaults..l { 111 | match types[i] { 112 | pd_sys::t_atomtype::A_FLOAT | pd_sys::t_atomtype::A_DEFFLOAT => { 113 | types[i] = pd_sys::t_atomtype::A_DEFFLOAT 114 | } 115 | pd_sys::t_atomtype::A_SYMBOL | pd_sys::t_atomtype::A_DEFSYM => { 116 | types[i] = pd_sys::t_atomtype::A_DEFSYM 117 | } 118 | _ => panic!("type cannot be made default"), 119 | } 120 | } 121 | 122 | //register 123 | unsafe { 124 | let sym = pd_sys::gensym(sel.as_ptr()); 125 | match types.len() { 126 | 0 => { 127 | pd_sys::class_addmethod(self.pd_class, m, sym, 0); 128 | } 129 | 1 => { 130 | assert!(defaults <= 1); 131 | pd_sys::class_addmethod(self.pd_class, m, sym, types[0], 0); 132 | } 133 | 2 => { 134 | assert!(defaults <= 2); 135 | pd_sys::class_addmethod(self.pd_class, m, sym, types[0], types[1], 0); 136 | } 137 | 3 => { 138 | assert!(defaults <= 3); 139 | pd_sys::class_addmethod(self.pd_class, m, sym, types[0], types[1], types[2], 0); 140 | } 141 | 4 => { 142 | assert!(defaults <= 4); 143 | pd_sys::class_addmethod( 144 | self.pd_class, 145 | m, 146 | sym, 147 | types[0], 148 | types[1], 149 | types[2], 150 | types[3], 151 | 0, 152 | ); 153 | } 154 | 5 => { 155 | assert!(defaults <= 5); 156 | pd_sys::class_addmethod( 157 | self.pd_class, 158 | m, 159 | sym, 160 | types[0], 161 | types[1], 162 | types[2], 163 | types[3], 164 | types[4], 165 | 0, 166 | ); 167 | } 168 | 6 => { 169 | assert!(defaults <= 6); 170 | pd_sys::class_addmethod( 171 | self.pd_class, 172 | m, 173 | sym, 174 | types[0], 175 | types[1], 176 | types[2], 177 | types[3], 178 | types[4], 179 | types[5], 180 | 0, 181 | ); 182 | } 183 | _ => unimplemented!(), 184 | } 185 | } 186 | } 187 | 188 | pub fn new_instance(&mut self) -> *mut ::std::os::raw::c_void { 189 | unsafe { 190 | let obj = 191 | std::mem::transmute::<*mut pd_sys::t_pd, *mut Self>(pd_sys::pd_new(self.pd_class)); 192 | //XXX run init? 193 | obj as *mut ::std::os::raw::c_void 194 | } 195 | } 196 | } 197 | 198 | include!(concat!(env!("OUT_DIR"), "/class-gen.rs")); 199 | 200 | impl Into<*mut pd_sys::_class> for Class { 201 | fn into(self) -> *mut pd_sys::_class { 202 | self.pd_class 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /macros/examples/xfade/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "autocfg" 5 | version = "0.1.5" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "either" 10 | version = "1.5.2" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | 13 | [[package]] 14 | name = "field-offset" 15 | version = "0.1.1" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | 18 | [[package]] 19 | name = "itertools" 20 | version = "0.8.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | dependencies = [ 23 | "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 24 | ] 25 | 26 | [[package]] 27 | name = "num" 28 | version = "0.2.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | dependencies = [ 31 | "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 32 | "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 33 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 36 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 37 | ] 38 | 39 | [[package]] 40 | name = "num-bigint" 41 | version = "0.2.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | dependencies = [ 44 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 46 | ] 47 | 48 | [[package]] 49 | name = "num-complex" 50 | version = "0.2.3" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | dependencies = [ 53 | "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 54 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 55 | ] 56 | 57 | [[package]] 58 | name = "num-integer" 59 | version = "0.1.41" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | dependencies = [ 62 | "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 63 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 64 | ] 65 | 66 | [[package]] 67 | name = "num-iter" 68 | version = "0.1.39" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | dependencies = [ 71 | "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 72 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 73 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 74 | ] 75 | 76 | [[package]] 77 | name = "num-rational" 78 | version = "0.2.2" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | dependencies = [ 81 | "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 82 | "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 83 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 84 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 85 | ] 86 | 87 | [[package]] 88 | name = "num-traits" 89 | version = "0.2.8" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | dependencies = [ 92 | "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 93 | ] 94 | 95 | [[package]] 96 | name = "pd-ext" 97 | version = "0.1.0" 98 | dependencies = [ 99 | "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 100 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 101 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 102 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 103 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 104 | ] 105 | 106 | [[package]] 107 | name = "pd-ext-macros" 108 | version = "0.1.1" 109 | dependencies = [ 110 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 111 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 112 | "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", 113 | ] 114 | 115 | [[package]] 116 | name = "pd-sys" 117 | version = "0.1.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | 120 | [[package]] 121 | name = "proc-macro2" 122 | version = "0.4.30" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | dependencies = [ 125 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 126 | ] 127 | 128 | [[package]] 129 | name = "quote" 130 | version = "0.6.13" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | dependencies = [ 133 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 134 | ] 135 | 136 | [[package]] 137 | name = "syn" 138 | version = "0.15.43" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | dependencies = [ 141 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 142 | "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 143 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 144 | ] 145 | 146 | [[package]] 147 | name = "unicode-xid" 148 | version = "0.1.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | 151 | [[package]] 152 | name = "xfade" 153 | version = "0.1.0" 154 | dependencies = [ 155 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 156 | "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 157 | "pd-ext 0.1.0", 158 | "pd-ext-macros 0.1.1", 159 | "pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 160 | ] 161 | 162 | [metadata] 163 | "checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" 164 | "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" 165 | "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" 166 | "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" 167 | "checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" 168 | "checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718" 169 | "checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" 170 | "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" 171 | "checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" 172 | "checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" 173 | "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" 174 | "checksum pd-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d277c9097b9df013dd6c0712ec0f55fbcd0cf78c6e5c2e509c022d0c353fedc" 175 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 176 | "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 177 | "checksum syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ee06ea4b620ab59a2267c6b48be16244a3389f8bfa0986bdd15c35b890b00af3" 178 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 179 | -------------------------------------------------------------------------------- /external/build.rs: -------------------------------------------------------------------------------- 1 | // build.rs 2 | 3 | use quote::quote; 4 | use std::env; 5 | use std::fs::File; 6 | use std::io::Write; 7 | use std::path::Path; 8 | 9 | #[derive(Clone, Copy, Debug)] 10 | enum Arg { 11 | Float, 12 | Symbol, 13 | } 14 | 15 | impl Arg { 16 | pub fn to_string(&self) -> String { 17 | match self { 18 | Arg::Float => "F", 19 | Arg::Symbol => "S", 20 | } 21 | .to_string() 22 | } 23 | 24 | pub fn to_sig(&self) -> proc_macro2::TokenStream { 25 | match self { 26 | Arg::Float => quote! { pd_sys::t_floatarg }, 27 | Arg::Symbol => quote! { *mut pd_sys::t_symbol }, 28 | } 29 | } 30 | 31 | pub fn to_arg(&self) -> proc_macro2::TokenStream { 32 | match self { 33 | Arg::Float => quote! { pd_sys::t_atomtype::A_FLOAT }, 34 | Arg::Symbol => quote! { pd_sys::t_atomtype::A_SYMBOL }, 35 | } 36 | } 37 | 38 | /* 39 | pub fn to_classnewarg(&self) -> proc_macro2::TokenStream { 40 | match self { 41 | Arg::Float => quote! { pd_sys::t_atomtype::A_DEFFLOAT }, 42 | Arg::Symbol => quote! { pd_sys::t_atomtype::A_DEFSYMBOL }, 43 | } 44 | } 45 | */ 46 | } 47 | 48 | fn append_perms(types: &Vec, perms: &mut Vec>, recurse: usize) { 49 | if recurse == 0 { 50 | return; 51 | } 52 | let mut append = Vec::new(); 53 | for t in types { 54 | for p in perms.iter() { 55 | let mut n = p.clone(); 56 | n.push(*t); 57 | append.push(n); 58 | } 59 | } 60 | append_perms(types, &mut append, recurse - 1); 61 | for a in append.into_iter() { 62 | perms.push(a); 63 | } 64 | } 65 | 66 | fn type_alias_name(perm: &Vec) -> String { 67 | perm.iter() 68 | .map(Arg::to_string) 69 | .collect::>() 70 | .join("") 71 | } 72 | 73 | fn classnew_variant_name(type_alias: &String) -> syn::Ident { 74 | syn::Ident::new(type_alias, proc_macro2::Span::call_site()) 75 | } 76 | 77 | fn sel_variant_name(type_alias: &String) -> syn::Ident { 78 | syn::Ident::new( 79 | &format!("Sel{}", type_alias), 80 | proc_macro2::Span::call_site(), 81 | ) 82 | } 83 | 84 | fn gen_method(perms: &Vec>) -> Result<(), Box> { 85 | let out_dir = env::var("OUT_DIR")?; 86 | let dest_path = Path::new(&out_dir).join("method-gen.rs"); 87 | let mut f = File::create(&dest_path)?; 88 | 89 | //build types 90 | let mut variants = Vec::new(); 91 | for p in perms.iter() { 92 | //build type alias 93 | let alias = type_alias_name(&p); 94 | let t = syn::Ident::new(&alias, proc_macro2::Span::call_site()); 95 | let v = sel_variant_name(&alias); 96 | 97 | //build method signature 98 | let args = p.iter().map(Arg::to_sig); 99 | f.write_all( 100 | quote! { 101 | pub type #t = unsafe extern "C" fn(*mut T, #(#args),*); 102 | } 103 | .to_string() 104 | .as_bytes(), 105 | )?; 106 | f.write_all(b"\n")?; 107 | 108 | //build up variant 109 | //TODO when we allow pointers, don't provide defaults if a pointer is at the end? 110 | variants.push(quote! { 111 | #v(std::ffi::CString, #t, usize) 112 | }); 113 | } 114 | 115 | //build enumeration 116 | f.write_all( 117 | quote! { 118 | pub enum Method { 119 | Bang(B), 120 | Float(F), 121 | Symbol(S), 122 | List(SelList), 123 | AnyThing(SelList), 124 | Sel(CString, B), 125 | SelVarArg(CString, SelList), 126 | #(#variants),* 127 | } 128 | } 129 | .to_string() 130 | .as_bytes(), 131 | )?; 132 | 133 | //class new enumeration 134 | let cvoidptr = quote! { *mut ::std::os::raw::c_void }; 135 | let mut variants = vec![ 136 | quote! { NoArgs(unsafe extern "C" fn() -> #cvoidptr) }, 137 | quote! { VarArgs(unsafe extern "C" fn(*mut pd_sys::t_symbol, std::os::raw::c_int, *const pd_sys::t_atom) -> #cvoidptr) }, 138 | ]; 139 | //XXX TODO, filter out pointers when we get them 140 | for p in perms.iter() { 141 | //build type alias 142 | let alias = type_alias_name(&p); 143 | let v = classnew_variant_name(&alias); 144 | let args = p.iter().map(Arg::to_sig); 145 | variants.push(quote! { #v(unsafe extern "C" fn(#(#args),*) -> #cvoidptr) }); 146 | } 147 | 148 | f.write_all( 149 | quote! { 150 | pub enum ClassNewMethod { 151 | #(#variants),* 152 | } 153 | } 154 | .to_string() 155 | .as_bytes(), 156 | )?; 157 | 158 | Ok(()) 159 | } 160 | 161 | fn gen_class(perms: &Vec>) -> Result<(), Box> { 162 | let out_dir = env::var("OUT_DIR")?; 163 | let dest_path = Path::new(&out_dir).join("class-gen.rs"); 164 | let mut f = File::create(&dest_path)?; 165 | 166 | //implementation that adds methods to class 167 | let mut matches = vec![ 168 | quote! { 169 | Method::Bang(f) => { 170 | pd_sys::class_addbang( 171 | self.pd_class, 172 | Some(std::mem::transmute::, PdMethod>(f)), 173 | ); 174 | } 175 | }, 176 | quote! { 177 | Method::Float(f) => { 178 | pd_sys::class_doaddfloat( 179 | self.pd_class, 180 | Some(std::mem::transmute::, PdMethod>(f)), 181 | ); 182 | } 183 | }, 184 | quote! { 185 | Method::Symbol(f) => { 186 | pd_sys::class_addsymbol( 187 | self.pd_class, 188 | Some(std::mem::transmute::, PdMethod>(f)), 189 | ); 190 | } 191 | }, 192 | quote! { 193 | Method::List(f) => { 194 | pd_sys::class_addlist( 195 | self.pd_class, 196 | Some(std::mem::transmute::, PdMethod>(f)), 197 | ); 198 | } 199 | }, 200 | quote! { 201 | Method::AnyThing(f) => { 202 | pd_sys::class_addanything( 203 | self.pd_class, 204 | Some(std::mem::transmute::, PdMethod>(f)), 205 | ); 206 | } 207 | }, 208 | quote! { 209 | Method::Sel(sel, f) => { 210 | self.add_sel_method( 211 | sel, 212 | Some(std::mem::transmute::, PdMethod>(f)), 213 | &mut [], 214 | 0, 215 | ); 216 | } 217 | }, 218 | quote! { 219 | Method::SelVarArg(sel, f) => { 220 | self.add_sel_method( 221 | sel, 222 | Some(std::mem::transmute::, PdMethod>(f)), 223 | &mut [pd_sys::t_atomtype::A_GIMME], 224 | 0, 225 | ); 226 | } 227 | }, 228 | ]; 229 | for p in perms.iter() { 230 | let alias = type_alias_name(&p); 231 | let t = syn::Ident::new(&alias, proc_macro2::Span::call_site()); 232 | let v = sel_variant_name(&alias); 233 | let args = p.iter().map(Arg::to_arg); 234 | matches.push(quote! { 235 | Method::#v(sel, f, defaults) => { 236 | self.add_sel_method( 237 | sel, 238 | Some(std::mem::transmute::, PdMethod>(f)), 239 | &mut [#(#args),*], 240 | defaults, 241 | ); 242 | } 243 | }); 244 | } 245 | 246 | f.write_all( 247 | quote! { 248 | impl Class { 249 | pub fn add_method(&mut self, m: Method) { 250 | unsafe { 251 | match m { 252 | #(#matches)* 253 | } 254 | } 255 | } 256 | } 257 | } 258 | .to_string() 259 | .as_bytes(), 260 | )?; 261 | Ok(()) 262 | } 263 | 264 | fn main() -> Result<(), Box> { 265 | let mut perms = vec![vec![Arg::Float], vec![Arg::Symbol]]; 266 | let types = vec![Arg::Float, Arg::Symbol]; 267 | append_perms(&types, &mut perms, 5); 268 | 269 | gen_method(&perms)?; 270 | gen_class(&perms)?; 271 | 272 | Ok(()) 273 | } 274 | -------------------------------------------------------------------------------- /external/src/wrapper.rs: -------------------------------------------------------------------------------- 1 | use crate::builder::*; 2 | use crate::external::*; 3 | use crate::method::PdDspPerform; 4 | use crate::obj::AsObject; 5 | use crate::symbol::Symbol; 6 | use field_offset::offset_of; 7 | use std::convert::TryInto; 8 | use std::mem::MaybeUninit; 9 | use std::slice; 10 | 11 | #[repr(C)] 12 | pub struct ControlExternalWrapper 13 | where 14 | T: ControlExternal, 15 | { 16 | x_obj: pd_sys::t_object, 17 | wrapped: MaybeUninit>, 18 | } 19 | 20 | #[repr(C)] 21 | pub struct SignalGeneratorExternalWrapper 22 | where 23 | T: SignalGeneratorExternal, 24 | { 25 | x_obj: pd_sys::t_object, 26 | wrapped: MaybeUninit>, 27 | } 28 | 29 | #[repr(C)] 30 | pub struct SignalProcessorExternalWrapper 31 | where 32 | T: SignalProcessorExternal, 33 | { 34 | x_obj: pd_sys::t_object, 35 | convert: pd_sys::t_float, 36 | wrapped: MaybeUninit>, 37 | } 38 | 39 | struct ControlExternalWrapperInternal 40 | where 41 | T: ControlExternal, 42 | { 43 | wrapped: T, 44 | } 45 | 46 | struct SignalGeneratorExternalWrapperInternal 47 | where 48 | T: SignalGeneratorExternal, 49 | { 50 | wrapped: T, 51 | generator: Box, 52 | signal_outlets: Vec, 53 | outlet_buffer: Vec<&'static mut [pd_sys::t_float]>, 54 | } 55 | 56 | struct SignalProcessorExternalWrapperInternal 57 | where 58 | T: SignalProcessorExternal, 59 | { 60 | wrapped: T, 61 | processor: Box, 62 | _signal_outlets: Vec, 63 | _signal_inlets: Vec, 64 | outlet_buffer: Vec<&'static mut [pd_sys::t_float]>, 65 | inlet_buffer: Vec>, 66 | } 67 | 68 | impl ControlExternalWrapperInternal 69 | where 70 | T: ControlExternal, 71 | { 72 | pub fn new<'a>(wrapped: T, _builder: Builder) -> Self { 73 | Self { wrapped } 74 | } 75 | 76 | pub fn wrapped(&mut self) -> &mut T { 77 | &mut self.wrapped 78 | } 79 | } 80 | 81 | impl SignalGeneratorExternalWrapperInternal 82 | where 83 | T: SignalGeneratorExternal, 84 | { 85 | pub fn new(wrapped: T, generator: Box, builder: Builder) -> Self { 86 | let temp: IntoBuiltGenerator = builder.into(); 87 | let outlets = temp.1.len(); 88 | let mut outlet_buffer = Vec::new(); 89 | unsafe { 90 | for _ in 0..outlets { 91 | outlet_buffer.push(slice::from_raw_parts_mut(std::ptr::null_mut(), 0)); 92 | } 93 | } 94 | Self { 95 | wrapped, 96 | generator, 97 | signal_outlets: temp.1, 98 | outlet_buffer, 99 | } 100 | } 101 | 102 | pub fn wrapped(&mut self) -> &mut T { 103 | &mut self.wrapped 104 | } 105 | 106 | pub fn signal_iolets(&self) -> usize { 107 | self.signal_outlets.len() 108 | } 109 | 110 | pub fn setup_generate(&mut self, frames: usize) { 111 | self.generator 112 | .setup_generate(frames, self.signal_outlets.len()); 113 | } 114 | 115 | pub fn generate(&mut self, nframes: usize, buffer: *mut pd_sys::t_int) { 116 | //assign the slices 117 | unsafe { 118 | let outlets = self.outlet_buffer.len(); 119 | let buffer = slice::from_raw_parts(buffer, outlets); 120 | for i in 0..outlets { 121 | let output = std::mem::transmute::<_, *mut pd_sys::t_sample>(buffer[i]); 122 | let output = slice::from_raw_parts_mut(output, nframes); 123 | self.outlet_buffer[i] = output; 124 | } 125 | } 126 | let output_slice = self.outlet_buffer.as_mut(); 127 | self.generator.generate(nframes, output_slice); 128 | } 129 | } 130 | 131 | impl SignalProcessorExternalWrapperInternal 132 | where 133 | T: SignalProcessorExternal, 134 | { 135 | pub fn new(wrapped: T, processor: Box, builder: Builder) -> Self { 136 | let temp: IntoBuiltProcessor = builder.into(); 137 | let inlets = temp.2.len() + 1; //one default 138 | let outlets = temp.1.len(); 139 | let mut inlet_buffer = Vec::new(); 140 | let mut outlet_buffer = Vec::new(); 141 | 142 | //reserve space for slices, 0 len for now 143 | unsafe { 144 | for _ in 0..inlets { 145 | inlet_buffer.push(Default::default()); 146 | } 147 | for _ in 0..outlets { 148 | outlet_buffer.push(slice::from_raw_parts_mut(std::ptr::null_mut(), 0)); 149 | } 150 | } 151 | Self { 152 | wrapped, 153 | processor, 154 | _signal_outlets: temp.1, 155 | _signal_inlets: temp.2, 156 | inlet_buffer, 157 | outlet_buffer, 158 | } 159 | } 160 | 161 | pub fn wrapped(&mut self) -> &mut T { 162 | &mut self.wrapped 163 | } 164 | 165 | pub fn signal_iolets(&self) -> usize { 166 | self.inlet_buffer.len() + self.outlet_buffer.len() 167 | } 168 | 169 | pub fn allocate_inlet_buffers(&mut self, nframes: usize) { 170 | for b in self.inlet_buffer.iter_mut() { 171 | b.resize(nframes); 172 | } 173 | } 174 | 175 | fn setup_process(&mut self, frames: usize) { 176 | self.processor 177 | .setup_process(frames, self.inlet_buffer.len(), self.outlet_buffer.len()); 178 | } 179 | 180 | pub fn process(&mut self, nframes: usize, buffer: *mut pd_sys::t_int) { 181 | let inlets = self.inlet_buffer.len(); 182 | let outlets = self.outlet_buffer.len(); 183 | //assign the slices 184 | //inputs first 185 | unsafe { 186 | let buffer = slice::from_raw_parts(buffer, inlets + outlets); 187 | for i in 0..inlets { 188 | let input = std::mem::transmute::<_, *const pd_sys::t_sample>(buffer[i]); 189 | let input = slice::from_raw_parts(input, nframes); 190 | self.inlet_buffer[i].0.copy_from_slice(input); 191 | } 192 | 193 | let offset = inlets; 194 | for i in 0..outlets { 195 | let output = std::mem::transmute::<_, *mut pd_sys::t_sample>(buffer[i + offset]); 196 | let output = slice::from_raw_parts_mut(output, nframes); 197 | self.outlet_buffer[i] = output; 198 | } 199 | } 200 | let output_slice = self.outlet_buffer.as_mut_slice(); 201 | let input_slice = self.inlet_buffer.as_slice(); 202 | unsafe { 203 | //the Slice newtype is transparent so we can just treat it as if it were the inner type 204 | let input_slice = std::mem::transmute::<_, _>(input_slice); 205 | //XXX can we cast input_slice to not be mut internally? 206 | self.processor.process(nframes, input_slice, output_slice); 207 | } 208 | } 209 | } 210 | 211 | impl ControlExternalWrapper 212 | where 213 | T: ControlExternal, 214 | { 215 | pub unsafe fn new( 216 | pd_class: *mut pd_sys::_class, 217 | args: &[crate::atom::Atom], 218 | name: *mut pd_sys::t_symbol, 219 | ) -> *mut ::std::os::raw::c_void { 220 | let obj = std::mem::transmute::<*mut pd_sys::t_pd, &mut Self>(pd_sys::pd_new(pd_class)); 221 | obj.init(args, name.try_into().ok()) 222 | } 223 | 224 | fn init( 225 | &mut self, 226 | args: &[crate::atom::Atom], 227 | name: Option, 228 | ) -> *mut ::std::os::raw::c_void { 229 | let mut builder = Builder::new(self, args, name); 230 | let r = match ControlExternal::new(&mut builder) { 231 | Ok(e) => { 232 | let c = ControlExternalWrapperInternal::new(e, builder); 233 | self.wrapped = MaybeUninit::new(c); 234 | self as *mut Self 235 | } 236 | Err(reason) => null_with_reason(reason), 237 | }; 238 | r as *mut ::std::os::raw::c_void 239 | } 240 | 241 | pub fn free(&mut self) { 242 | let mut wrapped = MaybeUninit::uninit(); 243 | std::mem::swap(&mut self.wrapped, &mut wrapped); 244 | unsafe { 245 | std::mem::drop(wrapped.assume_init()); 246 | } 247 | } 248 | 249 | pub fn wrapped(&mut self) -> &mut T { 250 | unsafe { (&mut (*self.wrapped.as_mut_ptr())).wrapped() } 251 | } 252 | } 253 | 254 | impl SignalGeneratorExternalWrapper 255 | where 256 | T: SignalGeneratorExternal, 257 | { 258 | pub unsafe fn new( 259 | pd_class: *mut pd_sys::_class, 260 | args: &[crate::atom::Atom], 261 | name: *mut pd_sys::t_symbol, 262 | ) -> *mut ::std::os::raw::c_void { 263 | let obj = std::mem::transmute::<*mut pd_sys::t_pd, &mut Self>(pd_sys::pd_new(pd_class)); 264 | obj.init(args, name.try_into().ok()) 265 | } 266 | 267 | fn init( 268 | &mut self, 269 | args: &[crate::atom::Atom], 270 | name: Option, 271 | ) -> *mut ::std::os::raw::c_void { 272 | let mut builder = Builder::new(self, args, name); 273 | let r = match SignalGeneratorExternal::new(&mut builder) { 274 | Ok((e, g)) => { 275 | //make sure we have some output 276 | if builder.signal_outlets() == 0 { 277 | null_with_reason("generator must have at least 1 signal outlet".into()) 278 | } else { 279 | self.wrapped = MaybeUninit::new(SignalGeneratorExternalWrapperInternal::new( 280 | e, g, builder, 281 | )); 282 | self as *mut Self 283 | } 284 | } 285 | Err(reason) => null_with_reason(reason), 286 | }; 287 | r as *mut ::std::os::raw::c_void 288 | } 289 | 290 | pub fn free(&mut self) { 291 | let mut wrapped = MaybeUninit::uninit(); 292 | std::mem::swap(&mut self.wrapped, &mut wrapped); 293 | unsafe { 294 | std::mem::drop(wrapped.assume_init()); 295 | } 296 | } 297 | 298 | fn inner(&self) -> &SignalGeneratorExternalWrapperInternal { 299 | unsafe { (&(*self.wrapped.as_ptr())) } 300 | } 301 | 302 | fn inner_mut(&mut self) -> &mut SignalGeneratorExternalWrapperInternal { 303 | unsafe { (&mut (*self.wrapped.as_mut_ptr())) } 304 | } 305 | 306 | pub fn wrapped(&mut self) -> &mut T { 307 | self.inner_mut().wrapped() 308 | } 309 | 310 | pub fn signal_iolets(&self) -> usize { 311 | self.inner().signal_iolets() 312 | } 313 | 314 | pub fn dsp(&mut self, sv: *mut *mut pd_sys::t_signal, trampoline: PdDspPerform) { 315 | let iolets = self.signal_iolets(); 316 | let frames = setup_dsp(self, iolets, sv, trampoline); 317 | self.inner_mut().setup_generate(frames); 318 | } 319 | 320 | pub fn perform(&mut self, w: *mut pd_sys::t_int) -> *mut pd_sys::t_int { 321 | unsafe { 322 | let iolets = self.signal_iolets(); 323 | let nframes = *std::mem::transmute::<_, *const usize>(w.offset(2)); 324 | self.inner_mut().generate(nframes, w.offset(3)); 325 | w.offset((3 + iolets) as isize) 326 | } 327 | } 328 | } 329 | 330 | impl SignalProcessorExternalWrapper 331 | where 332 | T: SignalProcessorExternal, 333 | { 334 | pub unsafe fn new( 335 | pd_class: *mut pd_sys::_class, 336 | args: &[crate::atom::Atom], 337 | name: *mut pd_sys::t_symbol, 338 | ) -> *mut ::std::os::raw::c_void { 339 | let obj = std::mem::transmute::<*mut pd_sys::t_pd, &mut Self>(pd_sys::pd_new(pd_class)); 340 | obj.init(args, name.try_into().ok()) 341 | } 342 | 343 | fn init( 344 | &mut self, 345 | args: &[crate::atom::Atom], 346 | name: Option, 347 | ) -> *mut ::std::os::raw::c_void { 348 | let mut builder = Builder::new(self, args, name); 349 | let r = match SignalProcessorExternal::new(&mut builder) { 350 | Ok((e, p)) => { 351 | self.wrapped = 352 | MaybeUninit::new(SignalProcessorExternalWrapperInternal::new(e, p, builder)); 353 | self as *mut Self 354 | } 355 | Err(reason) => null_with_reason(reason), 356 | }; 357 | r as *mut ::std::os::raw::c_void 358 | } 359 | 360 | pub fn free(&mut self) { 361 | let mut wrapped = MaybeUninit::uninit(); 362 | std::mem::swap(&mut self.wrapped, &mut wrapped); 363 | unsafe { 364 | std::mem::drop(wrapped.assume_init()); 365 | } 366 | } 367 | 368 | fn inner(&self) -> &SignalProcessorExternalWrapperInternal { 369 | unsafe { (&(*self.wrapped.as_ptr())) } 370 | } 371 | 372 | fn inner_mut(&mut self) -> &mut SignalProcessorExternalWrapperInternal { 373 | unsafe { (&mut (*self.wrapped.as_mut_ptr())) } 374 | } 375 | 376 | pub fn wrapped(&mut self) -> &mut T { 377 | self.inner_mut().wrapped() 378 | } 379 | 380 | pub fn signal_iolets(&self) -> usize { 381 | self.inner().signal_iolets() 382 | } 383 | 384 | pub fn float_convert_field_offset() -> usize { 385 | offset_of!(Self => convert).get_byte_offset() 386 | } 387 | 388 | pub fn dsp(&mut self, sv: *mut *mut pd_sys::t_signal, trampoline: PdDspPerform) { 389 | let iolets = self.signal_iolets(); 390 | let frames = setup_dsp(self, iolets, sv, trampoline); 391 | 392 | //allocate buffers to copy input data so we don't trample it 393 | self.inner_mut().allocate_inlet_buffers(frames); 394 | self.inner_mut().setup_process(frames); 395 | } 396 | 397 | pub fn perform(&mut self, w: *mut pd_sys::t_int) -> *mut pd_sys::t_int { 398 | unsafe { 399 | let iolets = self.signal_iolets(); 400 | let nframes = *std::mem::transmute::<_, *const usize>(w.offset(2)); 401 | self.inner_mut().process(nframes, w.offset(3)); 402 | w.offset((3 + iolets) as isize) 403 | } 404 | } 405 | } 406 | 407 | fn setup_dsp( 408 | obj: &mut T, 409 | iolets: usize, 410 | sv: *mut *mut pd_sys::t_signal, 411 | trampoline: PdDspPerform, 412 | ) -> usize { 413 | unsafe { 414 | let sv = slice::from_raw_parts(sv, iolets); 415 | let len = (*sv[0]).s_n as usize; 416 | 417 | //ptr to self, nframes, inputs, outputs 418 | let vecsize = 2 + iolets; 419 | let vecnbytes = vecsize * std::mem::size_of::<*mut pd_sys::t_int>(); 420 | let vecp = pd_sys::getbytes(vecnbytes); 421 | let vec = std::mem::transmute::<_, *mut *mut pd_sys::t_int>(vecp); 422 | assert!(!vecp.is_null(), "null pointer from pd_sys::getbytes",); 423 | 424 | let vec: &mut [*mut pd_sys::t_int] = slice::from_raw_parts_mut(vec, vecsize); 425 | vec[1] = std::mem::transmute::<_, _>(len); 426 | for i in 0..iolets { 427 | vec[2 + i] = std::mem::transmute::<_, _>((*sv[i]).s_vec); 428 | } 429 | 430 | vec[0] = std::mem::transmute::<_, _>(obj); 431 | 432 | pd_sys::dsp_addv( 433 | Some(trampoline), 434 | vecsize as std::os::raw::c_int, 435 | std::mem::transmute::<_, *mut pd_sys::t_int>(vecp), 436 | ); 437 | pd_sys::freebytes(vecp, vecnbytes); 438 | len 439 | } 440 | } 441 | 442 | impl AsObject for ControlExternalWrapper 443 | where 444 | T: ControlExternal, 445 | { 446 | fn as_obj(&mut self) -> *mut pd_sys::t_object { 447 | &mut self.x_obj 448 | } 449 | } 450 | 451 | impl AsObject for SignalGeneratorExternalWrapper 452 | where 453 | T: SignalGeneratorExternal, 454 | { 455 | fn as_obj(&mut self) -> *mut pd_sys::t_object { 456 | &mut self.x_obj 457 | } 458 | } 459 | 460 | impl AsObject for SignalProcessorExternalWrapper 461 | where 462 | T: SignalProcessorExternal, 463 | { 464 | fn as_obj(&mut self) -> *mut pd_sys::t_object { 465 | &mut self.x_obj 466 | } 467 | } 468 | 469 | impl Drop for SignalProcessorExternalWrapperInternal 470 | where 471 | T: SignalProcessorExternal, 472 | { 473 | fn drop(&mut self) { 474 | //anything needed? 475 | } 476 | } 477 | 478 | // indicate error and then return null (object creation) 479 | fn null_with_reason(reason: String) -> *mut T { 480 | crate::post::Post::error(reason); 481 | std::ptr::null_mut::() 482 | } 483 | -------------------------------------------------------------------------------- /macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "128"] 2 | extern crate proc_macro; 3 | 4 | use proc_macro2::Span; 5 | use quote::quote; 6 | use syn::parse::{Parse, ParseStream}; 7 | use syn::spanned::Spanned; 8 | use syn::{ 9 | parenthesized, parse_macro_input, Attribute, FnArg, Ident, ImplItem, ImplItemMethod, Item, 10 | ItemImpl, ItemStruct, Lit, LitInt, LitStr, Pat, Token, Type, TypePath, 11 | }; 12 | 13 | #[derive(Copy, Clone, Debug)] 14 | enum ExternalType { 15 | Control, 16 | Signal, 17 | } 18 | 19 | struct Parsed { 20 | items: Vec, 21 | } 22 | 23 | #[derive(Debug)] 24 | struct SelArgs { 25 | pub name: Option, 26 | pub defaults: Option, 27 | } 28 | 29 | //an attribute to specify the name of the pd class 30 | #[derive(Debug)] 31 | struct ClassNameArgs { 32 | pub name: LitStr, 33 | } 34 | 35 | impl Parse for Parsed { 36 | fn parse(input: ParseStream) -> syn::parse::Result { 37 | let mut items = Vec::new(); 38 | while !input.is_empty() { 39 | items.push(input.parse()?); 40 | } 41 | 42 | Ok(Self { items }) 43 | } 44 | } 45 | 46 | impl Parse for SelArgs { 47 | fn parse(input: ParseStream) -> syn::parse::Result { 48 | if input.is_empty() { 49 | return Ok(Self { 50 | name: None, 51 | defaults: None, 52 | }); 53 | } 54 | 55 | let content; 56 | parenthesized!(content in input); 57 | 58 | let mut name = None; 59 | let mut defaults = None; 60 | while !content.is_empty() { 61 | let key: Ident = content.parse()?; 62 | let _: Token![=] = content.parse()?; 63 | let value: Lit = content.parse()?; 64 | match key.to_string().as_ref() { 65 | "name" => name = Some(value), 66 | "defaults" => defaults = Some(value), 67 | v => { 68 | return Err(syn::Error::new( 69 | key.span(), 70 | format!("unknown sel attribute key '{}'", v), 71 | )); 72 | } 73 | } 74 | let _: syn::Result = content.parse(); 75 | } 76 | Ok(Self { name, defaults }) 77 | } 78 | } 79 | 80 | impl Parse for ClassNameArgs { 81 | fn parse(input: ParseStream) -> syn::parse::Result { 82 | let _: Token![=] = input.parse()?; 83 | let name: LitStr = input.parse()?; 84 | Ok(Self { name }) 85 | } 86 | } 87 | 88 | fn get_type( 89 | the_struct: &ItemStruct, 90 | impls: &Vec<&ItemImpl>, 91 | ) -> Result<(ExternalType, &'static str), &'static str> { 92 | let type_traits = [ 93 | (ExternalType::Control, &"ControlExternal"), 94 | (ExternalType::Signal, &"SignalGeneratorExternal"), 95 | (ExternalType::Signal, &"SignalProcessorExternal"), 96 | ]; 97 | //look through the impls and see if we find a matching one, return it and the ExternalType 98 | for i in impls { 99 | match i.self_ty.as_ref() { 100 | Type::Path(tp) => { 101 | //see if the type matches the struct we care about 102 | if tp.path.is_ident(the_struct.ident.clone()) { 103 | //does this impl implement a trait? 104 | if let Some((_, p, _)) = &i.trait_ { 105 | //is it a trait we care about? 106 | if let Some(type_trait) = type_traits 107 | .iter() 108 | .find(|x| p.segments.last().unwrap().value().ident == x.1) 109 | { 110 | return Ok((type_trait.0, type_trait.1)); 111 | } 112 | } 113 | } 114 | } 115 | _ => (), 116 | } 117 | } 118 | Err("Couldn't find External Implementation") 119 | } 120 | 121 | //return the class initialization item 122 | fn add_control(new_method_name: &Ident, free_method: &Ident) -> proc_macro2::TokenStream { 123 | quote! { 124 | pd_ext::class::Class::::register_new(name, pd_ext::method::ClassNewMethod::VarArgs(#new_method_name), Some(#free_method)); 125 | } 126 | } 127 | 128 | //return the class initialization item 129 | fn add_dsp( 130 | trampolines: &mut Vec, 131 | new_method_name: &Ident, 132 | free_method: &Ident, 133 | flat_name: &String, 134 | name_span: Span, 135 | ) -> proc_macro2::TokenStream { 136 | let dsp_method = Ident::new(&(flat_name.clone() + "_dsp"), name_span.clone()); 137 | let perform_method = Ident::new(&(flat_name.clone() + "_perform"), name_span.clone()); 138 | 139 | trampolines.push(quote! { 140 | pub unsafe extern "C" fn #dsp_method( 141 | x: *mut Wrapped, 142 | sp: *mut *mut pd_sys::t_signal, 143 | ) { 144 | let x = &mut *x; 145 | x.dsp(sp, #perform_method); 146 | } 147 | 148 | pub unsafe extern "C" fn #perform_method( 149 | w: *mut pd_sys::t_int, 150 | ) -> *mut pd_sys::t_int { 151 | //actually longer than 2 but .offset(1) didn't seem to work correctly 152 | //but slice does 153 | let x = std::slice::from_raw_parts(w, 2); 154 | let x = &mut *std::mem::transmute::<_, *mut Wrapped>(x[1]); 155 | x.perform(w) 156 | } 157 | }); 158 | 159 | quote! { 160 | pd_ext::class::Class::::register_dsp_new( 161 | name, 162 | pd_ext::method::ClassNewMethod::VarArgs(#new_method_name), 163 | pd_ext::class::SignalClassType::WithInput( #dsp_method, Wrapped::float_convert_field_offset(),), 164 | Some(#free_method),); 165 | } 166 | } 167 | 168 | //returns the method type token stream (for registering), and the trampoline implementation 169 | type MethodRegisterFn = 170 | fn( 171 | trampoline_name: &Ident, 172 | method_name: &Ident, 173 | _method: &ImplItemMethod, 174 | attr: &Attribute, 175 | ) -> syn::Result<(Option, proc_macro2::TokenStream)>; 176 | 177 | fn add_trampoline( 178 | trampoline_name: &Ident, 179 | method_name: &Ident, 180 | _method: &ImplItemMethod, 181 | _attr: &Attribute, 182 | ) -> syn::Result<(Option, proc_macro2::TokenStream)> { 183 | Ok(( 184 | None, 185 | quote! { 186 | pub unsafe extern "C" fn #trampoline_name(x: *mut Wrapped) { 187 | let x = &mut *x; 188 | x.wrapped().#method_name(); 189 | } 190 | }, 191 | )) 192 | } 193 | 194 | fn add_bang( 195 | trampoline_name: &Ident, 196 | method_name: &Ident, 197 | _method: &ImplItemMethod, 198 | _attr: &Attribute, 199 | ) -> syn::Result<(Option, proc_macro2::TokenStream)> { 200 | Ok(( 201 | Some(quote! { pd_ext::method::Method::Bang(#trampoline_name) }), 202 | quote! { 203 | pub unsafe extern "C" fn #trampoline_name(x: *mut Wrapped) { 204 | let x = &mut *x; 205 | x.wrapped().#method_name(); 206 | } 207 | }, 208 | )) 209 | } 210 | 211 | fn add_list( 212 | trampoline_name: &Ident, 213 | method_name: &Ident, 214 | _method: &ImplItemMethod, 215 | _attr: &Attribute, 216 | ) -> syn::Result<(Option, proc_macro2::TokenStream)> { 217 | //TODO validate arguments 218 | Ok(( 219 | Some(quote! { pd_ext::method::Method::List(#trampoline_name) }), 220 | quote! { 221 | pub unsafe extern "C" fn #trampoline_name(x: *mut Wrapped, _sel: /*ignored, always &s_list*/ *mut pd_sys::t_symbol, argc: std::os::raw::c_int, argv: *const pd_sys::t_atom) { 222 | let x = &mut *x; 223 | let args = pd_ext::atom::Atom::slice_from_raw_parts(argv, argc); 224 | x.wrapped().#method_name(args); 225 | } 226 | }, 227 | )) 228 | } 229 | 230 | fn add_anything( 231 | trampoline_name: &Ident, 232 | method_name: &Ident, 233 | _method: &ImplItemMethod, 234 | _attr: &Attribute, 235 | ) -> syn::Result<(Option, proc_macro2::TokenStream)> { 236 | //TODO validate arguments 237 | Ok(( 238 | Some(quote! { pd_ext::method::Method::AnyThing(#trampoline_name) }), 239 | quote! { 240 | pub unsafe extern "C" fn #trampoline_name(x: *mut Wrapped, sel: *mut pd_sys::t_symbol, argc: std::os::raw::c_int, argv: *const pd_sys::t_atom) { 241 | let x = &mut *x; 242 | let args = pd_ext::atom::Atom::slice_from_raw_parts(argv, argc); 243 | x.wrapped().#method_name(pd_ext::symbol::Symbol::try_from(sel).unwrap(), args); 244 | } 245 | }, 246 | )) 247 | } 248 | 249 | fn type_path_final_eq(p: &TypePath, ident: &str) -> bool { 250 | p.path.segments.last().unwrap().value().ident == ident 251 | } 252 | 253 | fn add_sel( 254 | trampoline_name: &Ident, 255 | method_name: &Ident, 256 | method: &ImplItemMethod, 257 | attr: &Attribute, 258 | ) -> syn::Result<(Option, proc_macro2::TokenStream)> { 259 | let mut sel_name = Lit::Str(LitStr::new(&method_name.to_string(), method_name.span())); 260 | let mut defaults = Lit::Int(LitInt::new(0, syn::IntSuffix::Usize, attr.span())); 261 | 262 | //extract name and defaults if they're given 263 | let args: syn::parse::Result = syn::parse2(attr.tts.clone()); 264 | match args { 265 | Ok(args) => { 266 | if let Some(d) = args.defaults { 267 | defaults = d.clone(); 268 | } 269 | if let Some(n) = args.name { 270 | sel_name = n.clone(); 271 | } 272 | } 273 | Err(e) => return Err(syn::Error::new(attr.span(), e)), 274 | } 275 | 276 | let sel_name = quote! { std::ffi::CString::new(#sel_name).unwrap() }; 277 | 278 | //XXX assert that the first arg is SelfRef 279 | 280 | //extract the args 281 | //arg name, arg type, string rep for Sel method, tramp arg type if different (*mut -> &mut) 282 | let args: syn::Result)>> = method 283 | .sig 284 | .decl 285 | .inputs 286 | .iter() 287 | .skip(1) 288 | .map(|a| { 289 | if let FnArg::Captured(a) = a { 290 | match (&a.pat, &a.ty) { 291 | (Pat::Ident(i), Type::Path(p)) => { 292 | if type_path_final_eq(&p, &"t_float") { 293 | return Ok((&i.ident, &a.ty, "F".to_string(), None)); 294 | } else if type_path_final_eq(&p, &"Symbol") { 295 | return Ok(( 296 | &i.ident, 297 | &a.ty, 298 | "S".to_string(), 299 | Some(quote! { *mut pd_sys::t_symbol }), 300 | )); 301 | } 302 | } 303 | (Pat::Ident(i), Type::Reference(_)) => { 304 | //XXX do more validation 305 | return Ok((&i.ident, &a.ty, "VarArg".to_string(), None)); 306 | } 307 | _ => (), 308 | }; 309 | } 310 | 311 | return Err(syn::Error::new( 312 | a.span(), 313 | format!("unsupported arg type {:?}", a), 314 | )); 315 | }) 316 | .collect(); 317 | let args = args?; 318 | 319 | //build variant 320 | let variant = format!( 321 | "Sel{}", 322 | args.iter() 323 | .map(|x| x.2.to_string()) 324 | .collect::>() 325 | .join("") 326 | ); 327 | let vararg = variant == "SelVarArg"; 328 | let variant = Ident::new(&variant, method_name.span()); 329 | 330 | let call = if args.len() == 0 || vararg { 331 | quote! { pd_ext::method::Method::#variant(#sel_name, #trampoline_name)} 332 | } else { 333 | quote! { pd_ext::method::Method::#variant(#sel_name, #trampoline_name, #defaults)} 334 | }; 335 | if vararg { 336 | Ok(( 337 | Some(call), 338 | quote! { 339 | pub unsafe extern "C" fn #trampoline_name(x: *mut Wrapped, _sel: /*ignored*/ *mut pd_sys::t_symbol, argc: std::os::raw::c_int, argv: *const pd_sys::t_atom) { 340 | let x = &mut *x; 341 | let args = pd_ext::atom::Atom::slice_from_raw_parts(argv, argc); 342 | x.wrapped().#method_name(args); 343 | } 344 | }, 345 | )) 346 | } else { 347 | //*mut -> &mut 348 | let mut tramp_args: Vec = Vec::new(); 349 | let mut wrapped_params: Vec = Vec::new(); 350 | let mut wrapped_refs = vec![quote! { let x = &mut *x; }]; 351 | for a in args.iter() { 352 | let ident = a.0; 353 | let typ = a.1; 354 | if let Some(t) = &a.3 { 355 | //TODO allow more types other than symbol 356 | let call_type = quote! { pd_ext::symbol::Symbol }; 357 | wrapped_refs.push(quote! { let #ident = #call_type::try_from(#ident).unwrap(); }); 358 | tramp_args.push(quote! { #ident: #t }); 359 | } else { 360 | tramp_args.push(quote! { #ident: #typ }); 361 | } 362 | wrapped_params.push(a.0.clone()); 363 | } 364 | 365 | Ok(( 366 | Some(call), 367 | quote! { 368 | pub unsafe extern "C" fn #trampoline_name(x: *mut Wrapped, #(#tramp_args),*) { 369 | #(#wrapped_refs)*; 370 | x.wrapped().#method_name(#(#wrapped_params),*); 371 | } 372 | }, 373 | )) 374 | } 375 | } 376 | 377 | static METHOD_ATTRS: &'static [(&'static str, MethodRegisterFn)] = &[ 378 | (&"tramp", add_trampoline), 379 | (&"bang", add_bang), 380 | (&"sel", add_sel), 381 | (&"list", add_list), 382 | (&"anything", add_anything), 383 | ]; 384 | 385 | //extract annotated methods and build trampolines 386 | fn update_method_trampolines( 387 | trampolines: &mut Vec, 388 | register_methods: &mut Vec, 389 | item: &ItemImpl, 390 | class_inst: &Ident, 391 | flat_name: &String, 392 | ) -> syn::Result { 393 | let mut item = item.clone(); 394 | let updated_items: syn::Result> = item 395 | .items 396 | .iter() 397 | .map(|i| match &i { 398 | ImplItem::Method(m) => { 399 | let mut m = m.clone(); 400 | for (n, add_method) in METHOD_ATTRS.iter() { 401 | if let Some(pos) = m 402 | .attrs 403 | .iter() 404 | .position(|a| a.path.segments.last().unwrap().value().ident == n) 405 | { 406 | let a = m.attrs.remove(pos); 407 | 408 | let method_name = m.sig.ident.clone(); 409 | let trampoline_name = Ident::new( 410 | &(format!("{:}_{:}_trampoline", flat_name, method_name)), 411 | m.sig.ident.span(), 412 | ); 413 | let (pd_method, trampoline) = 414 | add_method(&trampoline_name, &method_name, &m, &a)?; 415 | trampolines.push(trampoline); 416 | if let Some(m) = pd_method { 417 | register_methods.push(quote! { 418 | #class_inst.add_method(#m); 419 | }); 420 | } 421 | } 422 | } 423 | Ok(ImplItem::Method(m)) 424 | } 425 | _ => Ok(i.clone()), 426 | }) 427 | .collect(); 428 | item.items = updated_items?; 429 | Ok(quote! { 430 | #item 431 | }) 432 | } 433 | 434 | #[proc_macro] 435 | pub fn external(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 436 | let Parsed { items } = parse_macro_input!(input as Parsed); 437 | match parse_and_build(items) { 438 | Ok(ts) => ts, 439 | Err(err) => err.to_compile_error().into(), 440 | } 441 | } 442 | 443 | fn parse_and_build(items: Vec) -> syn::Result { 444 | let mut impls = Vec::new(); 445 | let mut the_struct = None; 446 | let mut remain = Vec::new(); 447 | let mut trampolines = Vec::new(); 448 | 449 | for item in items.iter() { 450 | match item { 451 | Item::Struct(x) => { 452 | if the_struct.is_some() { 453 | panic!("external! cannot wrap more than one struct"); 454 | } 455 | the_struct = Some(x); 456 | } 457 | Item::Impl(x) => impls.push(x), 458 | _ => remain.push(item), 459 | } 460 | } 461 | 462 | let the_struct = the_struct.expect("didn't find a struct"); 463 | let (etype, extern_impl) = get_type(&the_struct, &impls).unwrap(); 464 | 465 | let name_ident = the_struct.clone(); 466 | let struct_name = the_struct.ident.clone(); 467 | 468 | //build up names 469 | let lower_name = struct_name.to_string().to_lowercase(); 470 | let upper_name = struct_name.to_string().to_uppercase(); 471 | let (flat_name, mut class_name) = match etype { 472 | ExternalType::Signal => (format!("{:}_tilde", lower_name), format!("{}~", lower_name)), 473 | ExternalType::Control => (lower_name.clone(), lower_name.clone()), 474 | }; 475 | 476 | let class_static = Ident::new(&(format!("{:}_CLASS", upper_name)), name_ident.span()); 477 | let class_inst = Ident::new("c", name_ident.span()); 478 | let new_method_name = Ident::new(&(format!("{:}_new", flat_name)), name_ident.span()); 479 | let free_method = Ident::new(&(format!("{:}_free", flat_name)), name_ident.span()); 480 | let setup_method = Ident::new(&(format!("{:}_setup", flat_name)), name_ident.span()); 481 | let wrapper_type = Ident::new(&(format!("{:}Wrapper", extern_impl)), name_ident.span()); 482 | 483 | let wrapped_class = quote! { 484 | //generated 485 | type Wrapped = pd_ext::wrapper::#wrapper_type<#struct_name>; 486 | pub(crate) static mut #class_static: Option<*mut pd_sys::_class> = None; 487 | }; 488 | 489 | //new trampoline 490 | trampolines.push( 491 | quote! { 492 | pub unsafe extern "C" fn #new_method_name (name: *mut pd_sys::t_symbol, argc: std::os::raw::c_int, argv: *const pd_sys::t_atom) -> *mut ::std::os::raw::c_void { 493 | let args = pd_ext::atom::Atom::slice_from_raw_parts(argv, argc); 494 | Wrapped::new(#class_static.expect("class not initialized"), &args, name) 495 | } 496 | }); 497 | 498 | //free trampoline 499 | trampolines.push(quote! { 500 | pub unsafe extern "C" fn #free_method (x: *mut Wrapped) { 501 | let x = &mut *x; 502 | x.free(); 503 | } 504 | }); 505 | 506 | let mut register_methods: Vec = Vec::new(); 507 | 508 | let impls: syn::Result> = impls 509 | .into_iter() 510 | .map(|i| { 511 | match i.self_ty.as_ref() { 512 | Type::Path(tp) => { 513 | //matches struct 514 | if tp.path.is_ident(the_struct.ident.clone()) { 515 | return Ok(update_method_trampolines( 516 | &mut trampolines, 517 | &mut register_methods, 518 | i, 519 | &class_inst, 520 | &flat_name, 521 | )?); 522 | } 523 | } 524 | _ => (), 525 | }; 526 | Ok(quote! { #i }) 527 | }) 528 | .collect(); 529 | let impls = impls?; 530 | 531 | let class_new_method = match etype { 532 | ExternalType::Signal => add_dsp( 533 | &mut trampolines, 534 | &new_method_name, 535 | &free_method, 536 | &flat_name, 537 | name_ident.span(), 538 | ), 539 | ExternalType::Control => add_control(&new_method_name, &free_method), 540 | }; 541 | 542 | //extract the name attribute for the struct, if it exists 543 | //and apply the rename 544 | let mut the_struct = the_struct.clone(); 545 | if let Some(pos) = the_struct 546 | .attrs 547 | .iter() 548 | .position(|a| a.path.segments.last().unwrap().value().ident == "name") 549 | { 550 | let a = the_struct.attrs.remove(pos); 551 | let n: ClassNameArgs = syn::parse2(a.tts.clone())?; 552 | class_name = n.name.value(); 553 | } 554 | 555 | let class_name = LitStr::new(&(class_name), name_ident.span()); 556 | 557 | trampolines.push(quote! { 558 | #[no_mangle] 559 | pub unsafe extern "C" fn #setup_method() { 560 | let name = std::ffi::CString::new(#class_name).unwrap(); 561 | let mut #class_inst = #class_new_method 562 | 563 | #(#register_methods)* 564 | 565 | #class_static = Some(#class_inst.into()); 566 | } 567 | }); 568 | 569 | //how do we not get dupes of TryFrom if it is already included 570 | let expanded = quote! { 571 | use std::convert::TryFrom; 572 | 573 | #the_struct 574 | 575 | #(#impls)* 576 | 577 | #wrapped_class 578 | 579 | #(#trampolines)* 580 | 581 | #(#remain)* 582 | }; 583 | 584 | Ok(proc_macro::TokenStream::from(expanded)) 585 | } 586 | 587 | #[cfg(test)] 588 | mod tests { 589 | #[test] 590 | fn it_works() { 591 | assert_eq!(2 + 2, 4); 592 | } 593 | } 594 | -------------------------------------------------------------------------------- /pd-sys/src/ffi.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen */ 2 | 3 | #[repr(C)] 4 | #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] 5 | pub struct __BindgenBitfieldUnit 6 | where 7 | Storage: AsRef<[u8]> + AsMut<[u8]>, 8 | { 9 | storage: Storage, 10 | align: [Align; 0], 11 | } 12 | impl __BindgenBitfieldUnit 13 | where 14 | Storage: AsRef<[u8]> + AsMut<[u8]>, 15 | { 16 | #[inline] 17 | pub fn new(storage: Storage) -> Self { 18 | Self { storage, align: [] } 19 | } 20 | #[inline] 21 | pub fn get_bit(&self, index: usize) -> bool { 22 | debug_assert!(index / 8 < self.storage.as_ref().len()); 23 | let byte_index = index / 8; 24 | let byte = self.storage.as_ref()[byte_index]; 25 | let bit_index = if cfg!(target_endian = "big") { 26 | 7 - (index % 8) 27 | } else { 28 | index % 8 29 | }; 30 | let mask = 1 << bit_index; 31 | byte & mask == mask 32 | } 33 | #[inline] 34 | pub fn set_bit(&mut self, index: usize, val: bool) { 35 | debug_assert!(index / 8 < self.storage.as_ref().len()); 36 | let byte_index = index / 8; 37 | let byte = &mut self.storage.as_mut()[byte_index]; 38 | let bit_index = if cfg!(target_endian = "big") { 39 | 7 - (index % 8) 40 | } else { 41 | index % 8 42 | }; 43 | let mask = 1 << bit_index; 44 | if val { 45 | *byte |= mask; 46 | } else { 47 | *byte &= !mask; 48 | } 49 | } 50 | #[inline] 51 | pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { 52 | debug_assert!(bit_width <= 64); 53 | debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); 54 | debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); 55 | let mut val = 0; 56 | for i in 0..(bit_width as usize) { 57 | if self.get_bit(i + bit_offset) { 58 | let index = if cfg!(target_endian = "big") { 59 | bit_width as usize - 1 - i 60 | } else { 61 | i 62 | }; 63 | val |= 1 << index; 64 | } 65 | } 66 | val 67 | } 68 | #[inline] 69 | pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { 70 | debug_assert!(bit_width <= 64); 71 | debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); 72 | debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); 73 | for i in 0..(bit_width as usize) { 74 | let mask = 1 << i; 75 | let val_bit_is_set = val & mask == mask; 76 | let index = if cfg!(target_endian = "big") { 77 | bit_width as usize - 1 - i 78 | } else { 79 | i 80 | }; 81 | self.set_bit(index + bit_offset, val_bit_is_set); 82 | } 83 | } 84 | } 85 | pub const CLASS_DEFAULT: u32 = 0; 86 | pub const CLASS_PD: u32 = 1; 87 | pub const CLASS_GOBJ: u32 = 2; 88 | pub const CLASS_PATCHABLE: u32 = 3; 89 | pub const CLASS_NOINLET: u32 = 8; 90 | pub const CLASS_TYPEMASK: u32 = 3; 91 | pub type __off_t = ::std::os::raw::c_long; 92 | pub type __off64_t = ::std::os::raw::c_long; 93 | pub type FILE = _IO_FILE; 94 | pub type _IO_lock_t = ::std::os::raw::c_void; 95 | #[repr(C)] 96 | #[derive(Debug, Copy, Clone)] 97 | pub struct _IO_marker { 98 | pub _next: *mut _IO_marker, 99 | pub _sbuf: *mut _IO_FILE, 100 | pub _pos: ::std::os::raw::c_int, 101 | } 102 | #[test] 103 | fn bindgen_test_layout__IO_marker() { 104 | assert_eq!( 105 | ::std::mem::size_of::<_IO_marker>(), 106 | 24usize, 107 | concat!("Size of: ", stringify!(_IO_marker)) 108 | ); 109 | assert_eq!( 110 | ::std::mem::align_of::<_IO_marker>(), 111 | 8usize, 112 | concat!("Alignment of ", stringify!(_IO_marker)) 113 | ); 114 | assert_eq!( 115 | unsafe { &(*(::std::ptr::null::<_IO_marker>()))._next as *const _ as usize }, 116 | 0usize, 117 | concat!( 118 | "Offset of field: ", 119 | stringify!(_IO_marker), 120 | "::", 121 | stringify!(_next) 122 | ) 123 | ); 124 | assert_eq!( 125 | unsafe { &(*(::std::ptr::null::<_IO_marker>()))._sbuf as *const _ as usize }, 126 | 8usize, 127 | concat!( 128 | "Offset of field: ", 129 | stringify!(_IO_marker), 130 | "::", 131 | stringify!(_sbuf) 132 | ) 133 | ); 134 | assert_eq!( 135 | unsafe { &(*(::std::ptr::null::<_IO_marker>()))._pos as *const _ as usize }, 136 | 16usize, 137 | concat!( 138 | "Offset of field: ", 139 | stringify!(_IO_marker), 140 | "::", 141 | stringify!(_pos) 142 | ) 143 | ); 144 | } 145 | #[repr(C)] 146 | #[derive(Debug, Copy, Clone)] 147 | pub struct _IO_FILE { 148 | pub _flags: ::std::os::raw::c_int, 149 | pub _IO_read_ptr: *mut ::std::os::raw::c_char, 150 | pub _IO_read_end: *mut ::std::os::raw::c_char, 151 | pub _IO_read_base: *mut ::std::os::raw::c_char, 152 | pub _IO_write_base: *mut ::std::os::raw::c_char, 153 | pub _IO_write_ptr: *mut ::std::os::raw::c_char, 154 | pub _IO_write_end: *mut ::std::os::raw::c_char, 155 | pub _IO_buf_base: *mut ::std::os::raw::c_char, 156 | pub _IO_buf_end: *mut ::std::os::raw::c_char, 157 | pub _IO_save_base: *mut ::std::os::raw::c_char, 158 | pub _IO_backup_base: *mut ::std::os::raw::c_char, 159 | pub _IO_save_end: *mut ::std::os::raw::c_char, 160 | pub _markers: *mut _IO_marker, 161 | pub _chain: *mut _IO_FILE, 162 | pub _fileno: ::std::os::raw::c_int, 163 | pub _flags2: ::std::os::raw::c_int, 164 | pub _old_offset: __off_t, 165 | pub _cur_column: ::std::os::raw::c_ushort, 166 | pub _vtable_offset: ::std::os::raw::c_schar, 167 | pub _shortbuf: [::std::os::raw::c_char; 1usize], 168 | pub _lock: *mut _IO_lock_t, 169 | pub _offset: __off64_t, 170 | pub __pad1: *mut ::std::os::raw::c_void, 171 | pub __pad2: *mut ::std::os::raw::c_void, 172 | pub __pad3: *mut ::std::os::raw::c_void, 173 | pub __pad4: *mut ::std::os::raw::c_void, 174 | pub __pad5: usize, 175 | pub _mode: ::std::os::raw::c_int, 176 | pub _unused2: [::std::os::raw::c_char; 20usize], 177 | } 178 | #[test] 179 | fn bindgen_test_layout__IO_FILE() { 180 | assert_eq!( 181 | ::std::mem::size_of::<_IO_FILE>(), 182 | 216usize, 183 | concat!("Size of: ", stringify!(_IO_FILE)) 184 | ); 185 | assert_eq!( 186 | ::std::mem::align_of::<_IO_FILE>(), 187 | 8usize, 188 | concat!("Alignment of ", stringify!(_IO_FILE)) 189 | ); 190 | assert_eq!( 191 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._flags as *const _ as usize }, 192 | 0usize, 193 | concat!( 194 | "Offset of field: ", 195 | stringify!(_IO_FILE), 196 | "::", 197 | stringify!(_flags) 198 | ) 199 | ); 200 | assert_eq!( 201 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_read_ptr as *const _ as usize }, 202 | 8usize, 203 | concat!( 204 | "Offset of field: ", 205 | stringify!(_IO_FILE), 206 | "::", 207 | stringify!(_IO_read_ptr) 208 | ) 209 | ); 210 | assert_eq!( 211 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_read_end as *const _ as usize }, 212 | 16usize, 213 | concat!( 214 | "Offset of field: ", 215 | stringify!(_IO_FILE), 216 | "::", 217 | stringify!(_IO_read_end) 218 | ) 219 | ); 220 | assert_eq!( 221 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_read_base as *const _ as usize }, 222 | 24usize, 223 | concat!( 224 | "Offset of field: ", 225 | stringify!(_IO_FILE), 226 | "::", 227 | stringify!(_IO_read_base) 228 | ) 229 | ); 230 | assert_eq!( 231 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_write_base as *const _ as usize }, 232 | 32usize, 233 | concat!( 234 | "Offset of field: ", 235 | stringify!(_IO_FILE), 236 | "::", 237 | stringify!(_IO_write_base) 238 | ) 239 | ); 240 | assert_eq!( 241 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_write_ptr as *const _ as usize }, 242 | 40usize, 243 | concat!( 244 | "Offset of field: ", 245 | stringify!(_IO_FILE), 246 | "::", 247 | stringify!(_IO_write_ptr) 248 | ) 249 | ); 250 | assert_eq!( 251 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_write_end as *const _ as usize }, 252 | 48usize, 253 | concat!( 254 | "Offset of field: ", 255 | stringify!(_IO_FILE), 256 | "::", 257 | stringify!(_IO_write_end) 258 | ) 259 | ); 260 | assert_eq!( 261 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_buf_base as *const _ as usize }, 262 | 56usize, 263 | concat!( 264 | "Offset of field: ", 265 | stringify!(_IO_FILE), 266 | "::", 267 | stringify!(_IO_buf_base) 268 | ) 269 | ); 270 | assert_eq!( 271 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_buf_end as *const _ as usize }, 272 | 64usize, 273 | concat!( 274 | "Offset of field: ", 275 | stringify!(_IO_FILE), 276 | "::", 277 | stringify!(_IO_buf_end) 278 | ) 279 | ); 280 | assert_eq!( 281 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_save_base as *const _ as usize }, 282 | 72usize, 283 | concat!( 284 | "Offset of field: ", 285 | stringify!(_IO_FILE), 286 | "::", 287 | stringify!(_IO_save_base) 288 | ) 289 | ); 290 | assert_eq!( 291 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_backup_base as *const _ as usize }, 292 | 80usize, 293 | concat!( 294 | "Offset of field: ", 295 | stringify!(_IO_FILE), 296 | "::", 297 | stringify!(_IO_backup_base) 298 | ) 299 | ); 300 | assert_eq!( 301 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._IO_save_end as *const _ as usize }, 302 | 88usize, 303 | concat!( 304 | "Offset of field: ", 305 | stringify!(_IO_FILE), 306 | "::", 307 | stringify!(_IO_save_end) 308 | ) 309 | ); 310 | assert_eq!( 311 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._markers as *const _ as usize }, 312 | 96usize, 313 | concat!( 314 | "Offset of field: ", 315 | stringify!(_IO_FILE), 316 | "::", 317 | stringify!(_markers) 318 | ) 319 | ); 320 | assert_eq!( 321 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._chain as *const _ as usize }, 322 | 104usize, 323 | concat!( 324 | "Offset of field: ", 325 | stringify!(_IO_FILE), 326 | "::", 327 | stringify!(_chain) 328 | ) 329 | ); 330 | assert_eq!( 331 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._fileno as *const _ as usize }, 332 | 112usize, 333 | concat!( 334 | "Offset of field: ", 335 | stringify!(_IO_FILE), 336 | "::", 337 | stringify!(_fileno) 338 | ) 339 | ); 340 | assert_eq!( 341 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._flags2 as *const _ as usize }, 342 | 116usize, 343 | concat!( 344 | "Offset of field: ", 345 | stringify!(_IO_FILE), 346 | "::", 347 | stringify!(_flags2) 348 | ) 349 | ); 350 | assert_eq!( 351 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._old_offset as *const _ as usize }, 352 | 120usize, 353 | concat!( 354 | "Offset of field: ", 355 | stringify!(_IO_FILE), 356 | "::", 357 | stringify!(_old_offset) 358 | ) 359 | ); 360 | assert_eq!( 361 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._cur_column as *const _ as usize }, 362 | 128usize, 363 | concat!( 364 | "Offset of field: ", 365 | stringify!(_IO_FILE), 366 | "::", 367 | stringify!(_cur_column) 368 | ) 369 | ); 370 | assert_eq!( 371 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._vtable_offset as *const _ as usize }, 372 | 130usize, 373 | concat!( 374 | "Offset of field: ", 375 | stringify!(_IO_FILE), 376 | "::", 377 | stringify!(_vtable_offset) 378 | ) 379 | ); 380 | assert_eq!( 381 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._shortbuf as *const _ as usize }, 382 | 131usize, 383 | concat!( 384 | "Offset of field: ", 385 | stringify!(_IO_FILE), 386 | "::", 387 | stringify!(_shortbuf) 388 | ) 389 | ); 390 | assert_eq!( 391 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._lock as *const _ as usize }, 392 | 136usize, 393 | concat!( 394 | "Offset of field: ", 395 | stringify!(_IO_FILE), 396 | "::", 397 | stringify!(_lock) 398 | ) 399 | ); 400 | assert_eq!( 401 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._offset as *const _ as usize }, 402 | 144usize, 403 | concat!( 404 | "Offset of field: ", 405 | stringify!(_IO_FILE), 406 | "::", 407 | stringify!(_offset) 408 | ) 409 | ); 410 | assert_eq!( 411 | unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad1 as *const _ as usize }, 412 | 152usize, 413 | concat!( 414 | "Offset of field: ", 415 | stringify!(_IO_FILE), 416 | "::", 417 | stringify!(__pad1) 418 | ) 419 | ); 420 | assert_eq!( 421 | unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad2 as *const _ as usize }, 422 | 160usize, 423 | concat!( 424 | "Offset of field: ", 425 | stringify!(_IO_FILE), 426 | "::", 427 | stringify!(__pad2) 428 | ) 429 | ); 430 | assert_eq!( 431 | unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad3 as *const _ as usize }, 432 | 168usize, 433 | concat!( 434 | "Offset of field: ", 435 | stringify!(_IO_FILE), 436 | "::", 437 | stringify!(__pad3) 438 | ) 439 | ); 440 | assert_eq!( 441 | unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad4 as *const _ as usize }, 442 | 176usize, 443 | concat!( 444 | "Offset of field: ", 445 | stringify!(_IO_FILE), 446 | "::", 447 | stringify!(__pad4) 448 | ) 449 | ); 450 | assert_eq!( 451 | unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad5 as *const _ as usize }, 452 | 184usize, 453 | concat!( 454 | "Offset of field: ", 455 | stringify!(_IO_FILE), 456 | "::", 457 | stringify!(__pad5) 458 | ) 459 | ); 460 | assert_eq!( 461 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._mode as *const _ as usize }, 462 | 192usize, 463 | concat!( 464 | "Offset of field: ", 465 | stringify!(_IO_FILE), 466 | "::", 467 | stringify!(_mode) 468 | ) 469 | ); 470 | assert_eq!( 471 | unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._unused2 as *const _ as usize }, 472 | 196usize, 473 | concat!( 474 | "Offset of field: ", 475 | stringify!(_IO_FILE), 476 | "::", 477 | stringify!(_unused2) 478 | ) 479 | ); 480 | } 481 | pub type t_int = ::std::os::raw::c_long; 482 | pub type t_float = f32; 483 | pub type t_floatarg = f32; 484 | #[repr(C)] 485 | #[derive(Debug, Copy, Clone)] 486 | pub struct _symbol { 487 | pub s_name: *const ::std::os::raw::c_char, 488 | pub s_thing: *mut *mut _class, 489 | pub s_next: *mut _symbol, 490 | } 491 | #[test] 492 | fn bindgen_test_layout__symbol() { 493 | assert_eq!( 494 | ::std::mem::size_of::<_symbol>(), 495 | 24usize, 496 | concat!("Size of: ", stringify!(_symbol)) 497 | ); 498 | assert_eq!( 499 | ::std::mem::align_of::<_symbol>(), 500 | 8usize, 501 | concat!("Alignment of ", stringify!(_symbol)) 502 | ); 503 | assert_eq!( 504 | unsafe { &(*(::std::ptr::null::<_symbol>())).s_name as *const _ as usize }, 505 | 0usize, 506 | concat!( 507 | "Offset of field: ", 508 | stringify!(_symbol), 509 | "::", 510 | stringify!(s_name) 511 | ) 512 | ); 513 | assert_eq!( 514 | unsafe { &(*(::std::ptr::null::<_symbol>())).s_thing as *const _ as usize }, 515 | 8usize, 516 | concat!( 517 | "Offset of field: ", 518 | stringify!(_symbol), 519 | "::", 520 | stringify!(s_thing) 521 | ) 522 | ); 523 | assert_eq!( 524 | unsafe { &(*(::std::ptr::null::<_symbol>())).s_next as *const _ as usize }, 525 | 16usize, 526 | concat!( 527 | "Offset of field: ", 528 | stringify!(_symbol), 529 | "::", 530 | stringify!(s_next) 531 | ) 532 | ); 533 | } 534 | pub type t_symbol = _symbol; 535 | #[repr(C)] 536 | #[derive(Debug, Copy, Clone)] 537 | pub struct _array { 538 | _unused: [u8; 0], 539 | } 540 | #[repr(C)] 541 | #[derive(Copy, Clone)] 542 | pub struct _gstub { 543 | pub gs_un: _gstub__bindgen_ty_1, 544 | pub gs_which: ::std::os::raw::c_int, 545 | pub gs_refcount: ::std::os::raw::c_int, 546 | } 547 | #[repr(C)] 548 | #[derive(Copy, Clone)] 549 | pub union _gstub__bindgen_ty_1 { 550 | pub gs_glist: *mut _glist, 551 | pub gs_array: *mut _array, 552 | _bindgen_union_align: u64, 553 | } 554 | #[test] 555 | fn bindgen_test_layout__gstub__bindgen_ty_1() { 556 | assert_eq!( 557 | ::std::mem::size_of::<_gstub__bindgen_ty_1>(), 558 | 8usize, 559 | concat!("Size of: ", stringify!(_gstub__bindgen_ty_1)) 560 | ); 561 | assert_eq!( 562 | ::std::mem::align_of::<_gstub__bindgen_ty_1>(), 563 | 8usize, 564 | concat!("Alignment of ", stringify!(_gstub__bindgen_ty_1)) 565 | ); 566 | assert_eq!( 567 | unsafe { &(*(::std::ptr::null::<_gstub__bindgen_ty_1>())).gs_glist as *const _ as usize }, 568 | 0usize, 569 | concat!( 570 | "Offset of field: ", 571 | stringify!(_gstub__bindgen_ty_1), 572 | "::", 573 | stringify!(gs_glist) 574 | ) 575 | ); 576 | assert_eq!( 577 | unsafe { &(*(::std::ptr::null::<_gstub__bindgen_ty_1>())).gs_array as *const _ as usize }, 578 | 0usize, 579 | concat!( 580 | "Offset of field: ", 581 | stringify!(_gstub__bindgen_ty_1), 582 | "::", 583 | stringify!(gs_array) 584 | ) 585 | ); 586 | } 587 | #[test] 588 | fn bindgen_test_layout__gstub() { 589 | assert_eq!( 590 | ::std::mem::size_of::<_gstub>(), 591 | 16usize, 592 | concat!("Size of: ", stringify!(_gstub)) 593 | ); 594 | assert_eq!( 595 | ::std::mem::align_of::<_gstub>(), 596 | 8usize, 597 | concat!("Alignment of ", stringify!(_gstub)) 598 | ); 599 | assert_eq!( 600 | unsafe { &(*(::std::ptr::null::<_gstub>())).gs_un as *const _ as usize }, 601 | 0usize, 602 | concat!( 603 | "Offset of field: ", 604 | stringify!(_gstub), 605 | "::", 606 | stringify!(gs_un) 607 | ) 608 | ); 609 | assert_eq!( 610 | unsafe { &(*(::std::ptr::null::<_gstub>())).gs_which as *const _ as usize }, 611 | 8usize, 612 | concat!( 613 | "Offset of field: ", 614 | stringify!(_gstub), 615 | "::", 616 | stringify!(gs_which) 617 | ) 618 | ); 619 | assert_eq!( 620 | unsafe { &(*(::std::ptr::null::<_gstub>())).gs_refcount as *const _ as usize }, 621 | 12usize, 622 | concat!( 623 | "Offset of field: ", 624 | stringify!(_gstub), 625 | "::", 626 | stringify!(gs_refcount) 627 | ) 628 | ); 629 | } 630 | pub type t_gstub = _gstub; 631 | #[repr(C)] 632 | #[derive(Copy, Clone)] 633 | pub struct _gpointer { 634 | pub gp_un: _gpointer__bindgen_ty_1, 635 | pub gp_valid: ::std::os::raw::c_int, 636 | pub gp_stub: *mut t_gstub, 637 | } 638 | #[repr(C)] 639 | #[derive(Copy, Clone)] 640 | pub union _gpointer__bindgen_ty_1 { 641 | pub gp_scalar: *mut _scalar, 642 | pub gp_w: *mut word, 643 | _bindgen_union_align: u64, 644 | } 645 | #[test] 646 | fn bindgen_test_layout__gpointer__bindgen_ty_1() { 647 | assert_eq!( 648 | ::std::mem::size_of::<_gpointer__bindgen_ty_1>(), 649 | 8usize, 650 | concat!("Size of: ", stringify!(_gpointer__bindgen_ty_1)) 651 | ); 652 | assert_eq!( 653 | ::std::mem::align_of::<_gpointer__bindgen_ty_1>(), 654 | 8usize, 655 | concat!("Alignment of ", stringify!(_gpointer__bindgen_ty_1)) 656 | ); 657 | assert_eq!( 658 | unsafe { 659 | &(*(::std::ptr::null::<_gpointer__bindgen_ty_1>())).gp_scalar as *const _ as usize 660 | }, 661 | 0usize, 662 | concat!( 663 | "Offset of field: ", 664 | stringify!(_gpointer__bindgen_ty_1), 665 | "::", 666 | stringify!(gp_scalar) 667 | ) 668 | ); 669 | assert_eq!( 670 | unsafe { &(*(::std::ptr::null::<_gpointer__bindgen_ty_1>())).gp_w as *const _ as usize }, 671 | 0usize, 672 | concat!( 673 | "Offset of field: ", 674 | stringify!(_gpointer__bindgen_ty_1), 675 | "::", 676 | stringify!(gp_w) 677 | ) 678 | ); 679 | } 680 | #[test] 681 | fn bindgen_test_layout__gpointer() { 682 | assert_eq!( 683 | ::std::mem::size_of::<_gpointer>(), 684 | 24usize, 685 | concat!("Size of: ", stringify!(_gpointer)) 686 | ); 687 | assert_eq!( 688 | ::std::mem::align_of::<_gpointer>(), 689 | 8usize, 690 | concat!("Alignment of ", stringify!(_gpointer)) 691 | ); 692 | assert_eq!( 693 | unsafe { &(*(::std::ptr::null::<_gpointer>())).gp_un as *const _ as usize }, 694 | 0usize, 695 | concat!( 696 | "Offset of field: ", 697 | stringify!(_gpointer), 698 | "::", 699 | stringify!(gp_un) 700 | ) 701 | ); 702 | assert_eq!( 703 | unsafe { &(*(::std::ptr::null::<_gpointer>())).gp_valid as *const _ as usize }, 704 | 8usize, 705 | concat!( 706 | "Offset of field: ", 707 | stringify!(_gpointer), 708 | "::", 709 | stringify!(gp_valid) 710 | ) 711 | ); 712 | assert_eq!( 713 | unsafe { &(*(::std::ptr::null::<_gpointer>())).gp_stub as *const _ as usize }, 714 | 16usize, 715 | concat!( 716 | "Offset of field: ", 717 | stringify!(_gpointer), 718 | "::", 719 | stringify!(gp_stub) 720 | ) 721 | ); 722 | } 723 | pub type t_gpointer = _gpointer; 724 | #[repr(C)] 725 | #[derive(Copy, Clone)] 726 | pub union word { 727 | pub w_float: t_float, 728 | pub w_symbol: *mut t_symbol, 729 | pub w_gpointer: *mut t_gpointer, 730 | pub w_array: *mut _array, 731 | pub w_binbuf: *mut _binbuf, 732 | pub w_index: ::std::os::raw::c_int, 733 | _bindgen_union_align: u64, 734 | } 735 | #[test] 736 | fn bindgen_test_layout_word() { 737 | assert_eq!( 738 | ::std::mem::size_of::(), 739 | 8usize, 740 | concat!("Size of: ", stringify!(word)) 741 | ); 742 | assert_eq!( 743 | ::std::mem::align_of::(), 744 | 8usize, 745 | concat!("Alignment of ", stringify!(word)) 746 | ); 747 | assert_eq!( 748 | unsafe { &(*(::std::ptr::null::())).w_float as *const _ as usize }, 749 | 0usize, 750 | concat!( 751 | "Offset of field: ", 752 | stringify!(word), 753 | "::", 754 | stringify!(w_float) 755 | ) 756 | ); 757 | assert_eq!( 758 | unsafe { &(*(::std::ptr::null::())).w_symbol as *const _ as usize }, 759 | 0usize, 760 | concat!( 761 | "Offset of field: ", 762 | stringify!(word), 763 | "::", 764 | stringify!(w_symbol) 765 | ) 766 | ); 767 | assert_eq!( 768 | unsafe { &(*(::std::ptr::null::())).w_gpointer as *const _ as usize }, 769 | 0usize, 770 | concat!( 771 | "Offset of field: ", 772 | stringify!(word), 773 | "::", 774 | stringify!(w_gpointer) 775 | ) 776 | ); 777 | assert_eq!( 778 | unsafe { &(*(::std::ptr::null::())).w_array as *const _ as usize }, 779 | 0usize, 780 | concat!( 781 | "Offset of field: ", 782 | stringify!(word), 783 | "::", 784 | stringify!(w_array) 785 | ) 786 | ); 787 | assert_eq!( 788 | unsafe { &(*(::std::ptr::null::())).w_binbuf as *const _ as usize }, 789 | 0usize, 790 | concat!( 791 | "Offset of field: ", 792 | stringify!(word), 793 | "::", 794 | stringify!(w_binbuf) 795 | ) 796 | ); 797 | assert_eq!( 798 | unsafe { &(*(::std::ptr::null::())).w_index as *const _ as usize }, 799 | 0usize, 800 | concat!( 801 | "Offset of field: ", 802 | stringify!(word), 803 | "::", 804 | stringify!(w_index) 805 | ) 806 | ); 807 | } 808 | pub type t_word = word; 809 | pub mod t_atomtype { 810 | pub type Type = u32; 811 | pub const A_NULL: Type = 0; 812 | pub const A_FLOAT: Type = 1; 813 | pub const A_SYMBOL: Type = 2; 814 | pub const A_POINTER: Type = 3; 815 | pub const A_SEMI: Type = 4; 816 | pub const A_COMMA: Type = 5; 817 | pub const A_DEFFLOAT: Type = 6; 818 | pub const A_DEFSYM: Type = 7; 819 | pub const A_DOLLAR: Type = 8; 820 | pub const A_DOLLSYM: Type = 9; 821 | pub const A_GIMME: Type = 10; 822 | pub const A_CANT: Type = 11; 823 | } 824 | #[repr(C)] 825 | #[derive(Copy, Clone)] 826 | pub struct _atom { 827 | pub a_type: t_atomtype::Type, 828 | pub a_w: word, 829 | } 830 | #[test] 831 | fn bindgen_test_layout__atom() { 832 | assert_eq!( 833 | ::std::mem::size_of::<_atom>(), 834 | 16usize, 835 | concat!("Size of: ", stringify!(_atom)) 836 | ); 837 | assert_eq!( 838 | ::std::mem::align_of::<_atom>(), 839 | 8usize, 840 | concat!("Alignment of ", stringify!(_atom)) 841 | ); 842 | assert_eq!( 843 | unsafe { &(*(::std::ptr::null::<_atom>())).a_type as *const _ as usize }, 844 | 0usize, 845 | concat!( 846 | "Offset of field: ", 847 | stringify!(_atom), 848 | "::", 849 | stringify!(a_type) 850 | ) 851 | ); 852 | assert_eq!( 853 | unsafe { &(*(::std::ptr::null::<_atom>())).a_w as *const _ as usize }, 854 | 8usize, 855 | concat!( 856 | "Offset of field: ", 857 | stringify!(_atom), 858 | "::", 859 | stringify!(a_w) 860 | ) 861 | ); 862 | } 863 | pub type t_atom = _atom; 864 | #[repr(C)] 865 | #[derive(Debug, Copy, Clone)] 866 | pub struct _class { 867 | _unused: [u8; 0], 868 | } 869 | #[repr(C)] 870 | #[derive(Debug, Copy, Clone)] 871 | pub struct _outlet { 872 | _unused: [u8; 0], 873 | } 874 | #[repr(C)] 875 | #[derive(Debug, Copy, Clone)] 876 | pub struct _inlet { 877 | _unused: [u8; 0], 878 | } 879 | #[repr(C)] 880 | #[derive(Debug, Copy, Clone)] 881 | pub struct _binbuf { 882 | _unused: [u8; 0], 883 | } 884 | #[repr(C)] 885 | #[derive(Debug, Copy, Clone)] 886 | pub struct _clock { 887 | _unused: [u8; 0], 888 | } 889 | #[repr(C)] 890 | #[derive(Debug, Copy, Clone)] 891 | pub struct _glist { 892 | _unused: [u8; 0], 893 | } 894 | pub type t_pd = *mut _class; 895 | #[repr(C)] 896 | #[derive(Debug, Copy, Clone)] 897 | pub struct _gobj { 898 | pub g_pd: t_pd, 899 | pub g_next: *mut _gobj, 900 | } 901 | #[test] 902 | fn bindgen_test_layout__gobj() { 903 | assert_eq!( 904 | ::std::mem::size_of::<_gobj>(), 905 | 16usize, 906 | concat!("Size of: ", stringify!(_gobj)) 907 | ); 908 | assert_eq!( 909 | ::std::mem::align_of::<_gobj>(), 910 | 8usize, 911 | concat!("Alignment of ", stringify!(_gobj)) 912 | ); 913 | assert_eq!( 914 | unsafe { &(*(::std::ptr::null::<_gobj>())).g_pd as *const _ as usize }, 915 | 0usize, 916 | concat!( 917 | "Offset of field: ", 918 | stringify!(_gobj), 919 | "::", 920 | stringify!(g_pd) 921 | ) 922 | ); 923 | assert_eq!( 924 | unsafe { &(*(::std::ptr::null::<_gobj>())).g_next as *const _ as usize }, 925 | 8usize, 926 | concat!( 927 | "Offset of field: ", 928 | stringify!(_gobj), 929 | "::", 930 | stringify!(g_next) 931 | ) 932 | ); 933 | } 934 | pub type t_gobj = _gobj; 935 | #[repr(C)] 936 | #[derive(Copy, Clone)] 937 | pub struct _scalar { 938 | pub sc_gobj: t_gobj, 939 | pub sc_template: *mut t_symbol, 940 | pub sc_vec: [t_word; 1usize], 941 | } 942 | #[test] 943 | fn bindgen_test_layout__scalar() { 944 | assert_eq!( 945 | ::std::mem::size_of::<_scalar>(), 946 | 32usize, 947 | concat!("Size of: ", stringify!(_scalar)) 948 | ); 949 | assert_eq!( 950 | ::std::mem::align_of::<_scalar>(), 951 | 8usize, 952 | concat!("Alignment of ", stringify!(_scalar)) 953 | ); 954 | assert_eq!( 955 | unsafe { &(*(::std::ptr::null::<_scalar>())).sc_gobj as *const _ as usize }, 956 | 0usize, 957 | concat!( 958 | "Offset of field: ", 959 | stringify!(_scalar), 960 | "::", 961 | stringify!(sc_gobj) 962 | ) 963 | ); 964 | assert_eq!( 965 | unsafe { &(*(::std::ptr::null::<_scalar>())).sc_template as *const _ as usize }, 966 | 16usize, 967 | concat!( 968 | "Offset of field: ", 969 | stringify!(_scalar), 970 | "::", 971 | stringify!(sc_template) 972 | ) 973 | ); 974 | assert_eq!( 975 | unsafe { &(*(::std::ptr::null::<_scalar>())).sc_vec as *const _ as usize }, 976 | 24usize, 977 | concat!( 978 | "Offset of field: ", 979 | stringify!(_scalar), 980 | "::", 981 | stringify!(sc_vec) 982 | ) 983 | ); 984 | } 985 | pub type t_scalar = _scalar; 986 | #[repr(C)] 987 | #[derive(Debug, Copy, Clone)] 988 | pub struct _text { 989 | pub te_g: t_gobj, 990 | pub te_binbuf: *mut _binbuf, 991 | pub te_outlet: *mut _outlet, 992 | pub te_inlet: *mut _inlet, 993 | pub te_xpix: ::std::os::raw::c_short, 994 | pub te_ypix: ::std::os::raw::c_short, 995 | pub te_width: ::std::os::raw::c_short, 996 | pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize], u8>, 997 | pub __bindgen_padding_0: u8, 998 | } 999 | #[test] 1000 | fn bindgen_test_layout__text() { 1001 | assert_eq!( 1002 | ::std::mem::size_of::<_text>(), 1003 | 48usize, 1004 | concat!("Size of: ", stringify!(_text)) 1005 | ); 1006 | assert_eq!( 1007 | ::std::mem::align_of::<_text>(), 1008 | 8usize, 1009 | concat!("Alignment of ", stringify!(_text)) 1010 | ); 1011 | assert_eq!( 1012 | unsafe { &(*(::std::ptr::null::<_text>())).te_g as *const _ as usize }, 1013 | 0usize, 1014 | concat!( 1015 | "Offset of field: ", 1016 | stringify!(_text), 1017 | "::", 1018 | stringify!(te_g) 1019 | ) 1020 | ); 1021 | assert_eq!( 1022 | unsafe { &(*(::std::ptr::null::<_text>())).te_binbuf as *const _ as usize }, 1023 | 16usize, 1024 | concat!( 1025 | "Offset of field: ", 1026 | stringify!(_text), 1027 | "::", 1028 | stringify!(te_binbuf) 1029 | ) 1030 | ); 1031 | assert_eq!( 1032 | unsafe { &(*(::std::ptr::null::<_text>())).te_outlet as *const _ as usize }, 1033 | 24usize, 1034 | concat!( 1035 | "Offset of field: ", 1036 | stringify!(_text), 1037 | "::", 1038 | stringify!(te_outlet) 1039 | ) 1040 | ); 1041 | assert_eq!( 1042 | unsafe { &(*(::std::ptr::null::<_text>())).te_inlet as *const _ as usize }, 1043 | 32usize, 1044 | concat!( 1045 | "Offset of field: ", 1046 | stringify!(_text), 1047 | "::", 1048 | stringify!(te_inlet) 1049 | ) 1050 | ); 1051 | assert_eq!( 1052 | unsafe { &(*(::std::ptr::null::<_text>())).te_xpix as *const _ as usize }, 1053 | 40usize, 1054 | concat!( 1055 | "Offset of field: ", 1056 | stringify!(_text), 1057 | "::", 1058 | stringify!(te_xpix) 1059 | ) 1060 | ); 1061 | assert_eq!( 1062 | unsafe { &(*(::std::ptr::null::<_text>())).te_ypix as *const _ as usize }, 1063 | 42usize, 1064 | concat!( 1065 | "Offset of field: ", 1066 | stringify!(_text), 1067 | "::", 1068 | stringify!(te_ypix) 1069 | ) 1070 | ); 1071 | assert_eq!( 1072 | unsafe { &(*(::std::ptr::null::<_text>())).te_width as *const _ as usize }, 1073 | 44usize, 1074 | concat!( 1075 | "Offset of field: ", 1076 | stringify!(_text), 1077 | "::", 1078 | stringify!(te_width) 1079 | ) 1080 | ); 1081 | } 1082 | impl _text { 1083 | #[inline] 1084 | pub fn te_type(&self) -> ::std::os::raw::c_uint { 1085 | unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 2u8) as u32) } 1086 | } 1087 | #[inline] 1088 | pub fn set_te_type(&mut self, val: ::std::os::raw::c_uint) { 1089 | unsafe { 1090 | let val: u32 = ::std::mem::transmute(val); 1091 | self._bitfield_1.set(0usize, 2u8, val as u64) 1092 | } 1093 | } 1094 | #[inline] 1095 | pub fn new_bitfield_1( 1096 | te_type: ::std::os::raw::c_uint, 1097 | ) -> __BindgenBitfieldUnit<[u8; 1usize], u8> { 1098 | let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize], u8> = 1099 | Default::default(); 1100 | __bindgen_bitfield_unit.set(0usize, 2u8, { 1101 | let te_type: u32 = unsafe { ::std::mem::transmute(te_type) }; 1102 | te_type as u64 1103 | }); 1104 | __bindgen_bitfield_unit 1105 | } 1106 | } 1107 | pub type t_object = _text; 1108 | pub type t_method = ::std::option::Option; 1109 | pub type t_newmethod = ::std::option::Option *mut ::std::os::raw::c_void>; 1110 | extern "C" { 1111 | pub fn pd_typedmess( 1112 | x: *mut t_pd, 1113 | s: *mut t_symbol, 1114 | argc: ::std::os::raw::c_int, 1115 | argv: *mut t_atom, 1116 | ); 1117 | } 1118 | extern "C" { 1119 | pub fn pd_forwardmess(x: *mut t_pd, argc: ::std::os::raw::c_int, argv: *mut t_atom); 1120 | } 1121 | extern "C" { 1122 | pub fn gensym(s: *const ::std::os::raw::c_char) -> *mut t_symbol; 1123 | } 1124 | extern "C" { 1125 | pub fn pd_vmess(x: *mut t_pd, s: *mut t_symbol, fmt: *mut ::std::os::raw::c_char, ...); 1126 | } 1127 | extern "C" { 1128 | pub fn obj_list( 1129 | x: *mut t_object, 1130 | s: *mut t_symbol, 1131 | argc: ::std::os::raw::c_int, 1132 | argv: *mut t_atom, 1133 | ); 1134 | } 1135 | extern "C" { 1136 | pub fn pd_newest() -> *mut t_pd; 1137 | } 1138 | extern "C" { 1139 | pub fn getbytes(nbytes: usize) -> *mut ::std::os::raw::c_void; 1140 | } 1141 | extern "C" { 1142 | pub fn getzbytes(nbytes: usize) -> *mut ::std::os::raw::c_void; 1143 | } 1144 | extern "C" { 1145 | pub fn copybytes( 1146 | src: *const ::std::os::raw::c_void, 1147 | nbytes: usize, 1148 | ) -> *mut ::std::os::raw::c_void; 1149 | } 1150 | extern "C" { 1151 | pub fn freebytes(x: *mut ::std::os::raw::c_void, nbytes: usize); 1152 | } 1153 | extern "C" { 1154 | pub fn resizebytes( 1155 | x: *mut ::std::os::raw::c_void, 1156 | oldsize: usize, 1157 | newsize: usize, 1158 | ) -> *mut ::std::os::raw::c_void; 1159 | } 1160 | extern "C" { 1161 | pub fn atom_getfloat(a: *const t_atom) -> t_float; 1162 | } 1163 | extern "C" { 1164 | pub fn atom_getint(a: *const t_atom) -> t_int; 1165 | } 1166 | extern "C" { 1167 | pub fn atom_getsymbol(a: *const t_atom) -> *mut t_symbol; 1168 | } 1169 | extern "C" { 1170 | pub fn atom_gensym(a: *const t_atom) -> *mut t_symbol; 1171 | } 1172 | extern "C" { 1173 | pub fn atom_getfloatarg( 1174 | which: ::std::os::raw::c_int, 1175 | argc: ::std::os::raw::c_int, 1176 | argv: *const t_atom, 1177 | ) -> t_float; 1178 | } 1179 | extern "C" { 1180 | pub fn atom_getintarg( 1181 | which: ::std::os::raw::c_int, 1182 | argc: ::std::os::raw::c_int, 1183 | argv: *const t_atom, 1184 | ) -> t_int; 1185 | } 1186 | extern "C" { 1187 | pub fn atom_getsymbolarg( 1188 | which: ::std::os::raw::c_int, 1189 | argc: ::std::os::raw::c_int, 1190 | argv: *const t_atom, 1191 | ) -> *mut t_symbol; 1192 | } 1193 | extern "C" { 1194 | pub fn atom_string( 1195 | a: *const t_atom, 1196 | buf: *mut ::std::os::raw::c_char, 1197 | bufsize: ::std::os::raw::c_uint, 1198 | ); 1199 | } 1200 | extern "C" { 1201 | pub fn binbuf_new() -> *mut _binbuf; 1202 | } 1203 | extern "C" { 1204 | pub fn binbuf_free(x: *mut _binbuf); 1205 | } 1206 | extern "C" { 1207 | pub fn binbuf_duplicate(y: *const _binbuf) -> *mut _binbuf; 1208 | } 1209 | extern "C" { 1210 | pub fn binbuf_text(x: *mut _binbuf, text: *const ::std::os::raw::c_char, size: usize); 1211 | } 1212 | extern "C" { 1213 | pub fn binbuf_gettext( 1214 | x: *const _binbuf, 1215 | bufp: *mut *mut ::std::os::raw::c_char, 1216 | lengthp: *mut ::std::os::raw::c_int, 1217 | ); 1218 | } 1219 | extern "C" { 1220 | pub fn binbuf_clear(x: *mut _binbuf); 1221 | } 1222 | extern "C" { 1223 | pub fn binbuf_add(x: *mut _binbuf, argc: ::std::os::raw::c_int, argv: *const t_atom); 1224 | } 1225 | extern "C" { 1226 | pub fn binbuf_addv(x: *mut _binbuf, fmt: *const ::std::os::raw::c_char, ...); 1227 | } 1228 | extern "C" { 1229 | pub fn binbuf_addbinbuf(x: *mut _binbuf, y: *const _binbuf); 1230 | } 1231 | extern "C" { 1232 | pub fn binbuf_addsemi(x: *mut _binbuf); 1233 | } 1234 | extern "C" { 1235 | pub fn binbuf_restore(x: *mut _binbuf, argc: ::std::os::raw::c_int, argv: *const t_atom); 1236 | } 1237 | extern "C" { 1238 | pub fn binbuf_print(x: *const _binbuf); 1239 | } 1240 | extern "C" { 1241 | pub fn binbuf_getnatom(x: *const _binbuf) -> ::std::os::raw::c_int; 1242 | } 1243 | extern "C" { 1244 | pub fn binbuf_getvec(x: *const _binbuf) -> *mut t_atom; 1245 | } 1246 | extern "C" { 1247 | pub fn binbuf_resize(x: *mut _binbuf, newsize: ::std::os::raw::c_int) -> ::std::os::raw::c_int; 1248 | } 1249 | extern "C" { 1250 | pub fn binbuf_eval( 1251 | x: *const _binbuf, 1252 | target: *mut t_pd, 1253 | argc: ::std::os::raw::c_int, 1254 | argv: *const t_atom, 1255 | ); 1256 | } 1257 | extern "C" { 1258 | pub fn binbuf_read( 1259 | b: *mut _binbuf, 1260 | filename: *const ::std::os::raw::c_char, 1261 | dirname: *const ::std::os::raw::c_char, 1262 | crflag: ::std::os::raw::c_int, 1263 | ) -> ::std::os::raw::c_int; 1264 | } 1265 | extern "C" { 1266 | pub fn binbuf_read_via_canvas( 1267 | b: *mut _binbuf, 1268 | filename: *const ::std::os::raw::c_char, 1269 | canvas: *const _glist, 1270 | crflag: ::std::os::raw::c_int, 1271 | ) -> ::std::os::raw::c_int; 1272 | } 1273 | extern "C" { 1274 | pub fn binbuf_read_via_path( 1275 | b: *mut _binbuf, 1276 | filename: *const ::std::os::raw::c_char, 1277 | dirname: *const ::std::os::raw::c_char, 1278 | crflag: ::std::os::raw::c_int, 1279 | ) -> ::std::os::raw::c_int; 1280 | } 1281 | extern "C" { 1282 | pub fn binbuf_write( 1283 | x: *const _binbuf, 1284 | filename: *const ::std::os::raw::c_char, 1285 | dir: *const ::std::os::raw::c_char, 1286 | crflag: ::std::os::raw::c_int, 1287 | ) -> ::std::os::raw::c_int; 1288 | } 1289 | extern "C" { 1290 | pub fn binbuf_evalfile(name: *mut t_symbol, dir: *mut t_symbol); 1291 | } 1292 | extern "C" { 1293 | pub fn binbuf_realizedollsym( 1294 | s: *mut t_symbol, 1295 | ac: ::std::os::raw::c_int, 1296 | av: *const t_atom, 1297 | tonew: ::std::os::raw::c_int, 1298 | ) -> *mut t_symbol; 1299 | } 1300 | extern "C" { 1301 | pub fn clock_new(owner: *mut ::std::os::raw::c_void, fn_: t_method) -> *mut _clock; 1302 | } 1303 | extern "C" { 1304 | pub fn clock_set(x: *mut _clock, systime: f64); 1305 | } 1306 | extern "C" { 1307 | pub fn clock_delay(x: *mut _clock, delaytime: f64); 1308 | } 1309 | extern "C" { 1310 | pub fn clock_unset(x: *mut _clock); 1311 | } 1312 | extern "C" { 1313 | pub fn clock_setunit(x: *mut _clock, timeunit: f64, sampflag: ::std::os::raw::c_int); 1314 | } 1315 | extern "C" { 1316 | pub fn clock_getlogicaltime() -> f64; 1317 | } 1318 | extern "C" { 1319 | pub fn clock_getsystime() -> f64; 1320 | } 1321 | extern "C" { 1322 | pub fn clock_gettimesince(prevsystime: f64) -> f64; 1323 | } 1324 | extern "C" { 1325 | pub fn clock_gettimesincewithunits( 1326 | prevsystime: f64, 1327 | units: f64, 1328 | sampflag: ::std::os::raw::c_int, 1329 | ) -> f64; 1330 | } 1331 | extern "C" { 1332 | pub fn clock_getsystimeafter(delaytime: f64) -> f64; 1333 | } 1334 | extern "C" { 1335 | pub fn clock_free(x: *mut _clock); 1336 | } 1337 | extern "C" { 1338 | pub fn pd_new(cls: *mut _class) -> *mut t_pd; 1339 | } 1340 | extern "C" { 1341 | pub fn pd_free(x: *mut t_pd); 1342 | } 1343 | extern "C" { 1344 | pub fn pd_bind(x: *mut t_pd, s: *mut t_symbol); 1345 | } 1346 | extern "C" { 1347 | pub fn pd_unbind(x: *mut t_pd, s: *mut t_symbol); 1348 | } 1349 | extern "C" { 1350 | pub fn pd_findbyclass(s: *mut t_symbol, c: *const _class) -> *mut t_pd; 1351 | } 1352 | extern "C" { 1353 | pub fn pd_pushsym(x: *mut t_pd); 1354 | } 1355 | extern "C" { 1356 | pub fn pd_popsym(x: *mut t_pd); 1357 | } 1358 | extern "C" { 1359 | pub fn pd_bang(x: *mut t_pd); 1360 | } 1361 | extern "C" { 1362 | pub fn pd_pointer(x: *mut t_pd, gp: *mut t_gpointer); 1363 | } 1364 | extern "C" { 1365 | pub fn pd_float(x: *mut t_pd, f: t_float); 1366 | } 1367 | extern "C" { 1368 | pub fn pd_symbol(x: *mut t_pd, s: *mut t_symbol); 1369 | } 1370 | extern "C" { 1371 | pub fn pd_list(x: *mut t_pd, s: *mut t_symbol, argc: ::std::os::raw::c_int, argv: *mut t_atom); 1372 | } 1373 | extern "C" { 1374 | pub fn pd_anything( 1375 | x: *mut t_pd, 1376 | s: *mut t_symbol, 1377 | argc: ::std::os::raw::c_int, 1378 | argv: *mut t_atom, 1379 | ); 1380 | } 1381 | extern "C" { 1382 | pub fn gpointer_init(gp: *mut t_gpointer); 1383 | } 1384 | extern "C" { 1385 | pub fn gpointer_copy(gpfrom: *const t_gpointer, gpto: *mut t_gpointer); 1386 | } 1387 | extern "C" { 1388 | pub fn gpointer_unset(gp: *mut t_gpointer); 1389 | } 1390 | extern "C" { 1391 | pub fn gpointer_check( 1392 | gp: *const t_gpointer, 1393 | headok: ::std::os::raw::c_int, 1394 | ) -> ::std::os::raw::c_int; 1395 | } 1396 | extern "C" { 1397 | pub fn inlet_new( 1398 | owner: *mut t_object, 1399 | dest: *mut t_pd, 1400 | s1: *mut t_symbol, 1401 | s2: *mut t_symbol, 1402 | ) -> *mut _inlet; 1403 | } 1404 | extern "C" { 1405 | pub fn pointerinlet_new(owner: *mut t_object, gp: *mut t_gpointer) -> *mut _inlet; 1406 | } 1407 | extern "C" { 1408 | pub fn floatinlet_new(owner: *mut t_object, fp: *mut t_float) -> *mut _inlet; 1409 | } 1410 | extern "C" { 1411 | pub fn symbolinlet_new(owner: *mut t_object, sp: *mut *mut t_symbol) -> *mut _inlet; 1412 | } 1413 | extern "C" { 1414 | pub fn signalinlet_new(owner: *mut t_object, f: t_float) -> *mut _inlet; 1415 | } 1416 | extern "C" { 1417 | pub fn inlet_free(x: *mut _inlet); 1418 | } 1419 | extern "C" { 1420 | pub fn outlet_new(owner: *mut t_object, s: *mut t_symbol) -> *mut _outlet; 1421 | } 1422 | extern "C" { 1423 | pub fn outlet_bang(x: *mut _outlet); 1424 | } 1425 | extern "C" { 1426 | pub fn outlet_pointer(x: *mut _outlet, gp: *mut t_gpointer); 1427 | } 1428 | extern "C" { 1429 | pub fn outlet_float(x: *mut _outlet, f: t_float); 1430 | } 1431 | extern "C" { 1432 | pub fn outlet_symbol(x: *mut _outlet, s: *mut t_symbol); 1433 | } 1434 | extern "C" { 1435 | pub fn outlet_list( 1436 | x: *mut _outlet, 1437 | s: *mut t_symbol, 1438 | argc: ::std::os::raw::c_int, 1439 | argv: *mut t_atom, 1440 | ); 1441 | } 1442 | extern "C" { 1443 | pub fn outlet_anything( 1444 | x: *mut _outlet, 1445 | s: *mut t_symbol, 1446 | argc: ::std::os::raw::c_int, 1447 | argv: *mut t_atom, 1448 | ); 1449 | } 1450 | extern "C" { 1451 | pub fn outlet_getsymbol(x: *mut _outlet) -> *mut t_symbol; 1452 | } 1453 | extern "C" { 1454 | pub fn outlet_free(x: *mut _outlet); 1455 | } 1456 | extern "C" { 1457 | pub fn pd_checkobject(x: *mut t_pd) -> *mut t_object; 1458 | } 1459 | extern "C" { 1460 | pub fn glob_setfilename( 1461 | dummy: *mut ::std::os::raw::c_void, 1462 | name: *mut t_symbol, 1463 | dir: *mut t_symbol, 1464 | ); 1465 | } 1466 | extern "C" { 1467 | pub fn canvas_setargs(argc: ::std::os::raw::c_int, argv: *const t_atom); 1468 | } 1469 | extern "C" { 1470 | pub fn canvas_getargs(argcp: *mut ::std::os::raw::c_int, argvp: *mut *mut t_atom); 1471 | } 1472 | extern "C" { 1473 | pub fn canvas_getcurrentdir() -> *mut t_symbol; 1474 | } 1475 | extern "C" { 1476 | pub fn canvas_getcurrent() -> *mut _glist; 1477 | } 1478 | extern "C" { 1479 | pub fn canvas_makefilename( 1480 | c: *const _glist, 1481 | file: *const ::std::os::raw::c_char, 1482 | result: *mut ::std::os::raw::c_char, 1483 | resultsize: ::std::os::raw::c_int, 1484 | ); 1485 | } 1486 | extern "C" { 1487 | pub fn canvas_getdir(x: *const _glist) -> *mut t_symbol; 1488 | } 1489 | extern "C" { 1490 | pub fn sys_hostfontsize( 1491 | fontsize: ::std::os::raw::c_int, 1492 | zoom: ::std::os::raw::c_int, 1493 | ) -> ::std::os::raw::c_int; 1494 | } 1495 | extern "C" { 1496 | pub fn sys_zoomfontwidth( 1497 | fontsize: ::std::os::raw::c_int, 1498 | zoom: ::std::os::raw::c_int, 1499 | worstcase: ::std::os::raw::c_int, 1500 | ) -> ::std::os::raw::c_int; 1501 | } 1502 | extern "C" { 1503 | pub fn sys_zoomfontheight( 1504 | fontsize: ::std::os::raw::c_int, 1505 | zoom: ::std::os::raw::c_int, 1506 | worstcase: ::std::os::raw::c_int, 1507 | ) -> ::std::os::raw::c_int; 1508 | } 1509 | extern "C" { 1510 | pub fn sys_fontwidth(fontsize: ::std::os::raw::c_int) -> ::std::os::raw::c_int; 1511 | } 1512 | extern "C" { 1513 | pub fn sys_fontheight(fontsize: ::std::os::raw::c_int) -> ::std::os::raw::c_int; 1514 | } 1515 | extern "C" { 1516 | pub fn canvas_dataproperties(x: *mut _glist, sc: *mut t_scalar, b: *mut _binbuf); 1517 | } 1518 | extern "C" { 1519 | pub fn canvas_open( 1520 | x: *const _glist, 1521 | name: *const ::std::os::raw::c_char, 1522 | ext: *const ::std::os::raw::c_char, 1523 | dirresult: *mut ::std::os::raw::c_char, 1524 | nameresult: *mut *mut ::std::os::raw::c_char, 1525 | size: ::std::os::raw::c_uint, 1526 | bin: ::std::os::raw::c_int, 1527 | ) -> ::std::os::raw::c_int; 1528 | } 1529 | #[repr(C)] 1530 | #[derive(Debug, Copy, Clone)] 1531 | pub struct _widgetbehavior { 1532 | _unused: [u8; 0], 1533 | } 1534 | #[repr(C)] 1535 | #[derive(Debug, Copy, Clone)] 1536 | pub struct _parentwidgetbehavior { 1537 | _unused: [u8; 0], 1538 | } 1539 | extern "C" { 1540 | pub fn pd_getparentwidget(x: *mut t_pd) -> *const _parentwidgetbehavior; 1541 | } 1542 | extern "C" { 1543 | pub fn class_new( 1544 | name: *mut t_symbol, 1545 | newmethod: t_newmethod, 1546 | freemethod: t_method, 1547 | size: usize, 1548 | flags: ::std::os::raw::c_int, 1549 | arg1: t_atomtype::Type, 1550 | ... 1551 | ) -> *mut _class; 1552 | } 1553 | extern "C" { 1554 | pub fn class_new64( 1555 | name: *mut t_symbol, 1556 | newmethod: t_newmethod, 1557 | freemethod: t_method, 1558 | size: usize, 1559 | flags: ::std::os::raw::c_int, 1560 | arg1: t_atomtype::Type, 1561 | ... 1562 | ) -> *mut _class; 1563 | } 1564 | extern "C" { 1565 | pub fn class_addcreator(newmethod: t_newmethod, s: *mut t_symbol, type1: t_atomtype::Type, ...); 1566 | } 1567 | extern "C" { 1568 | pub fn class_addmethod( 1569 | c: *mut _class, 1570 | fn_: t_method, 1571 | sel: *mut t_symbol, 1572 | arg1: t_atomtype::Type, 1573 | ... 1574 | ); 1575 | } 1576 | extern "C" { 1577 | pub fn class_addbang(c: *mut _class, fn_: t_method); 1578 | } 1579 | extern "C" { 1580 | pub fn class_addpointer(c: *mut _class, fn_: t_method); 1581 | } 1582 | extern "C" { 1583 | pub fn class_doaddfloat(c: *mut _class, fn_: t_method); 1584 | } 1585 | extern "C" { 1586 | pub fn class_addsymbol(c: *mut _class, fn_: t_method); 1587 | } 1588 | extern "C" { 1589 | pub fn class_addlist(c: *mut _class, fn_: t_method); 1590 | } 1591 | extern "C" { 1592 | pub fn class_addanything(c: *mut _class, fn_: t_method); 1593 | } 1594 | extern "C" { 1595 | pub fn class_sethelpsymbol(c: *mut _class, s: *mut t_symbol); 1596 | } 1597 | extern "C" { 1598 | pub fn class_setwidget(c: *mut _class, w: *const _widgetbehavior); 1599 | } 1600 | extern "C" { 1601 | pub fn class_setparentwidget(c: *mut _class, w: *const _parentwidgetbehavior); 1602 | } 1603 | extern "C" { 1604 | pub fn class_getname(c: *const _class) -> *const ::std::os::raw::c_char; 1605 | } 1606 | extern "C" { 1607 | pub fn class_gethelpname(c: *const _class) -> *const ::std::os::raw::c_char; 1608 | } 1609 | extern "C" { 1610 | pub fn class_gethelpdir(c: *const _class) -> *const ::std::os::raw::c_char; 1611 | } 1612 | extern "C" { 1613 | pub fn class_setdrawcommand(c: *mut _class); 1614 | } 1615 | extern "C" { 1616 | pub fn class_isdrawcommand(c: *const _class) -> ::std::os::raw::c_int; 1617 | } 1618 | extern "C" { 1619 | pub fn class_domainsignalin(c: *mut _class, onset: ::std::os::raw::c_int); 1620 | } 1621 | extern "C" { 1622 | pub fn class_set_extern_dir(s: *mut t_symbol); 1623 | } 1624 | pub type t_savefn = ::std::option::Option; 1625 | extern "C" { 1626 | pub fn class_setsavefn(c: *mut _class, f: t_savefn); 1627 | } 1628 | extern "C" { 1629 | pub fn class_getsavefn(c: *const _class) -> t_savefn; 1630 | } 1631 | extern "C" { 1632 | pub fn obj_saveformat(x: *const t_object, bb: *mut _binbuf); 1633 | } 1634 | pub type t_propertiesfn = 1635 | ::std::option::Option; 1636 | extern "C" { 1637 | pub fn class_setpropertiesfn(c: *mut _class, f: t_propertiesfn); 1638 | } 1639 | extern "C" { 1640 | pub fn class_getpropertiesfn(c: *const _class) -> t_propertiesfn; 1641 | } 1642 | extern "C" { 1643 | pub fn post(fmt: *const ::std::os::raw::c_char, ...); 1644 | } 1645 | extern "C" { 1646 | pub fn startpost(fmt: *const ::std::os::raw::c_char, ...); 1647 | } 1648 | extern "C" { 1649 | pub fn poststring(s: *const ::std::os::raw::c_char); 1650 | } 1651 | extern "C" { 1652 | pub fn postfloat(f: t_floatarg); 1653 | } 1654 | extern "C" { 1655 | pub fn postatom(argc: ::std::os::raw::c_int, argv: *const t_atom); 1656 | } 1657 | extern "C" { 1658 | pub fn endpost(); 1659 | } 1660 | extern "C" { 1661 | pub fn error(fmt: *const ::std::os::raw::c_char, ...); 1662 | } 1663 | extern "C" { 1664 | pub fn verbose(level: ::std::os::raw::c_int, fmt: *const ::std::os::raw::c_char, ...); 1665 | } 1666 | extern "C" { 1667 | pub fn bug(fmt: *const ::std::os::raw::c_char, ...); 1668 | } 1669 | extern "C" { 1670 | pub fn pd_error(object: *const ::std::os::raw::c_void, fmt: *const ::std::os::raw::c_char, ...); 1671 | } 1672 | extern "C" { 1673 | pub fn logpost( 1674 | object: *const ::std::os::raw::c_void, 1675 | level: ::std::os::raw::c_int, 1676 | fmt: *const ::std::os::raw::c_char, 1677 | ... 1678 | ); 1679 | } 1680 | extern "C" { 1681 | pub fn sys_logerror(object: *const ::std::os::raw::c_char, s: *const ::std::os::raw::c_char); 1682 | } 1683 | extern "C" { 1684 | pub fn sys_unixerror(object: *const ::std::os::raw::c_char); 1685 | } 1686 | extern "C" { 1687 | pub fn sys_ouch(); 1688 | } 1689 | extern "C" { 1690 | pub fn sys_isabsolutepath(dir: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; 1691 | } 1692 | extern "C" { 1693 | pub fn sys_bashfilename(from: *const ::std::os::raw::c_char, to: *mut ::std::os::raw::c_char); 1694 | } 1695 | extern "C" { 1696 | pub fn sys_unbashfilename(from: *const ::std::os::raw::c_char, to: *mut ::std::os::raw::c_char); 1697 | } 1698 | extern "C" { 1699 | pub fn sys_getrealtime() -> f64; 1700 | } 1701 | extern "C" { 1702 | pub fn sys_open( 1703 | path: *const ::std::os::raw::c_char, 1704 | oflag: ::std::os::raw::c_int, 1705 | ... 1706 | ) -> ::std::os::raw::c_int; 1707 | } 1708 | extern "C" { 1709 | pub fn sys_close(fd: ::std::os::raw::c_int) -> ::std::os::raw::c_int; 1710 | } 1711 | extern "C" { 1712 | pub fn sys_fopen( 1713 | filename: *const ::std::os::raw::c_char, 1714 | mode: *const ::std::os::raw::c_char, 1715 | ) -> *mut FILE; 1716 | } 1717 | extern "C" { 1718 | pub fn sys_fclose(stream: *mut FILE) -> ::std::os::raw::c_int; 1719 | } 1720 | extern "C" { 1721 | pub fn sys_lock(); 1722 | } 1723 | extern "C" { 1724 | pub fn sys_unlock(); 1725 | } 1726 | extern "C" { 1727 | pub fn sys_trylock() -> ::std::os::raw::c_int; 1728 | } 1729 | pub type t_sample = f32; 1730 | #[repr(C)] 1731 | #[derive(Debug, Copy, Clone)] 1732 | pub struct _signal { 1733 | pub s_n: ::std::os::raw::c_int, 1734 | pub s_vec: *mut t_sample, 1735 | pub s_sr: t_float, 1736 | pub s_refcount: ::std::os::raw::c_int, 1737 | pub s_isborrowed: ::std::os::raw::c_int, 1738 | pub s_borrowedfrom: *mut _signal, 1739 | pub s_nextfree: *mut _signal, 1740 | pub s_nextused: *mut _signal, 1741 | pub s_vecsize: ::std::os::raw::c_int, 1742 | } 1743 | #[test] 1744 | fn bindgen_test_layout__signal() { 1745 | assert_eq!( 1746 | ::std::mem::size_of::<_signal>(), 1747 | 64usize, 1748 | concat!("Size of: ", stringify!(_signal)) 1749 | ); 1750 | assert_eq!( 1751 | ::std::mem::align_of::<_signal>(), 1752 | 8usize, 1753 | concat!("Alignment of ", stringify!(_signal)) 1754 | ); 1755 | assert_eq!( 1756 | unsafe { &(*(::std::ptr::null::<_signal>())).s_n as *const _ as usize }, 1757 | 0usize, 1758 | concat!( 1759 | "Offset of field: ", 1760 | stringify!(_signal), 1761 | "::", 1762 | stringify!(s_n) 1763 | ) 1764 | ); 1765 | assert_eq!( 1766 | unsafe { &(*(::std::ptr::null::<_signal>())).s_vec as *const _ as usize }, 1767 | 8usize, 1768 | concat!( 1769 | "Offset of field: ", 1770 | stringify!(_signal), 1771 | "::", 1772 | stringify!(s_vec) 1773 | ) 1774 | ); 1775 | assert_eq!( 1776 | unsafe { &(*(::std::ptr::null::<_signal>())).s_sr as *const _ as usize }, 1777 | 16usize, 1778 | concat!( 1779 | "Offset of field: ", 1780 | stringify!(_signal), 1781 | "::", 1782 | stringify!(s_sr) 1783 | ) 1784 | ); 1785 | assert_eq!( 1786 | unsafe { &(*(::std::ptr::null::<_signal>())).s_refcount as *const _ as usize }, 1787 | 20usize, 1788 | concat!( 1789 | "Offset of field: ", 1790 | stringify!(_signal), 1791 | "::", 1792 | stringify!(s_refcount) 1793 | ) 1794 | ); 1795 | assert_eq!( 1796 | unsafe { &(*(::std::ptr::null::<_signal>())).s_isborrowed as *const _ as usize }, 1797 | 24usize, 1798 | concat!( 1799 | "Offset of field: ", 1800 | stringify!(_signal), 1801 | "::", 1802 | stringify!(s_isborrowed) 1803 | ) 1804 | ); 1805 | assert_eq!( 1806 | unsafe { &(*(::std::ptr::null::<_signal>())).s_borrowedfrom as *const _ as usize }, 1807 | 32usize, 1808 | concat!( 1809 | "Offset of field: ", 1810 | stringify!(_signal), 1811 | "::", 1812 | stringify!(s_borrowedfrom) 1813 | ) 1814 | ); 1815 | assert_eq!( 1816 | unsafe { &(*(::std::ptr::null::<_signal>())).s_nextfree as *const _ as usize }, 1817 | 40usize, 1818 | concat!( 1819 | "Offset of field: ", 1820 | stringify!(_signal), 1821 | "::", 1822 | stringify!(s_nextfree) 1823 | ) 1824 | ); 1825 | assert_eq!( 1826 | unsafe { &(*(::std::ptr::null::<_signal>())).s_nextused as *const _ as usize }, 1827 | 48usize, 1828 | concat!( 1829 | "Offset of field: ", 1830 | stringify!(_signal), 1831 | "::", 1832 | stringify!(s_nextused) 1833 | ) 1834 | ); 1835 | assert_eq!( 1836 | unsafe { &(*(::std::ptr::null::<_signal>())).s_vecsize as *const _ as usize }, 1837 | 56usize, 1838 | concat!( 1839 | "Offset of field: ", 1840 | stringify!(_signal), 1841 | "::", 1842 | stringify!(s_vecsize) 1843 | ) 1844 | ); 1845 | } 1846 | pub type t_signal = _signal; 1847 | pub type t_perfroutine = 1848 | ::std::option::Option *mut t_int>; 1849 | extern "C" { 1850 | pub fn plus_perform(args: *mut t_int) -> *mut t_int; 1851 | } 1852 | extern "C" { 1853 | pub fn zero_perform(args: *mut t_int) -> *mut t_int; 1854 | } 1855 | extern "C" { 1856 | pub fn copy_perform(args: *mut t_int) -> *mut t_int; 1857 | } 1858 | extern "C" { 1859 | pub fn dsp_add_plus( 1860 | in1: *mut t_sample, 1861 | in2: *mut t_sample, 1862 | out: *mut t_sample, 1863 | n: ::std::os::raw::c_int, 1864 | ); 1865 | } 1866 | extern "C" { 1867 | pub fn dsp_add_copy(in_: *mut t_sample, out: *mut t_sample, n: ::std::os::raw::c_int); 1868 | } 1869 | extern "C" { 1870 | pub fn dsp_add_scalarcopy(in_: *mut t_float, out: *mut t_sample, n: ::std::os::raw::c_int); 1871 | } 1872 | extern "C" { 1873 | pub fn dsp_add_zero(out: *mut t_sample, n: ::std::os::raw::c_int); 1874 | } 1875 | extern "C" { 1876 | pub fn sys_getblksize() -> ::std::os::raw::c_int; 1877 | } 1878 | extern "C" { 1879 | pub fn sys_getsr() -> t_float; 1880 | } 1881 | extern "C" { 1882 | pub fn sys_get_inchannels() -> ::std::os::raw::c_int; 1883 | } 1884 | extern "C" { 1885 | pub fn sys_get_outchannels() -> ::std::os::raw::c_int; 1886 | } 1887 | extern "C" { 1888 | pub fn dsp_add(f: t_perfroutine, n: ::std::os::raw::c_int, ...); 1889 | } 1890 | extern "C" { 1891 | pub fn dsp_addv(f: t_perfroutine, n: ::std::os::raw::c_int, vec: *mut t_int); 1892 | } 1893 | extern "C" { 1894 | pub fn pd_fft( 1895 | buf: *mut t_float, 1896 | npoints: ::std::os::raw::c_int, 1897 | inverse: ::std::os::raw::c_int, 1898 | ); 1899 | } 1900 | extern "C" { 1901 | pub fn ilog2(n: ::std::os::raw::c_int) -> ::std::os::raw::c_int; 1902 | } 1903 | extern "C" { 1904 | pub fn mayer_fht(fz: *mut t_sample, n: ::std::os::raw::c_int); 1905 | } 1906 | extern "C" { 1907 | pub fn mayer_fft(n: ::std::os::raw::c_int, real: *mut t_sample, imag: *mut t_sample); 1908 | } 1909 | extern "C" { 1910 | pub fn mayer_ifft(n: ::std::os::raw::c_int, real: *mut t_sample, imag: *mut t_sample); 1911 | } 1912 | extern "C" { 1913 | pub fn mayer_realfft(n: ::std::os::raw::c_int, real: *mut t_sample); 1914 | } 1915 | extern "C" { 1916 | pub fn mayer_realifft(n: ::std::os::raw::c_int, real: *mut t_sample); 1917 | } 1918 | extern "C" { 1919 | pub fn canvas_suspend_dsp() -> ::std::os::raw::c_int; 1920 | } 1921 | extern "C" { 1922 | pub fn canvas_resume_dsp(oldstate: ::std::os::raw::c_int); 1923 | } 1924 | extern "C" { 1925 | pub fn canvas_update_dsp(); 1926 | } 1927 | #[repr(C)] 1928 | #[derive(Debug, Copy, Clone)] 1929 | pub struct _resample { 1930 | pub method: ::std::os::raw::c_int, 1931 | pub downsample: ::std::os::raw::c_int, 1932 | pub upsample: ::std::os::raw::c_int, 1933 | pub s_vec: *mut t_sample, 1934 | pub s_n: ::std::os::raw::c_int, 1935 | pub coeffs: *mut t_sample, 1936 | pub coefsize: ::std::os::raw::c_int, 1937 | pub buffer: *mut t_sample, 1938 | pub bufsize: ::std::os::raw::c_int, 1939 | } 1940 | #[test] 1941 | fn bindgen_test_layout__resample() { 1942 | assert_eq!( 1943 | ::std::mem::size_of::<_resample>(), 1944 | 64usize, 1945 | concat!("Size of: ", stringify!(_resample)) 1946 | ); 1947 | assert_eq!( 1948 | ::std::mem::align_of::<_resample>(), 1949 | 8usize, 1950 | concat!("Alignment of ", stringify!(_resample)) 1951 | ); 1952 | assert_eq!( 1953 | unsafe { &(*(::std::ptr::null::<_resample>())).method as *const _ as usize }, 1954 | 0usize, 1955 | concat!( 1956 | "Offset of field: ", 1957 | stringify!(_resample), 1958 | "::", 1959 | stringify!(method) 1960 | ) 1961 | ); 1962 | assert_eq!( 1963 | unsafe { &(*(::std::ptr::null::<_resample>())).downsample as *const _ as usize }, 1964 | 4usize, 1965 | concat!( 1966 | "Offset of field: ", 1967 | stringify!(_resample), 1968 | "::", 1969 | stringify!(downsample) 1970 | ) 1971 | ); 1972 | assert_eq!( 1973 | unsafe { &(*(::std::ptr::null::<_resample>())).upsample as *const _ as usize }, 1974 | 8usize, 1975 | concat!( 1976 | "Offset of field: ", 1977 | stringify!(_resample), 1978 | "::", 1979 | stringify!(upsample) 1980 | ) 1981 | ); 1982 | assert_eq!( 1983 | unsafe { &(*(::std::ptr::null::<_resample>())).s_vec as *const _ as usize }, 1984 | 16usize, 1985 | concat!( 1986 | "Offset of field: ", 1987 | stringify!(_resample), 1988 | "::", 1989 | stringify!(s_vec) 1990 | ) 1991 | ); 1992 | assert_eq!( 1993 | unsafe { &(*(::std::ptr::null::<_resample>())).s_n as *const _ as usize }, 1994 | 24usize, 1995 | concat!( 1996 | "Offset of field: ", 1997 | stringify!(_resample), 1998 | "::", 1999 | stringify!(s_n) 2000 | ) 2001 | ); 2002 | assert_eq!( 2003 | unsafe { &(*(::std::ptr::null::<_resample>())).coeffs as *const _ as usize }, 2004 | 32usize, 2005 | concat!( 2006 | "Offset of field: ", 2007 | stringify!(_resample), 2008 | "::", 2009 | stringify!(coeffs) 2010 | ) 2011 | ); 2012 | assert_eq!( 2013 | unsafe { &(*(::std::ptr::null::<_resample>())).coefsize as *const _ as usize }, 2014 | 40usize, 2015 | concat!( 2016 | "Offset of field: ", 2017 | stringify!(_resample), 2018 | "::", 2019 | stringify!(coefsize) 2020 | ) 2021 | ); 2022 | assert_eq!( 2023 | unsafe { &(*(::std::ptr::null::<_resample>())).buffer as *const _ as usize }, 2024 | 48usize, 2025 | concat!( 2026 | "Offset of field: ", 2027 | stringify!(_resample), 2028 | "::", 2029 | stringify!(buffer) 2030 | ) 2031 | ); 2032 | assert_eq!( 2033 | unsafe { &(*(::std::ptr::null::<_resample>())).bufsize as *const _ as usize }, 2034 | 56usize, 2035 | concat!( 2036 | "Offset of field: ", 2037 | stringify!(_resample), 2038 | "::", 2039 | stringify!(bufsize) 2040 | ) 2041 | ); 2042 | } 2043 | pub type t_resample = _resample; 2044 | extern "C" { 2045 | pub fn resample_init(x: *mut t_resample); 2046 | } 2047 | extern "C" { 2048 | pub fn resample_free(x: *mut t_resample); 2049 | } 2050 | extern "C" { 2051 | pub fn resample_dsp( 2052 | x: *mut t_resample, 2053 | in_: *mut t_sample, 2054 | insize: ::std::os::raw::c_int, 2055 | out: *mut t_sample, 2056 | outsize: ::std::os::raw::c_int, 2057 | method: ::std::os::raw::c_int, 2058 | ); 2059 | } 2060 | extern "C" { 2061 | pub fn resamplefrom_dsp( 2062 | x: *mut t_resample, 2063 | in_: *mut t_sample, 2064 | insize: ::std::os::raw::c_int, 2065 | outsize: ::std::os::raw::c_int, 2066 | method: ::std::os::raw::c_int, 2067 | ); 2068 | } 2069 | extern "C" { 2070 | pub fn resampleto_dsp( 2071 | x: *mut t_resample, 2072 | out: *mut t_sample, 2073 | insize: ::std::os::raw::c_int, 2074 | outsize: ::std::os::raw::c_int, 2075 | method: ::std::os::raw::c_int, 2076 | ); 2077 | } 2078 | #[repr(C)] 2079 | #[derive(Debug, Copy, Clone)] 2080 | pub struct _garray { 2081 | _unused: [u8; 0], 2082 | } 2083 | extern "C" { 2084 | pub fn garray_getfloatarray( 2085 | x: *mut _garray, 2086 | size: *mut ::std::os::raw::c_int, 2087 | vec: *mut *mut t_float, 2088 | ) -> ::std::os::raw::c_int; 2089 | } 2090 | extern "C" { 2091 | pub fn garray_getfloatwords( 2092 | x: *mut _garray, 2093 | size: *mut ::std::os::raw::c_int, 2094 | vec: *mut *mut t_word, 2095 | ) -> ::std::os::raw::c_int; 2096 | } 2097 | extern "C" { 2098 | pub fn garray_redraw(x: *mut _garray); 2099 | } 2100 | extern "C" { 2101 | pub fn garray_npoints(x: *mut _garray) -> ::std::os::raw::c_int; 2102 | } 2103 | extern "C" { 2104 | pub fn garray_vec(x: *mut _garray) -> *mut ::std::os::raw::c_char; 2105 | } 2106 | extern "C" { 2107 | pub fn garray_resize(x: *mut _garray, f: t_floatarg); 2108 | } 2109 | extern "C" { 2110 | pub fn garray_resize_long(x: *mut _garray, n: ::std::os::raw::c_long); 2111 | } 2112 | extern "C" { 2113 | pub fn garray_usedindsp(x: *mut _garray); 2114 | } 2115 | extern "C" { 2116 | pub fn garray_setsaveit(x: *mut _garray, saveit: ::std::os::raw::c_int); 2117 | } 2118 | extern "C" { 2119 | pub fn garray_getglist(x: *mut _garray) -> *mut _glist; 2120 | } 2121 | extern "C" { 2122 | pub fn garray_getarray(x: *mut _garray) -> *mut _array; 2123 | } 2124 | extern "C" { 2125 | pub fn value_get(s: *mut t_symbol) -> *mut t_float; 2126 | } 2127 | extern "C" { 2128 | pub fn value_release(s: *mut t_symbol); 2129 | } 2130 | extern "C" { 2131 | pub fn value_getfloat(s: *mut t_symbol, f: *mut t_float) -> ::std::os::raw::c_int; 2132 | } 2133 | extern "C" { 2134 | pub fn value_setfloat(s: *mut t_symbol, f: t_float) -> ::std::os::raw::c_int; 2135 | } 2136 | pub type t_guicallbackfn = 2137 | ::std::option::Option; 2138 | extern "C" { 2139 | pub fn sys_vgui(fmt: *mut ::std::os::raw::c_char, ...); 2140 | } 2141 | extern "C" { 2142 | pub fn sys_gui(s: *mut ::std::os::raw::c_char); 2143 | } 2144 | extern "C" { 2145 | pub fn sys_pretendguibytes(n: ::std::os::raw::c_int); 2146 | } 2147 | extern "C" { 2148 | pub fn sys_queuegui( 2149 | client: *mut ::std::os::raw::c_void, 2150 | glist: *mut _glist, 2151 | f: t_guicallbackfn, 2152 | ); 2153 | } 2154 | extern "C" { 2155 | pub fn sys_unqueuegui(client: *mut ::std::os::raw::c_void); 2156 | } 2157 | extern "C" { 2158 | pub fn sys_getversion( 2159 | major: *mut ::std::os::raw::c_int, 2160 | minor: *mut ::std::os::raw::c_int, 2161 | bugfix: *mut ::std::os::raw::c_int, 2162 | ); 2163 | } 2164 | extern "C" { 2165 | pub static mut s_pointer: t_symbol; 2166 | } 2167 | extern "C" { 2168 | pub static mut s_float: t_symbol; 2169 | } 2170 | extern "C" { 2171 | pub static mut s_symbol: t_symbol; 2172 | } 2173 | extern "C" { 2174 | pub static mut s_bang: t_symbol; 2175 | } 2176 | extern "C" { 2177 | pub static mut s_list: t_symbol; 2178 | } 2179 | extern "C" { 2180 | pub static mut s_anything: t_symbol; 2181 | } 2182 | extern "C" { 2183 | pub static mut s_signal: t_symbol; 2184 | } 2185 | extern "C" { 2186 | pub static mut s__N: t_symbol; 2187 | } 2188 | extern "C" { 2189 | pub static mut s__X: t_symbol; 2190 | } 2191 | extern "C" { 2192 | pub static mut s_x: t_symbol; 2193 | } 2194 | extern "C" { 2195 | pub static mut s_y: t_symbol; 2196 | } 2197 | extern "C" { 2198 | pub static mut s_: t_symbol; 2199 | } 2200 | extern "C" { 2201 | pub fn pd_getcanvaslist() -> *mut _glist; 2202 | } 2203 | extern "C" { 2204 | pub fn pd_getdspstate() -> ::std::os::raw::c_int; 2205 | } 2206 | --------------------------------------------------------------------------------