clap_clap/ext/
note_ports.rs1use std::fmt::{Display, Formatter};
2
3use crate::{
4 ffi::{
5 CLAP_NOTE_DIALECT_CLAP, CLAP_NOTE_DIALECT_MIDI, CLAP_NOTE_DIALECT_MIDI_MPE,
6 CLAP_NOTE_DIALECT_MIDI2, CLAP_NOTE_PORTS_RESCAN_ALL, CLAP_NOTE_PORTS_RESCAN_NAMES,
7 clap_host_note_ports, clap_note_port_info,
8 },
9 host::Host,
10 id::ClapId,
11 impl_flags_u32,
12 plugin::Plugin,
13};
14
15pub trait NotePorts<P>
16where
17 P: Plugin,
18{
19 fn count(plugin: &P, is_input: bool) -> u32;
20 fn get(plugin: &P, index: u32, is_input: bool) -> Option<NotePortInfo>;
21}
22
23impl<P: Plugin> NotePorts<P> for () {
24 fn count(_: &P, _: bool) -> u32 {
25 0
26 }
27
28 fn get(_: &P, _: u32, _: bool) -> Option<NotePortInfo> {
29 None
30 }
31}
32
33#[derive(Debug, Copy, Clone, PartialEq, Eq)]
34#[repr(u32)]
35pub enum NoteDialect {
36 Clap = CLAP_NOTE_DIALECT_CLAP,
38 Midi = CLAP_NOTE_DIALECT_MIDI,
40 MidiMPE = CLAP_NOTE_DIALECT_MIDI_MPE,
42 Midi2 = CLAP_NOTE_DIALECT_MIDI2,
44}
45
46impl_flags_u32!(NoteDialect);
47
48impl NoteDialect {
49 pub fn all() -> u32 {
50 !0
51 }
52}
53
54#[derive(Debug, Default, Clone, PartialEq)]
55pub struct NotePortInfo {
56 pub id: ClapId,
57 pub supported_dialects: u32,
58 pub preferred_dialect: u32,
59 pub name: String,
60}
61
62impl NotePortInfo {
63 pub(super) fn fill_clap_note_port_info(&self, info: &mut clap_note_port_info) {
64 info.id = self.id.into();
65
66 let n = self.name.len().min(info.name.len() - 1);
68 unsafe {
69 std::ptr::copy_nonoverlapping(self.name.as_ptr(), info.name.as_mut_ptr() as *mut _, n)
70 }
71 info.name[n] = b'\0' as _;
73
74 info.supported_dialects = self.supported_dialects;
75 info.preferred_dialect = self.preferred_dialect;
76 }
77}
78
79pub(crate) use ffi::PluginNotePorts;
80
81mod ffi {
82 use std::marker::PhantomData;
83
84 use crate::{
85 ext::note_ports::NotePorts,
86 ffi::{clap_note_port_info, clap_plugin, clap_plugin_note_ports},
87 plugin::{ClapPlugin, Plugin},
88 };
89
90 extern "C-unwind" fn count<E, P>(plugin: *const clap_plugin, is_input: bool) -> u32
91 where
92 P: Plugin,
93 E: NotePorts<P>,
94 {
95 if plugin.is_null() {
96 return 0;
97 }
98 let mut clap_plugin = unsafe { ClapPlugin::<P>::new_unchecked(plugin) };
101
102 let plugin = unsafe { clap_plugin.plugin() };
107
108 E::count(plugin, is_input)
109 }
110
111 extern "C-unwind" fn get<E, P>(
112 plugin: *const clap_plugin,
113 index: u32,
114 is_input: bool,
115 info: *mut clap_note_port_info,
116 ) -> bool
117 where
118 P: Plugin,
119 E: NotePorts<P>,
120 {
121 if plugin.is_null() {
122 return false;
123 }
124 let mut clap_plugin = unsafe { ClapPlugin::<P>::new_unchecked(plugin) };
127
128 let plugin = unsafe { clap_plugin.plugin() };
133
134 let info = unsafe { &mut *info };
138
139 E::get(plugin, index, is_input)
140 .map(|x| x.fill_clap_note_port_info(info))
141 .is_some()
142 }
143
144 pub struct PluginNotePorts<P> {
145 #[allow(unused)]
146 clap_plugin_note_ports: clap_plugin_note_ports,
147 _marker: PhantomData<P>,
148 }
149
150 impl<P: Plugin> PluginNotePorts<P> {
151 pub fn new<E: NotePorts<P>>(_: E) -> Self {
152 Self {
153 clap_plugin_note_ports: clap_plugin_note_ports {
154 count: Some(count::<E, P>),
155 get: Some(get::<E, P>),
156 },
157 _marker: PhantomData,
158 }
159 }
160 }
161}
162
163#[derive(Debug, Copy, Clone, PartialEq)]
164#[repr(u32)]
165pub enum RescanFlags {
166 All = CLAP_NOTE_PORTS_RESCAN_ALL,
171 Names = CLAP_NOTE_PORTS_RESCAN_NAMES,
173}
174
175impl_flags_u32!(RescanFlags);
176
177#[derive(Debug)]
178pub struct HostNotePorts<'a> {
179 host: &'a Host,
180 clap_host_note_ports: &'a clap_host_note_ports,
181}
182
183impl<'a> HostNotePorts<'a> {
184 pub(crate) const unsafe fn new_unchecked(
189 host: &'a Host,
190 clap_host_note_ports: &'a clap_host_note_ports,
191 ) -> Self {
192 Self {
193 host,
194 clap_host_note_ports,
195 }
196 }
197
198 pub fn supported_dialects(&self) -> u32 {
199 let callback = self.clap_host_note_ports.supported_dialects.unwrap();
202 unsafe { callback(self.host.clap_host()) }
203 }
204
205 pub fn rescan(&self, flags: u32) {
206 let callback = self.clap_host_note_ports.rescan.unwrap();
209 unsafe { callback(self.host.clap_host(), flags) };
210 }
211}
212
213#[derive(Debug)]
214pub enum Error {}
215
216impl Display for Error {
217 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
218 write!(f, "note ports")
219 }
220}
221
222impl std::error::Error for Error {}
223
224impl From<Error> for crate::Error {
225 fn from(value: Error) -> Self {
226 crate::ext::Error::NotePorts(value).into()
227 }
228}