Add a Transport struct with conversion methods
We'll add this to the ProcessContext in a bit.
This commit is contained in:
parent
99f97978a9
commit
a483dbc6a6
218
src/context.rs
218
src/context.rs
|
@ -80,6 +80,60 @@ pub trait GuiContext: Send + Sync + 'static {
|
||||||
unsafe fn raw_default_normalized_param_value(&self, param: ParamPtr) -> f32;
|
unsafe fn raw_default_normalized_param_value(&self, param: ParamPtr) -> f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information about the plugin's transport. Depending on the plugin API and the host not all
|
||||||
|
/// fields may be available.
|
||||||
|
pub struct Transport {
|
||||||
|
/// Whether the transport is currently running.
|
||||||
|
pub playing: bool,
|
||||||
|
/// Whether recording is enabled in the project.
|
||||||
|
pub recording: bool,
|
||||||
|
/// Whether the pre-roll is currently active, if the plugin API reports this information.
|
||||||
|
pub preroll_active: Option<bool>,
|
||||||
|
|
||||||
|
/// The sample rate in Hertz. Also passed in
|
||||||
|
/// [`Plugin::initialize()`][crate::prelude::Plugin::initialize()], so if you need this then you
|
||||||
|
/// can also store that value.
|
||||||
|
pub sample_rate: f32,
|
||||||
|
/// The proejct's tempo in beats per minute.
|
||||||
|
pub tempo: Option<f64>,
|
||||||
|
/// The time signature's numerator.
|
||||||
|
pub time_sig_numerator: Option<i32>,
|
||||||
|
/// The time signature's denominator.
|
||||||
|
pub time_sig_denominator: Option<i32>,
|
||||||
|
|
||||||
|
// XXX: VST3 also has a continuous time in samples that ignores loops, but we can't reconstruct
|
||||||
|
// something similar in CLAP so it may be best to just ignore that so you can't rely on it
|
||||||
|
/// The position in the song in samples. Can be used to calculate the time in seconds if needed.
|
||||||
|
pub(crate) pos_samples: Option<i64>,
|
||||||
|
/// The position in the song in quarter notes. Can be used to calculate the time in samples if
|
||||||
|
/// needed.
|
||||||
|
pub(crate) pos_seconds: Option<f64>,
|
||||||
|
/// The position in the song in quarter notes. Can be calculated from the time in seconds and
|
||||||
|
/// the tempo if needed.
|
||||||
|
pub(crate) pos_beats: Option<f64>,
|
||||||
|
/// The last bar's start position in beats. Can be calculated from the beat position and time
|
||||||
|
/// signature if needed.
|
||||||
|
pub(crate) bar_start_pos_beats: Option<f64>,
|
||||||
|
/// The number of the bar at `bar_start_pos_beats`. This starts at 0 for the very first bar at
|
||||||
|
/// the start of the song. Can be calculated from the beat position and time signature if
|
||||||
|
/// needed.
|
||||||
|
pub(crate) bar_number: Option<i32>,
|
||||||
|
|
||||||
|
/// The loop range in samples, if the loop is active and this information is available. None of
|
||||||
|
/// the plugin API docs mention whether this is exclusive or inclusive, but just assume that the
|
||||||
|
/// end is exclusive. Can be calulcated from the other loop range information if needed.
|
||||||
|
pub(crate) loop_range_samples: Option<(i64, i64)>,
|
||||||
|
/// The loop range in seconds, if the loop is active and this information is available. None of
|
||||||
|
/// the plugin API docs mention whether this is exclusive or inclusive, but just assume that the
|
||||||
|
/// end is exclusive. Can be calulcated from the other loop range information if needed.
|
||||||
|
pub(crate) loop_range_seconds: Option<(f64, f64)>,
|
||||||
|
/// The loop range in quarter notes, if the loop is active and this information is available.
|
||||||
|
/// None of the plugin API docs mention whether this is exclusive or inclusive, but just assume
|
||||||
|
/// that the end is exclusive. Can be calulcated from the other loop range information if
|
||||||
|
/// needed.
|
||||||
|
pub(crate) loop_range_beats: Option<(f64, f64)>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A convenience helper for setting parameter values. Any changes made here will be broadcasted to
|
/// A convenience helper for setting parameter values. Any changes made here will be broadcasted to
|
||||||
/// the host and reflected in the plugin's [`Params`][crate::param::internals::Params] object. These
|
/// the host and reflected in the plugin's [`Params`][crate::param::internals::Params] object. These
|
||||||
/// functions should only be called from the main thread.
|
/// functions should only be called from the main thread.
|
||||||
|
@ -87,6 +141,170 @@ pub struct ParamSetter<'a> {
|
||||||
context: &'a dyn GuiContext,
|
context: &'a dyn GuiContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: These conversions have not really been tested yet, there might be an error in there somewhere
|
||||||
|
impl Transport {
|
||||||
|
/// The position in the song in samples. Will be calculated from other information if needed.
|
||||||
|
pub fn pos_samples(&self) -> Option<i64> {
|
||||||
|
match (
|
||||||
|
self.pos_samples,
|
||||||
|
self.pos_seconds,
|
||||||
|
self.pos_beats,
|
||||||
|
self.tempo,
|
||||||
|
) {
|
||||||
|
(Some(pos_samples), _, _, _) => Some(pos_samples),
|
||||||
|
(_, Some(pos_seconds), _, _) => {
|
||||||
|
Some((pos_seconds * self.sample_rate as f64).round() as i64)
|
||||||
|
}
|
||||||
|
(_, _, Some(pos_beats), Some(tempo)) => {
|
||||||
|
Some((pos_beats / tempo * 60.0 * self.sample_rate as f64).round() as i64)
|
||||||
|
}
|
||||||
|
(_, _, _, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The position in the song in quarter notes. Will be calculated from other information if
|
||||||
|
/// needed.
|
||||||
|
pub fn pos_seconds(&self) -> Option<f64> {
|
||||||
|
match (
|
||||||
|
self.pos_samples,
|
||||||
|
self.pos_seconds,
|
||||||
|
self.pos_beats,
|
||||||
|
self.tempo,
|
||||||
|
) {
|
||||||
|
(_, Some(pos_seconds), _, _) => Some(pos_seconds),
|
||||||
|
(Some(pos_samples), _, _, _) => Some(pos_samples as f64 / self.sample_rate as f64),
|
||||||
|
(_, _, Some(pos_beats), Some(tempo)) => Some(pos_beats / tempo * 60.0),
|
||||||
|
(_, _, _, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The position in the song in quarter notes. Will be calculated from other information if
|
||||||
|
/// needed.
|
||||||
|
pub fn pos_beats(&self) -> Option<f64> {
|
||||||
|
match (
|
||||||
|
self.pos_samples,
|
||||||
|
self.pos_seconds,
|
||||||
|
self.pos_beats,
|
||||||
|
self.tempo,
|
||||||
|
) {
|
||||||
|
(_, _, Some(pos_beats), _) => Some(pos_beats),
|
||||||
|
(_, Some(pos_seconds), _, Some(tempo)) => Some(pos_seconds / 60.0 * tempo),
|
||||||
|
(Some(pos_samples), _, _, Some(tempo)) => {
|
||||||
|
Some(pos_samples as f64 / self.sample_rate as f64 / 60.0 * tempo)
|
||||||
|
}
|
||||||
|
(_, _, _, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The last bar's start position in beats. Will be calculated from other information if needed.
|
||||||
|
pub fn bar_start_pos_beats(&self) -> Option<f64> {
|
||||||
|
if self.bar_start_pos_beats.is_some() {
|
||||||
|
return self.bar_start_pos_beats;
|
||||||
|
}
|
||||||
|
|
||||||
|
match (
|
||||||
|
self.time_sig_numerator,
|
||||||
|
self.time_sig_denominator,
|
||||||
|
self.pos_beats(),
|
||||||
|
) {
|
||||||
|
(Some(time_sig_numerator), Some(time_sig_denominator), Some(pos_beats)) => {
|
||||||
|
let quarter_note_bar_length =
|
||||||
|
time_sig_numerator as f64 / time_sig_denominator as f64 * 4.0;
|
||||||
|
Some(pos_beats.div_euclid(quarter_note_bar_length))
|
||||||
|
}
|
||||||
|
(_, _, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The number of the bar at `bar_start_pos_beats`. This starts at 0 for the very first bar at
|
||||||
|
/// the start of the song. Will be calculated from other information if needed.
|
||||||
|
pub fn bar_number(&self) -> Option<i32> {
|
||||||
|
if self.bar_number.is_some() {
|
||||||
|
return self.bar_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
match (
|
||||||
|
self.time_sig_numerator,
|
||||||
|
self.time_sig_denominator,
|
||||||
|
self.pos_beats(),
|
||||||
|
) {
|
||||||
|
(Some(time_sig_numerator), Some(time_sig_denominator), Some(pos_beats)) => {
|
||||||
|
let quarter_note_bar_length =
|
||||||
|
time_sig_numerator as f64 / time_sig_denominator as f64 * 4.0;
|
||||||
|
Some((pos_beats / quarter_note_bar_length).floor() as i32)
|
||||||
|
}
|
||||||
|
(_, _, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The loop range in samples, if the loop is active and this information is available. None of
|
||||||
|
/// the plugin API docs mention whether this is exclusive or inclusive, but just assume that the
|
||||||
|
/// end is exclusive. Will be calculated from other information if needed.
|
||||||
|
pub fn loop_range_samples(&self) -> Option<(i64, i64)> {
|
||||||
|
match (
|
||||||
|
self.loop_range_samples,
|
||||||
|
self.loop_range_seconds,
|
||||||
|
self.loop_range_beats,
|
||||||
|
self.tempo,
|
||||||
|
) {
|
||||||
|
(Some(loop_range_samples), _, _, _) => Some(loop_range_samples),
|
||||||
|
(_, Some((start_seconds, end_seconds)), _, _) => Some((
|
||||||
|
((start_seconds * self.sample_rate as f64).round() as i64),
|
||||||
|
((end_seconds * self.sample_rate as f64).round() as i64),
|
||||||
|
)),
|
||||||
|
(_, _, Some((start_beats, end_beats)), Some(tempo)) => Some((
|
||||||
|
(start_beats / tempo * 60.0 * self.sample_rate as f64).round() as i64,
|
||||||
|
(end_beats / tempo * 60.0 * self.sample_rate as f64).round() as i64,
|
||||||
|
)),
|
||||||
|
(_, _, _, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The loop range in seconds, if the loop is active and this information is available. None of
|
||||||
|
/// the plugin API docs mention whether this is exclusive or inclusive, but just assume that the
|
||||||
|
/// end is exclusive. Will be calculated from other information if needed.
|
||||||
|
pub fn loop_range_seconds(&self) -> Option<(f64, f64)> {
|
||||||
|
match (
|
||||||
|
self.loop_range_samples,
|
||||||
|
self.loop_range_seconds,
|
||||||
|
self.loop_range_beats,
|
||||||
|
self.tempo,
|
||||||
|
) {
|
||||||
|
(_, Some(loop_range_seconds), _, _) => Some(loop_range_seconds),
|
||||||
|
(Some((start_samples, end_samples)), _, _, _) => Some((
|
||||||
|
start_samples as f64 / self.sample_rate as f64,
|
||||||
|
end_samples as f64 / self.sample_rate as f64,
|
||||||
|
)),
|
||||||
|
(_, _, Some((start_beats, end_beats)), Some(tempo)) => {
|
||||||
|
Some((start_beats / tempo * 60.0, end_beats / tempo * 60.0))
|
||||||
|
}
|
||||||
|
(_, _, _, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The loop range in quarter notes, if the loop is active and this information is available.
|
||||||
|
/// None of the plugin API docs mention whether this is exclusive or inclusive, but just assume
|
||||||
|
/// that the end is exclusive. Will be calculated from other information if needed.
|
||||||
|
pub fn loop_range_beats(&self) -> Option<(f64, f64)> {
|
||||||
|
match (
|
||||||
|
self.loop_range_samples,
|
||||||
|
self.loop_range_seconds,
|
||||||
|
self.loop_range_beats,
|
||||||
|
self.tempo,
|
||||||
|
) {
|
||||||
|
(_, _, Some(loop_range_beats), _) => Some(loop_range_beats),
|
||||||
|
(_, Some((start_seconds, end_seconds)), _, Some(tempo)) => {
|
||||||
|
Some((start_seconds / 60.0 * tempo, end_seconds / 60.0 * tempo))
|
||||||
|
}
|
||||||
|
(Some((start_samples, end_samples)), _, _, Some(tempo)) => Some((
|
||||||
|
start_samples as f64 / self.sample_rate as f64 / 60.0 * tempo,
|
||||||
|
end_samples as f64 / self.sample_rate as f64 / 60.0 * tempo,
|
||||||
|
)),
|
||||||
|
(_, _, _, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> ParamSetter<'a> {
|
impl<'a> ParamSetter<'a> {
|
||||||
pub fn new(context: &'a dyn GuiContext) -> Self {
|
pub fn new(context: &'a dyn GuiContext) -> Self {
|
||||||
Self { context }
|
Self { context }
|
||||||
|
|
Loading…
Reference in a new issue