Skip to content

Commit

Permalink
add option screens
Browse files Browse the repository at this point in the history
  • Loading branch information
vk2seb committed Nov 12, 2023
1 parent 66015d3 commit 5873287
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 88 deletions.
45 changes: 30 additions & 15 deletions firmware/litex-fw/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ impl State {
let voice = &self.voice_manager.voices[n_voice];
shifter[n_voice].set_pitch(voice.pitch);
lpf[n_voice].set_cutoff((voice.amplitude * 8000f32) as i16);
lpf[n_voice].set_resonance(opts.resonance.value);
lpf[n_voice].set_resonance(opts.adsr.resonance.value);
}
}
}
Expand Down Expand Up @@ -367,17 +367,31 @@ where
let opts_view = opts.view();

let vy: usize = 205;

// Draw the current screen text
Text::with_alignment(
opts.screen.value.into(),
Point::new(5, (vy-10) as i32),
match (opts.selected(), opts.modify) {
(None, _) => font_small_white,
_ => font_small_grey,
},
Alignment::Left,
).draw(d)?;

for (n, opt) in opts_view.iter().enumerate() {
let mut font = font_small_grey;
if opts.selected == n {
font = font_small_white;
if opts.modify {
Text::with_alignment(
"-",
Point::new(62, (vy+10*n) as i32),
font,
Alignment::Left,
).draw(d)?;
if let Some(n_selected) = opts.selected() {
if n_selected == n {
font = font_small_white;
if opts.modify {
Text::with_alignment(
"-",
Point::new(62, (vy+10*n) as i32),
font,
Alignment::Left,
).draw(d)?;
}
}
}
Text::with_alignment(
Expand Down Expand Up @@ -694,9 +708,11 @@ fn main() -> ! {
state.trace.len_us())
});

for (n_voice, voice) in voices.iter().enumerate() {
draw_voice(&mut disp, (55+37*n_voice) as u32,
n_voice as u32, voice).ok();
if opts.screen.value == opt::Screen::Adsr {
for (n_voice, voice) in voices.iter().enumerate() {
draw_voice(&mut disp, (55+37*n_voice) as u32,
n_voice as u32, voice).ok();
}
}

draw_options(&mut disp, &opts).ok();
Expand All @@ -706,8 +722,7 @@ fn main() -> ! {
draw_ms(&mut disp, irq0_len_us,
Point::new(5, 245), character_style).ok();

{

if opts.screen.value == opt::Screen::Scope {
let samples = critical_section::with(|cs| {
let scope = &mut oscope.borrow_ref_mut(cs);
if scope.full() {
Expand Down
207 changes: 137 additions & 70 deletions firmware/litex-fw/src/opt.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use heapless::String;
use heapless::Vec;

use strum_macros::{EnumIter, IntoStaticStr};

pub type OptionString = String<32>;
pub type OptionView<'a> = Vec<&'a dyn OptionTrait, 10>;
pub type OptionViewMut<'a> = Vec<&'a mut dyn OptionTrait, 10>;

pub trait OptionTrait {
fn name(&self) -> &OptionString;
Expand Down Expand Up @@ -34,62 +37,92 @@ pub enum EnumTest {
ValueC
}

#[derive(Clone, Copy, PartialEq, EnumIter, IntoStaticStr)]
#[strum(serialize_all = "SCREAMING-KEBAB-CASE")]
pub enum Screen {
Adsr,
Scope,
}


#[derive(Clone)]
pub struct Options {
pub modify: bool,
pub selected: usize,
pub struct AdsrOptions {
pub selected: Option<usize>,
pub attack_ms: NumOption<u32>,
pub decay_ms: NumOption<u32>,
pub release_ms: NumOption<u32>,
pub resonance: NumOption<i16>,
}

#[derive(Clone)]
pub struct ScopeOptions {
pub selected: Option<usize>,
pub delay_len: NumOption<u32>,
pub enum_test: EnumOption<EnumTest>,
}

#[derive(Clone)]
pub struct Options {
pub modify: bool,
pub screen: EnumOption<Screen>,

pub adsr: AdsrOptions,
pub scope: ScopeOptions,
}

impl Options {
pub fn new() -> Options {
Options {
modify: false,
selected: 0,
delay_len: NumOption{
name: "delayln".into(),
value: 511,
step: 1,
min: 128,
max: 511,
},
attack_ms: NumOption{
name: "attack".into(),
value: 100,
step: 50,
min: 0,
max: 5000,
modify: true,
screen: EnumOption {
name: "screen".into(),
value: Screen::Adsr,
},
decay_ms: NumOption{
name: "decay".into(),
value: 100,
step: 50,
min: 0,
max: 5000,
},
release_ms: NumOption{
name: "release".into(),
value: 300,
step: 50,
min: 0,
max: 5000,
},
resonance: NumOption{
name: "reso".into(),
value: 10000,
step: 1000,
min: 0,
max: 20000,
},
enum_test: EnumOption{
name: "enumt".into(),
value: EnumTest::ValueA,
adsr: AdsrOptions {
selected: None,
attack_ms: NumOption{
name: "attack".into(),
value: 100,
step: 50,
min: 0,
max: 5000,
},
decay_ms: NumOption{
name: "decay".into(),
value: 100,
step: 50,
min: 0,
max: 5000,
},
release_ms: NumOption{
name: "release".into(),
value: 300,
step: 50,
min: 0,
max: 5000,
},
resonance: NumOption{
name: "reso".into(),
value: 10000,
step: 1000,
min: 0,
max: 20000,
},
},
scope: ScopeOptions {
selected: None,
delay_len: NumOption{
name: "delayln".into(),
value: 511,
step: 1,
min: 128,
max: 511,
},
enum_test: EnumOption{
name: "enumt".into(),
value: EnumTest::ValueA,
},
}
}
}

Expand All @@ -98,45 +131,79 @@ impl Options {
}

pub fn tick_up(&mut self) {
let selected = self.selected;
if self.modify {
self.view_mut()[selected].tick_up();
} else if selected < self.view().len()-1 {
self.selected = selected + 1;
if let Some(n_selected) = self.selected() {
if self.modify {
self.view_mut()[n_selected].tick_up();
} else if n_selected < self.view().len()-1 {
*self.selected_mut() = Some(n_selected + 1);
}
} else if self.modify {
self.screen.tick_up();
} else if !self.view().is_empty() {
*self.selected_mut() = Some(0);
}
}

pub fn tick_down(&mut self) {
let selected = self.selected;
if self.modify {
self.view_mut()[selected].tick_down();
} else if selected != 0 {
self.selected = selected - 1;
if let Some(n_selected) = self.selected() {
if self.modify {
self.view_mut()[n_selected].tick_down();
} else if n_selected != 0 {
*self.selected_mut() = Some(n_selected - 1);
} else {
*self.selected_mut() = None;
}
} else if self.modify {
self.screen.tick_down();
}
}

pub fn selected(&self) -> Option<usize> {
match self.screen.value {
Screen::Adsr => self.adsr.selected,
Screen::Scope => self.scope.selected,
}
}

pub fn selected_mut(&mut self) -> &mut Option<usize> {
match self.screen.value {
Screen::Adsr => &mut self.adsr.selected,
Screen::Scope => &mut self.scope.selected,
}
}

#[allow(dead_code)]
pub fn view(&self) -> [& dyn OptionTrait; 6] {
[
&self.enum_test,
&self.attack_ms,
&self.decay_ms,
&self.release_ms,
&self.resonance,
&self.delay_len,
]
pub fn view(&self) -> OptionView {
match self.screen.value {
Screen::Adsr => OptionView::from_slice(&[
&self.adsr.attack_ms,
&self.adsr.decay_ms,
&self.adsr.release_ms,
&self.adsr.resonance,
]),
Screen::Scope => OptionView::from_slice(&[
&self.scope.delay_len,
&self.scope.enum_test,
]),
}.unwrap()
}

#[allow(dead_code)]
pub fn view_mut(&mut self) -> [&mut dyn OptionTrait; 6] {
[
&mut self.enum_test,
&mut self.attack_ms,
&mut self.decay_ms,
&mut self.release_ms,
&mut self.resonance,
&mut self.delay_len,
]
fn view_mut(&mut self) -> OptionViewMut {
let mut r = OptionViewMut::new();
match self.screen.value {
Screen::Adsr => {
r.push(&mut self.adsr.attack_ms).ok();
r.push(&mut self.adsr.decay_ms).ok();
r.push(&mut self.adsr.release_ms).ok();
r.push(&mut self.adsr.resonance).ok();
},
Screen::Scope => {
r.push(&mut self.scope.delay_len).ok();
r.push(&mut self.scope.enum_test).ok();
},
}
r
}
}

Expand Down
6 changes: 3 additions & 3 deletions firmware/litex-fw/src/voice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ impl VoiceManager {

if v.adsr.is_none() {
v.adsr = Some( AdsrParams {
attack_ms: opts.attack_ms.value,
decay_ms: opts.decay_ms.value,
release_ms: opts.release_ms.value,
attack_ms: opts.adsr.attack_ms.value,
decay_ms: opts.adsr.decay_ms.value,
release_ms: opts.adsr.release_ms.value,
attack_amplitude: 1.0f32 * (v.velocity as f32 / 128.0f32),
sustain_amplitude: 0.8f32 * (v.velocity as f32 / 128.0f32),
});
Expand Down

0 comments on commit 5873287

Please sign in to comment.