1use std::{
2 io::{Read, Write},
3 mem,
4 sync::{
5 Arc,
6 atomic::{AtomicU64, Ordering},
7 },
8};
9
10use clap_clap::prelude as clap;
11
12const NUM_PARAMS: usize = 3;
13const NUM_BYTES: usize = NUM_PARAMS * 8; struct Example {
18 state: Arc<[AtomicU64; NUM_PARAMS]>,
20}
21
22impl Default for Example {
23 fn default() -> Self {
24 Self {
25 state: Arc::new([
26 AtomicU64::new(0.0f64.to_bits()),
27 AtomicU64::new(0.0f64.to_bits()),
28 AtomicU64::new(0.0f64.to_bits()),
29 ]),
30 }
31 }
32}
33
34impl clap::Extensions<Self> for Example {
35 fn params() -> Option<impl clap::Params<Self>> {
36 Some(ExampleParams)
37 }
38
39 fn state() -> Option<impl clap::State<Self>> {
40 Some(ExampleState)
41 }
42}
43
44struct ExampleParams;
45
46impl clap::Params<Example> for ExampleParams {
47 fn count(_: &Example) -> u32 {
48 NUM_PARAMS as u32
49 }
50
51 fn get_info(_: &Example, param_index: u32) -> Option<clap::ParamInfo> {
52 (param_index < NUM_PARAMS as u32).then(|| {
53 clap::ParamInfo {
54 id: clap::ClapId::from(param_index as u16),
55 flags: clap::params::InfoFlags::RequiresProcess as u32
56 | clap::params::InfoFlags::Automatable as u32,
58 name: format!("Param {param_index}"),
59 module: format!("{param_index}/param"),
60 min_value: 0.0,
61 max_value: 1.0,
62 default_value: 0.0,
63 }
64 })
65 }
66
67 fn get_value(plugin: &Example, param_id: clap::ClapId) -> Option<f64> {
68 let id: usize = param_id.into();
69 (id < NUM_PARAMS).then(|| f64::from_bits(plugin.state[id].load(Ordering::Relaxed)))
70 }
71
72 fn value_to_text(
73 _: &Example,
74 _: clap::ClapId,
75 value: f64,
76 mut out_buf: &mut [u8],
77 ) -> Result<(), clap::Error> {
78 Ok(write!(out_buf, "{value:.2}")?)
79 }
80
81 fn text_to_value(
82 _: &Example,
83 _: clap::ClapId,
84 param_value_text: &str,
85 ) -> Result<f64, clap::Error> {
86 Ok(param_value_text.parse()?)
87 }
88
89 fn flush_inactive(_: &Example, _: &clap::InputEvents, _: &clap::OutputEvents) {}
90
91 fn flush(
92 _: &<Example as clap::Plugin>::AudioThread,
93 _: &clap::InputEvents,
94 _: &clap::OutputEvents,
95 ) {
96 }
97}
98
99struct ExampleState;
100
101impl clap::State<Example> for ExampleState {
102 fn save(plugin: &Example, stream: &mut clap::OStream) -> Result<(), clap::Error> {
103 let buf: [u64; NUM_PARAMS] =
104 std::array::from_fn(|i| plugin.state[i].load(Ordering::Acquire));
105 let buf: [u8; NUM_BYTES] = unsafe { mem::transmute(buf) };
106 stream.write_all(&buf).map_err(Into::into)
107 }
108
109 fn load(plugin: &Example, stream: &mut clap::IStream) -> Result<(), clap::Error> {
110 let mut buf: [u8; NUM_BYTES] = [0; NUM_BYTES];
111 stream.read_exact(&mut buf)?;
112
113 let buf: [u64; NUM_PARAMS] = unsafe { mem::transmute(buf) };
114 for i in 0..NUM_PARAMS {
115 plugin.state[i].store(buf[i], Ordering::Release);
116 }
117
118 Ok(())
119 }
120}
121
122impl clap::Plugin for Example {
123 type AudioThread = AudioThread;
124
125 const ID: &'static str = "com.your-company.YourPlugin";
126 const NAME: &'static str = "Plugin Name";
127 const VENDOR: &'static str = "Vendor";
128 const URL: &'static str = "https://your-domain.com/your-plugin";
129 const MANUAL_URL: &'static str = "https://your-domain.com/your-plugin/manual";
130 const SUPPORT_URL: &'static str = "https://your-domain.com/support";
131 const VERSION: &'static str = "1.4.2";
132 const DESCRIPTION: &'static str = "The plugin description.";
133
134 fn features() -> impl Iterator<Item = &'static str> {
135 "example parameter state".split_whitespace()
136 }
137
138 fn init(&mut self, _: Arc<clap::Host>) -> Result<(), clap::Error> {
139 Ok(())
140 }
141
142 fn activate(&mut self, _: f64, _: u32, _: u32) -> Result<AudioThread, clap::Error> {
144 Ok(AudioThread {
145 state: self.state.clone(),
146 })
147 }
148}
149
150struct AudioThread {
151 state: Arc<[AtomicU64; NUM_PARAMS]>,
152}
153
154impl clap::AudioThread<Example> for AudioThread {
155 fn process(&mut self, process: &mut clap::Process) -> Result<clap::Status, clap::Error> {
156 let in_events = process.in_events();
157
158 for i in 0..in_events.size() {
159 let header = in_events.get(i);
160
161 if let Ok(param) = header.param_value() {
162 let value = param.value();
163 let id: usize = param.param_id().into();
164
165 if id < NUM_PARAMS {
166 self.state[id].store(value.to_bits(), Ordering::Release);
167 }
168 }
169 }
170 Ok(clap::Continue)
171 }
172}
173
174clap::entry!(Example);