diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2f0b5..de56bdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ backwards compatibility. * LED can be configured to visualize the current position within the loop. * Allow reset of the loop position through a control input. * Play/pause the delay line using a control input. +* Allow configuration of the ratio between the tap interval and delay length. ## 1.2.0 diff --git a/control/src/cache/configuration.rs b/control/src/cache/configuration.rs index 47e0ab0..fe987c1 100644 --- a/control/src/cache/configuration.rs +++ b/control/src/cache/configuration.rs @@ -11,6 +11,7 @@ pub struct Configuration { pub default_display_page: DisplayPage, pub position_reset_mapping: PositionResetMapping, pub play_pause_mapping: PlayPauseMapping, + pub tap_interval_denominator: usize, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -38,6 +39,7 @@ impl Default for Configuration { default_display_page: DisplayPage::Heads, position_reset_mapping: None, play_pause_mapping: None, + tap_interval_denominator: 1, } } } diff --git a/control/src/cache/display.rs b/control/src/cache/display.rs index 5dc5fd5..cc5be50 100644 --- a/control/src/cache/display.rs +++ b/control/src/cache/display.rs @@ -42,6 +42,7 @@ pub enum ConfigurationScreen { Rewind((usize, usize)), DefaultScreen(usize), ControlMapping(Option), + TapIntervalDenominator(usize), } #[derive(Debug, Clone, Copy)] @@ -241,6 +242,9 @@ fn ticked_dialog(menu: DialogScreen) -> DialogScreen { ConfigurationScreen::ControlMapping(mapping) => { ticked_configuration_control_mapping(mapping) } + ConfigurationScreen::TapIntervalDenominator(denominator) => { + ticked_tap_interval_denominator(denominator) + } }, DialogScreen::Calibration(calibration) => match calibration { CalibrationScreen::SelectOctave1(i, cycles) => ticked_calibration_1(i, cycles), @@ -267,6 +271,10 @@ fn ticked_configuration_control_mapping(mapping: Option) -> DialogScreen DialogScreen::Configuration(ConfigurationScreen::ControlMapping(mapping)) } +fn ticked_tap_interval_denominator(denominator: usize) -> DialogScreen { + DialogScreen::Configuration(ConfigurationScreen::TapIntervalDenominator(denominator)) +} + fn ticked_calibration_1(i: usize, mut cycles: u32) -> DialogScreen { cycles = if cycles > 240 * 6 { 0 } else { cycles + 1 }; DialogScreen::Calibration(CalibrationScreen::SelectOctave1(i, cycles)) @@ -402,6 +410,16 @@ fn leds_for_configuration(configuration: &ConfigurationScreen) -> [bool; 8] { } leds } + ConfigurationScreen::TapIntervalDenominator(denominator) => { + let index = match *denominator { + 16 => 0, + 8 => 1, + 4 => 2, + 1 => 3, + _ => unreachable!(), + }; + index_to_leds(index) + } } } diff --git a/control/src/store.rs b/control/src/store.rs index e486d62..e713f5b 100644 --- a/control/src/store.rs +++ b/control/src/store.rs @@ -441,6 +441,12 @@ impl Store { return (draft, Some(screen)); } + if let Some(screen) = + update_tap_interval_denominator(&mut draft, &mut self.input.head[1].pan) + { + return (draft, Some(screen)); + } + (draft, None) } @@ -601,6 +607,28 @@ fn update_play_pause_mapping( } } +fn update_tap_interval_denominator( + draft: &mut Configuration, + pot: &mut Pot, +) -> Option { + let pot_active = pot.activation_movement(); + if !pot_active { + return None; + } + + let pot_value = pot.value(); + let index = (pot_value * 3.999) as usize; + let denominator = match index { + 0 => 16, + 1 => 8, + 2 => 4, + 3 => 1, + _ => unreachable!(), + }; + draft.tap_interval_denominator = denominator; + Some(ConfigurationScreen::TapIntervalDenominator(denominator)) +} + fn f32_to_index_of_4(x: f32) -> usize { if x < 0.25 { 0 diff --git a/manual/user/manual.tex b/manual/user/manual.tex index 3873b1c..e3d86c1 100644 --- a/manual/user/manual.tex +++ b/manual/user/manual.tex @@ -553,10 +553,10 @@ \subsection{Default display page} Select what should be visualized on the display when pots are inactive. -\textbf{Position within the loop} -- the LEDs blink in round-robin fashion, - representing the current position within the loop. This is the default. +\textbf{1. Position within the loop} -- the LEDs blink in round-robin fashion, + representing the current position within the delay loop. This is the default. -\textbf{Active heads} -- the top and bottom rows of LEDs represent heads with +\textbf{2. Active heads} -- the top and bottom rows of LEDs represent heads with active playback and feedback respectively. While in the configuration menu, turn the SPEED knob to select the default page. @@ -582,6 +582,37 @@ \subsection{Play/pause trigger} control input for this mapping. Turning it all the way to the left will disable this mapping. +\end{minipage}% +\begin{minipage}{0.05\textwidth} +\phantom{ } +\end{minipage}% +% Right column +\begin{minipage}[t]{0.45\textwidth} +\setlength{\parskip}{6pt} + +\subsection{Tap/clock-in interval} + +Configure the length of the tap/clock-in interval. Using a shorter interval +makes dialing in longer delay lengths easier. Setting the right interval +may also provide more intuitive control of tempo for cases where you count +beats and bars. + +\textbf{1. 1/16 of the delay length} -- the delay is four times as long as the + the time it takes to tap-in. This is as if you counted-in 4 bars long + sequence. + +\textbf{2. 1/8 of the delay length} -- the delay is twice as long as the time + it takes to tap-in. This is as if you counted-in 2 bars long sequence. + +\textbf{3. 1/4 of the delay length} -- the length of the delay is the same as + the total time it takes to tap-in. + +\textbf{4. Full delay length} -- the length of the delay is equal to the + interval between each of the taps. + +While in the configuration menu, turn the second PAN knob to select the desired +interval. + \end{minipage} \newpage @@ -701,7 +732,8 @@ \section{Changelog} & New filter placements \\ v1.3 & The status LED blinks three times \\ & Default display can be customized \\ - & Delay position can be reset + & Delay position can be reset \\ + & Configure the tap/delay length ratio \end{tabular} \end{minipage}