-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a volume parameter to the polysynth example
- Loading branch information
Showing
5 changed files
with
211 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
use crate::{PolySynthAudioProcessor, PolySynthPluginMainThread}; | ||
use clack_extensions::params::implementation::{ | ||
ParamDisplayWriter, ParamInfoWriter, PluginAudioProcessorParams, PluginMainThreadParams, | ||
}; | ||
use clack_extensions::params::info::{ParamInfoData, ParamInfoFlags}; | ||
use clack_extensions::state::PluginStateImpl; | ||
use clack_plugin::events::spaces::CoreEventSpace; | ||
use clack_plugin::events::UnknownEvent; | ||
use clack_plugin::plugin::PluginError; | ||
use clack_plugin::prelude::{InputEvents, OutputEvents}; | ||
use clack_plugin::stream::{InputStream, OutputStream}; | ||
use std::fmt::Write as _; | ||
use std::io::{Read, Write as _}; | ||
use std::sync::atomic::{AtomicU32, Ordering}; | ||
|
||
const DEFAULT_VOLUME: f32 = 0.2; | ||
|
||
pub struct PolySynthParams { | ||
volume: AtomicF32, | ||
} | ||
|
||
impl PolySynthParams { | ||
pub fn new() -> Self { | ||
Self { | ||
volume: AtomicF32::new(DEFAULT_VOLUME), | ||
} | ||
} | ||
|
||
#[inline] | ||
pub fn get_volume(&self) -> f32 { | ||
self.volume.load(Ordering::SeqCst) | ||
} | ||
|
||
#[inline] | ||
pub fn set_volume(&self, new_volume: f32) { | ||
let new_volume = new_volume.clamp(0., 1.); | ||
self.volume.store(new_volume, Ordering::SeqCst) | ||
} | ||
|
||
pub fn handle_event(&self, event: &UnknownEvent) { | ||
if let Some(CoreEventSpace::ParamValue(event)) = event.as_core_event() { | ||
if event.param_id() == 1 { | ||
self.set_volume(event.value() as f32) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl<'a> PluginStateImpl for PolySynthPluginMainThread<'a> { | ||
fn save(&mut self, output: &mut OutputStream) -> Result<(), PluginError> { | ||
let volume_param = self.shared.params.get_volume(); | ||
|
||
output.write_all(&volume_param.to_le_bytes())?; | ||
Ok(()) | ||
} | ||
|
||
fn load(&mut self, input: &mut InputStream) -> Result<(), PluginError> { | ||
let mut buf = [0; 4]; | ||
input.read_exact(&mut buf)?; | ||
let volume_value = f32::from_le_bytes(buf); | ||
self.shared.params.set_volume(volume_value); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<'a> PluginMainThreadParams for PolySynthPluginMainThread<'a> { | ||
fn count(&self) -> u32 { | ||
1 | ||
} | ||
|
||
fn get_info(&self, param_index: u32, info: &mut ParamInfoWriter) { | ||
if param_index != 0 { | ||
return; | ||
} | ||
info.set(&ParamInfoData { | ||
id: 1, | ||
flags: ParamInfoFlags::IS_AUTOMATABLE, | ||
cookie: Default::default(), | ||
name: "Volume", | ||
module: "", | ||
min_value: 0.0, | ||
max_value: 1.0, | ||
default_value: DEFAULT_VOLUME as f64, | ||
}) | ||
} | ||
|
||
fn get_value(&self, param_id: u32) -> Option<f64> { | ||
if param_id == 1 { | ||
Some(self.shared.params.get_volume() as f64) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
fn value_to_text( | ||
&self, | ||
param_id: u32, | ||
value: f64, | ||
writer: &mut ParamDisplayWriter, | ||
) -> std::fmt::Result { | ||
if param_id == 1 { | ||
write!(writer, "{0:.2} %", value * 100.0) | ||
} else { | ||
Err(std::fmt::Error) | ||
} | ||
} | ||
|
||
fn text_to_value(&self, param_id: u32, text: &str) -> Option<f64> { | ||
if param_id == 1 { | ||
let text = text.strip_suffix(" %")?; | ||
let value = text.parse().ok()?; | ||
|
||
Some(value) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
fn flush( | ||
&mut self, | ||
input_parameter_changes: &InputEvents, | ||
_output_parameter_changes: &mut OutputEvents, | ||
) { | ||
for event in input_parameter_changes { | ||
self.shared.params.handle_event(event) | ||
} | ||
} | ||
} | ||
|
||
impl<'a> PluginAudioProcessorParams for PolySynthAudioProcessor<'a> { | ||
fn flush( | ||
&mut self, | ||
input_parameter_changes: &InputEvents, | ||
_output_parameter_changes: &mut OutputEvents, | ||
) { | ||
for event in input_parameter_changes { | ||
self.shared.params.handle_event(event) | ||
} | ||
} | ||
} | ||
|
||
struct AtomicF32(AtomicU32); | ||
|
||
impl AtomicF32 { | ||
#[inline] | ||
fn new(value: f32) -> Self { | ||
Self(AtomicU32::new(f32_to_u32_bytes(value))) | ||
} | ||
|
||
#[inline] | ||
fn store(&self, new_value: f32, order: Ordering) { | ||
self.0.store(f32_to_u32_bytes(new_value), order) | ||
} | ||
|
||
#[inline] | ||
fn load(&self, order: Ordering) -> f32 { | ||
f32_from_u32_bytes(self.0.load(order)) | ||
} | ||
} | ||
|
||
#[inline] | ||
fn f32_to_u32_bytes(value: f32) -> u32 { | ||
u32::from_ne_bytes(value.to_ne_bytes()) | ||
} | ||
|
||
#[inline] | ||
fn f32_from_u32_bytes(bytes: u32) -> f32 { | ||
f32::from_ne_bytes(bytes.to_ne_bytes()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters