Skip to content

Commit

Permalink
Add types for controlling a virtual DJ deck
Browse files Browse the repository at this point in the history
  • Loading branch information
uklotzde committed Jan 18, 2024
1 parent 99d6e23 commit 460f919
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 11 deletions.
12 changes: 6 additions & 6 deletions .rustfmt.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
edition = "2021"

# <https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#imports_granularity>
imports_granularity = "Crate"
#imports_granularity = "Crate"

# <https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#group_imports>
group_imports = "StdExternalCrate"
#group_imports = "StdExternalCrate"

# <https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#use_field_init_shorthand>
use_field_init_shorthand = true
#use_field_init_shorthand = true

# <https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#use_try_shorthand>
use_try_shorthand = true
#use_try_shorthand = true

# <https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#format_strings>
format_strings = true
#format_strings = true

# <https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#format_code_in_doc_comments>
format_code_in_doc_comments = true
#format_code_in_doc_comments = true
128 changes: 128 additions & 0 deletions src/deck.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-FileCopyrightText: The djio authors
// SPDX-License-Identifier: MPL-2.0

//! Virtual DJ deck utilities.
use std::time::Duration;

use crate::{CenterSliderInput, LedState};

pub const PLAYBACK_RATE_DEFAULT: f32 = 1.0;

pub const PLAYBACK_RATE_PAUSED: f32 = 0.0;

/// +/- 8%
pub const TEMPO_RANGE_DEFAULT: f32 = 0.08;

#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Position {
pub offset_secs: f64,
}

#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Cue {
pub position: Position,
}

#[derive(Debug, Clone, PartialEq)]
pub enum PlayState {
/// Paused
Paused {
on_cue: bool,
},
/// Previewing while (hot) cue is pressed
Previewing {
/// The cue or hot cue that is being previewed
cue: Cue,
},
/// Playing
Playing,
// Ended
Ended,
}

impl PlayState {
#[must_use]
pub const fn pioneer_cue_led_state(&self) -> LedState {
match self {
PlayState::Paused { on_cue: true }
| PlayState::Previewing { .. }
| PlayState::Playing => LedState::On,
PlayState::Paused { on_cue: false } => LedState::BlinkFast,
PlayState::Ended => LedState::Off,
}
}

#[must_use]
pub const fn pioneer_playpause_led_state(&self) -> LedState {
match self {
PlayState::Playing => LedState::On,
PlayState::Paused { .. } | PlayState::Previewing { .. } => LedState::BlinkSlow,
PlayState::Ended => LedState::Off,
}
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct Playable {
pub play_state: PlayState,

/// Duration of the media
///
/// `None` if unlimited or unknown in advance.
pub duration: Option<Duration>,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Tempo {
pub range: f32,
pub input: CenterSliderInput,
}

impl Tempo {
#[must_use]
pub fn playback_rate(self) -> f32 {
PLAYBACK_RATE_DEFAULT + self.input.map_position_linear(-self.range, 0.0, self.range)
}
}

impl Default for Tempo {
fn default() -> Self {
Self {
range: TEMPO_RANGE_DEFAULT,
input: CenterSliderInput {
position: CenterSliderInput::CENTER_POSITION,
},
}
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct Player {
/// Cue
pub cue: Cue,

/// Tempo
pub tempo: Tempo,

/// Playback rate
pub playback_rate: f32,

/// Pitch
///
/// `None` if disabled, i.e. changing the tempo implicitly changes the pitch.
///
/// `Some(0)` will preserve the original pitch.
pub pitch_semitones: Option<i8>,
}

impl Default for Player {
fn default() -> Self {
Self {
cue: Default::default(),
tempo: Default::default(),
playback_rate: PLAYBACK_RATE_DEFAULT,
pitch_semitones: None,
}
}
}
10 changes: 6 additions & 4 deletions src/hid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,10 @@ fn timeout_millis(timeout: Option<Duration>) -> i32 {
// to prevent losing precision unintentionally.
debug_assert_eq!(0, timeout.unwrap_or_default().subsec_nanos() % 1_000_000);
timeout
.as_ref()
.map(Duration::as_millis)
// Saturating conversion from u128 to i32
.map_or(INF_TIMEOUT_MILLIS, |millis| millis.min(MAX_TIMEOUT_MILLIS as _) as _)
.as_ref()
.map(Duration::as_millis)
// Saturating conversion from u128 to i32
.map_or(INF_TIMEOUT_MILLIS, |millis| {
millis.min(MAX_TIMEOUT_MILLIS as _) as _
})
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ pub use self::midi::{
MidiPortDescriptor, NewMidiInputGateway,
};

pub mod deck;

#[cfg(feature = "experimental-param")]
pub mod param;

Expand Down
3 changes: 2 additions & 1 deletion src/param/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ impl Registry {
};
self.entries.push(new_entry);
debug_assert_eq!(self.address_to_id.len(), self.entries.len());
let entry = self.entries
let entry = self
.entries
.last_mut()
// Safe unwrap after push
.expect("entry exists");
Expand Down

0 comments on commit 460f919

Please sign in to comment.