Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Midi functions draft #66

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions main/medium/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,9 @@ pub use control_surface::*;
mod midi;
pub use midi::*;

mod source_midi;
pub use source_midi::*;

mod pcm_source;
pub use pcm_source::*;

Expand Down
50 changes: 50 additions & 0 deletions main/medium/src/misc_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
};

use crate::util::concat_reaper_strs;
use derive_more::Display;
use enumflags2::BitFlags;
use helgoboss_midi::{U14, U7};
use reaper_low::raw;
Expand Down Expand Up @@ -1586,3 +1587,52 @@ impl InsertMediaMode {
bits as i32
}
}

/// Represents MediaItemTake midi CC shape kind.
///
/// # Note
///
/// If CcShapeKind::Beizer is given to CC event, additional midi event
/// should be put at the same position:
/// 0xF followed by 'CCBZ ' and 5 more bytes represents
/// bezier curve data for the previous MIDI event:
/// - 1 byte for the bezier type (usually 0)
/// - 4 bytes for the bezier tension as a float.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Display)]
pub enum CcShapeKind {
#[default]
Square,
Linear,
SlowStartEnd,
FastStart,
FastEnd,
Beizer,
}
impl CcShapeKind {
/// CcShapeKind from u8.
///
/// Returns Err if can not find proper variant.
pub fn from_raw(value: u8) -> Result<Self, String> {
match value {
v if v == 0 => Ok(Self::Square),
v if v == 16 => Ok(Self::Linear),
v if v == 32 => Ok(Self::SlowStartEnd),
v if v == 16 | 32 => Ok(Self::FastStart),
v if v == 64 => Ok(Self::FastEnd),
v if v == 16 | 64 => Ok(Self::Beizer),
_ => Err(format!("not a cc shape: {:?}", value)),
}
}

/// u8 representation of CcShapeKind
pub fn to_raw(&self) -> u8 {
match self {
Self::Square => 0,
Self::Linear => 16,
Self::SlowStartEnd => 32,
Self::FastStart => 16 | 32,
Self::FastEnd => 64,
Self::Beizer => 16 | 64,
}
}
}
84 changes: 84 additions & 0 deletions main/medium/src/misc_newtypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,90 @@ impl TryFrom<f64> for PositionInQuarterNotes {
}
}

impl std::ops::Add for PositionInQuarterNotes {
fn add(self, rhs: Self) -> Self {
PositionInQuarterNotes::new(self.get() + rhs.get())
}
type Output = Self;
}
impl std::ops::Sub for PositionInQuarterNotes {
fn sub(self, rhs: Self) -> Self {
PositionInQuarterNotes::new(self.get() - rhs.get())
}
type Output = Self;
}
impl std::ops::Div for PositionInQuarterNotes {
fn div(self, rhs: Self) -> Self {
PositionInQuarterNotes::new(self.get() / rhs.get())
}
type Output = Self;
}
impl std::ops::Mul for PositionInQuarterNotes {
fn mul(self, rhs: Self) -> Self {
PositionInQuarterNotes::new(self.get() * rhs.get())
}
type Output = Self;
}

/// This represents a position expressed as an amount of midi ticks (PPQ).
///
/// Can be negative, see [`PositionInSeconds`](struct.PositionInSeconds.html).
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Default, Display)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(try_from = "f64")
)]
pub struct PositionInPpq(pub(crate) f64);

impl PositionInPpq {
/// Position at 0.0 quarter notes.
pub const ZERO: PositionInPpq = PositionInPpq(0.0);

fn is_valid(value: f64) -> bool {
!value.is_infinite() && !value.is_nan()
}

/// Creates a value.
///
/// # Panics
///
/// This function panics if the given value is a special number.
pub fn new(value: f64) -> PositionInPpq {
assert!(
Self::is_valid(value),
"{} is not a valid PositionInQn value",
value
);
PositionInPpq(value)
}

/// Creates a PositionInQn value without bound checking.
///
/// # Safety
///
/// You must ensure that the given value is not a special number.
pub unsafe fn new_unchecked(value: f64) -> PositionInPpq {
PositionInPpq(value)
}

/// Returns the wrapped value.
pub const fn get(self) -> f64 {
self.0
}
}

impl TryFrom<f64> for PositionInPpq {
type Error = TryFromGreaterError<f64>;

fn try_from(value: f64) -> Result<Self, Self::Error> {
if !Self::is_valid(value) {
return Err(TryFromGreaterError::new("value must be non-special", value));
}
Ok(PositionInPpq(value))
}
}

/// This represents a volume measured in decibel.
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Default, Display)]
#[cfg_attr(
Expand Down
Loading