Skip to content

Commit

Permalink
Adjust playback speed (#12)
Browse files Browse the repository at this point in the history
* Adjust playback speed

* add label to decrease repetition
  • Loading branch information
agourlay authored Sep 5, 2024
1 parent 80a51cc commit 6a6264b
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 13 deletions.
14 changes: 12 additions & 2 deletions src/audio/midi_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@ impl AudioPlayer {
pub fn new(
song: Rc<Song>,
song_tempo: i32,
tempo_percentage: usize,
sound_font_file: Option<PathBuf>,
beat_sender: Arc<Sender<usize>>,
) -> Self {
// default to no solo track
let solo_track_id = None;

// player params
let player_params = Arc::new(Mutex::new(MidiPlayerParams::new(song_tempo, solo_track_id)));
let player_params = Arc::new(Mutex::new(MidiPlayerParams::new(
song_tempo,
tempo_percentage,
solo_track_id,
)));

// midi sequencer initialization
let builder = MidiBuilder::new();
Expand Down Expand Up @@ -102,6 +107,11 @@ impl AudioPlayer {
}
}

pub fn set_tempo_percentage(&mut self, new_tempo_percentage: usize) {
let mut params_guard = self.player_params.lock().unwrap();
params_guard.set_tempo_percentage(new_tempo_percentage)
}

pub fn stop(&mut self) {
// Pause stream
if let Some(stream) = &self.stream {
Expand Down Expand Up @@ -233,7 +243,7 @@ fn new_output_stream(
move |output: &mut [f32], _: &cpal::OutputCallbackInfo| {
let mut player_params_guard = player_params.lock().unwrap();
let mut sequencer_guard = sequencer.lock().unwrap();
sequencer_guard.advance(player_params_guard.tempo());
sequencer_guard.advance(player_params_guard.adjusted_tempo());
let mut synthesizer_guard = synthesizer.lock().unwrap();
// process midi events for current tick
if let Some(events) = sequencer_guard.get_next_events() {
Expand Down
12 changes: 9 additions & 3 deletions src/audio/midi_player_params.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
/// Hold values changed during playback of a MIDI events.
pub struct MidiPlayerParams {
tempo: i32,
tempo_percentage: usize,
solo_track_id: Option<usize>,
}

impl MidiPlayerParams {
pub fn new(tempo: i32, solo_track_id: Option<usize>) -> Self {
pub fn new(tempo: i32, tempo_percentage: usize, solo_track_id: Option<usize>) -> Self {
Self {
tempo,
tempo_percentage,
solo_track_id,
}
}
Expand All @@ -20,11 +22,15 @@ impl MidiPlayerParams {
self.solo_track_id = solo_track_id;
}

pub fn tempo(&self) -> i32 {
self.tempo
pub fn adjusted_tempo(&self) -> i32 {
(self.tempo as f32 * self.tempo_percentage as f32 / 100.0) as i32
}

pub fn set_tempo(&mut self, tempo: i32) {
self.tempo = tempo;
}

pub fn set_tempo_percentage(&mut self, tempo_percentage: usize) {
self.tempo_percentage = tempo_percentage;
}
}
73 changes: 65 additions & 8 deletions src/ui/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct RuxApplication {
all_tracks: Vec<TrackSelection>, // all possible tracks
tablature: Option<Tablature>, // loaded tablature
tablature_id: container::Id, // tablature container id
tempo_selection: TempoSelection, // tempo percentage for playback
audio_player: Option<AudioPlayer>, // audio player
tab_file_is_loading: bool, // file loading flag in progress
sound_font_file: Option<PathBuf>, // sound font file
Expand All @@ -54,6 +55,43 @@ impl SongDisplayInfo {
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct TempoSelection {
percentage: usize,
}

impl Default for TempoSelection {
fn default() -> Self {
TempoSelection::new(100)
}
}

impl TempoSelection {
fn new(percentage: usize) -> Self {
Self { percentage }
}

fn values() -> Vec<TempoSelection> {
vec![
TempoSelection::new(25),
TempoSelection::new(50),
TempoSelection::new(60),
TempoSelection::new(70),
TempoSelection::new(80),
TempoSelection::new(90),
TempoSelection::new(100),
TempoSelection::new(150),
TempoSelection::new(200),
]
}
}

impl Display for TempoSelection {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}%", self.percentage)
}
}

#[derive(Debug, Default, Clone, PartialEq)]
pub struct TrackSelection {
index: usize,
Expand All @@ -77,13 +115,14 @@ pub enum Message {
OpenFile, // open file dialog
FileOpened(Result<(Vec<u8>, String), PickerError>), // file content & file name
TrackSelected(TrackSelection), // track selection
FocusMeasure(usize), // used when clicking on measure in tablature
FocusTick(usize), // focus on a specific tick in the tablature
PlayPause, // toggle play/pause
StopPlayer, // stop playback
ToggleSolo, // toggle solo mode
WindowResized, // window resized
TablatureResized(Size), // tablature resized
FocusMeasure(usize), // used when clicking on measure in tablature
FocusTick(usize), // focus on a specific tick in the tablature
PlayPause, // toggle play/pause
StopPlayer, // stop playback
ToggleSolo, // toggle solo mode
WindowResized, // window resized
TablatureResized(Size), // tablature resized
TempoSelected(TempoSelection), // tempo selection
}

impl RuxApplication {
Expand All @@ -95,6 +134,7 @@ impl RuxApplication {
all_tracks: vec![],
tablature: None,
tablature_id: container::Id::new("tablature-outer-container"),
tempo_selection: TempoSelection::default(),
audio_player: None,
tab_file_is_loading: false,
sound_font_file,
Expand Down Expand Up @@ -186,6 +226,7 @@ impl RuxApplication {
let audio_player = AudioPlayer::new(
song_rc.clone(),
song_rc.tempo.value,
self.tempo_selection.percentage,
self.sound_font_file.clone(),
self.beat_sender.clone(),
);
Expand Down Expand Up @@ -270,6 +311,13 @@ impl RuxApplication {
}
Task::none()
}
Message::TempoSelected(tempos_selection) => {
if let Some(audio_player) = &mut self.audio_player {
audio_player.set_tempo_percentage(tempos_selection.percentage)
}
self.tempo_selection = tempos_selection;
Task::none()
}
}
}

Expand Down Expand Up @@ -298,6 +346,15 @@ impl RuxApplication {
let track_control = if self.all_tracks.is_empty() {
row![horizontal_space()]
} else {
let tempo_label = text("Tempo").size(14);
let tempo_percentage = pick_list(
TempoSelection::values(),
Some(&self.tempo_selection),
Message::TempoSelected,
)
.text_size(14)
.padding([5, 10]);

let solo_mode = action_toggle(
solo_icon(),
"Solo",
Expand All @@ -315,7 +372,7 @@ impl RuxApplication {
.text_size(14)
.padding([5, 10]);

row![solo_mode, track_pick_list,]
row![tempo_label, tempo_percentage, solo_mode, track_pick_list,]
.spacing(10)
.align_y(Alignment::Center)
};
Expand Down

0 comments on commit 6a6264b

Please sign in to comment.