use crate::{
error::SubscriptionError,
helpers::make_atom_list_from_t_atom_list,
types::{Atom, ReceiverHandle},
C_STRING_FAILURE, C_STR_FAILURE,
};
use libffi::high::{ClosureMut1, ClosureMut2, ClosureMut3, ClosureMut4};
use std::ffi::{CStr, CString};
pub fn start_listening_from<T: AsRef<str>>(sender: T) -> Result<ReceiverHandle, SubscriptionError> {
let send = CString::new(sender.as_ref()).expect(C_STRING_FAILURE);
unsafe {
let handle = libpd_sys::libpd_bind(send.as_ptr());
if handle.is_null() {
Err(SubscriptionError::FailedToSubscribeToSender(
sender.as_ref().to_owned(),
))
} else {
Ok(ReceiverHandle::from(handle))
}
}
}
pub fn stop_listening_from(source: ReceiverHandle) {
let handle: *mut std::ffi::c_void = source.into();
if handle.is_null() {
return;
}
unsafe {
libpd_sys::libpd_unbind(handle);
}
}
pub fn source_to_listen_from_exists<T: AsRef<str>>(sender: T) -> bool {
let send = CString::new(sender.as_ref()).expect(C_STRING_FAILURE);
unsafe { matches!(libpd_sys::libpd_exists(send.as_ptr()), 1) }
}
pub fn on_print<F: FnMut(&str) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ = Box::leak(Box::new(move |out: *const std::os::raw::c_char| {
let out = unsafe { CStr::from_ptr(out).to_str().expect(C_STR_FAILURE) };
user_provided_closure(out);
}));
let callback = ClosureMut1::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr1<*const i8, ()>)
.cast::<unsafe extern "C" fn(*const i8)>()
};
std::mem::forget(callback);
unsafe {
libpd_sys::libpd_set_queued_printhook(Some(libpd_sys::libpd_print_concatenator));
libpd_sys::libpd_set_concatenated_printhook(Some(*ptr));
};
}
pub fn on_bang<F: FnMut(&str) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ =
Box::leak(Box::new(move |source: *const std::os::raw::c_char| {
let source = unsafe { CStr::from_ptr(source).to_str().expect(C_STR_FAILURE) };
user_provided_closure(source);
}));
let callback = ClosureMut1::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr1<*const i8, ()>)
.cast::<unsafe extern "C" fn(*const i8)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_banghook(Some(*ptr)) };
}
pub fn on_float<F: FnMut(&str, f32) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ = Box::leak(Box::new(
move |source: *const std::os::raw::c_char, float: f32| {
let source = unsafe { CStr::from_ptr(source).to_str().expect(C_STR_FAILURE) };
user_provided_closure(source, float);
},
));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<*const i8, f32, ()>)
.cast::<unsafe extern "C" fn(*const i8, f32)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_floathook(Some(*ptr)) };
}
pub fn on_double<F: FnMut(&str, f64) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ = Box::leak(Box::new(
move |source: *const std::os::raw::c_char, double: f64| {
let source = unsafe { CStr::from_ptr(source).to_str().expect(C_STR_FAILURE) };
user_provided_closure(source, double);
},
));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<*const i8, f64, ()>)
.cast::<unsafe extern "C" fn(*const i8, f64)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_doublehook(Some(*ptr)) };
}
pub fn on_symbol<F: FnMut(&str, &str) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ = Box::leak(Box::new(
move |source: *const std::os::raw::c_char, symbol: *const std::os::raw::c_char| {
let source = unsafe { CStr::from_ptr(source).to_str().expect(C_STR_FAILURE) };
let symbol = unsafe { CStr::from_ptr(symbol).to_str().expect(C_STR_FAILURE) };
user_provided_closure(source, symbol);
},
));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<*const i8, *const i8, ()>)
.cast::<unsafe extern "C" fn(*const i8, *const i8)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_symbolhook(Some(*ptr)) };
}
pub fn on_list<F: FnMut(&str, &[Atom]) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ = Box::leak(Box::new(
move |source: *const std::os::raw::c_char,
list_length: i32,
atom_list: *mut libpd_sys::t_atom| {
let source = unsafe { CStr::from_ptr(source).to_str().expect(C_STR_FAILURE) };
#[allow(clippy::cast_sign_loss)]
let atom_list = unsafe { std::slice::from_raw_parts(atom_list, list_length as usize) };
let atoms = make_atom_list_from_t_atom_list!(atom_list);
user_provided_closure(source, &atoms);
},
));
let callback = ClosureMut3::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr3<*const i8, i32, *mut libpd_sys::_atom, ()>)
.cast::<unsafe extern "C" fn(*const i8, i32, *mut libpd_sys::_atom)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_listhook(Some(*ptr)) };
}
pub fn on_message<F: FnMut(&str, &str, &[Atom]) + Send + Sync + 'static>(
mut user_provided_closure: F,
) {
let closure: &'static mut _ = Box::leak(Box::new(
move |source: *const std::os::raw::c_char,
message: *const std::os::raw::c_char,
list_length: i32,
atom_list: *mut libpd_sys::t_atom| {
let source = unsafe { CStr::from_ptr(source).to_str().expect(C_STR_FAILURE) };
let message = unsafe { CStr::from_ptr(message).to_str().expect(C_STR_FAILURE) };
#[allow(clippy::cast_sign_loss)]
let atom_list = unsafe { std::slice::from_raw_parts(atom_list, list_length as usize) };
let atoms = make_atom_list_from_t_atom_list!(atom_list);
user_provided_closure(source, message, &atoms);
},
));
let callback = ClosureMut4::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr4<
*const i8,
*const i8,
i32,
*mut libpd_sys::_atom,
(),
>)
.cast::<unsafe extern "C" fn(*const i8, *const i8, i32, *mut libpd_sys::_atom)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_messagehook(Some(*ptr)) };
}
pub fn receive_messages_from_pd() {
unsafe { libpd_sys::libpd_queued_receive_pd_messages() };
}
pub fn on_midi_note_on<F: FnMut(i32, i32, i32) + Send + Sync + 'static>(
mut user_provided_closure: F,
) {
let closure: &'static mut _ =
Box::leak(Box::new(move |channel: i32, pitch: i32, velocity: i32| {
user_provided_closure(channel, pitch, velocity);
}));
let callback = ClosureMut3::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr3<i32, i32, i32, ()>).cast::<unsafe extern "C" fn(
i32,
i32,
i32,
)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_noteonhook(Some(*ptr)) };
}
pub fn on_midi_control_change<F: FnMut(i32, i32, i32) + Send + Sync + 'static>(
mut user_provided_closure: F,
) {
let closure: &'static mut _ = Box::leak(Box::new(
move |channel: i32, controller: i32, value: i32| {
user_provided_closure(channel, controller, value);
},
));
let callback = ClosureMut3::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr3<i32, i32, i32, ()>).cast::<unsafe extern "C" fn(
i32,
i32,
i32,
)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_controlchangehook(Some(*ptr)) };
}
pub fn on_midi_program_change<F: FnMut(i32, i32) + Send + Sync + 'static>(
mut user_provided_closure: F,
) {
let closure: &'static mut _ = Box::leak(Box::new(move |channel: i32, value: i32| {
user_provided_closure(channel, value);
}));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<i32, i32, ()>)
.cast::<unsafe extern "C" fn(i32, i32)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_programchangehook(Some(*ptr)) };
}
pub fn on_midi_pitch_bend<F: FnMut(i32, i32) + Send + Sync + 'static>(
mut user_provided_closure: F,
) {
let closure: &'static mut _ = Box::leak(Box::new(move |channel: i32, value: i32| {
user_provided_closure(channel, value);
}));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<i32, i32, ()>)
.cast::<unsafe extern "C" fn(i32, i32)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_pitchbendhook(Some(*ptr)) };
}
pub fn on_midi_after_touch<F: FnMut(i32, i32) + Send + Sync + 'static>(
mut user_provided_closure: F,
) {
let closure: &'static mut _ = Box::leak(Box::new(move |channel: i32, value: i32| {
user_provided_closure(channel, value);
}));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<i32, i32, ()>)
.cast::<unsafe extern "C" fn(i32, i32)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_aftertouchhook(Some(*ptr)) };
}
pub fn on_midi_poly_after_touch<F: FnMut(i32, i32, i32) + Send + Sync + 'static>(
mut user_provided_closure: F,
) {
let closure: &'static mut _ =
Box::leak(Box::new(move |channel: i32, pitch: i32, value: i32| {
user_provided_closure(channel, pitch, value);
}));
let callback = ClosureMut3::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr3<i32, i32, i32, ()>).cast::<unsafe extern "C" fn(
i32,
i32,
i32,
)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_polyaftertouchhook(Some(*ptr)) };
}
pub fn on_midi_byte<F: FnMut(i32, i32) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ = Box::leak(Box::new(move |port: i32, byte: i32| {
user_provided_closure(port, byte);
}));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<i32, i32, ()>)
.cast::<unsafe extern "C" fn(i32, i32)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_midibytehook(Some(*ptr)) };
}
pub fn receive_midi_messages_from_pd() {
unsafe { libpd_sys::libpd_queued_receive_midi_messages() };
}