]> git.huck.website - cellseq.git/commitdiff
added: new display and controls
authorHuck Boles <huck@huck.website>
Wed, 28 Jun 2023 20:34:18 +0000 (15:34 -0500)
committerHuck Boles <huck@huck.website>
Wed, 28 Jun 2023 20:34:18 +0000 (15:34 -0500)
src/display.rs [new file with mode: 0644]
src/lib.rs
src/main.rs
src/map.rs

diff --git a/src/display.rs b/src/display.rs
new file mode 100644 (file)
index 0000000..48219e9
--- /dev/null
@@ -0,0 +1,148 @@
+use iced::{
+    theme,
+    widget::{button, column, row, slider, text},
+    Alignment, Element, Length,
+};
+
+use crate::Message;
+
+pub fn top_controls<'a>(
+    is_playing: bool,
+    bpm: usize,
+    is_looping: bool,
+    loop_len: usize,
+    step_num: usize,
+) -> Element<'a, Message> {
+    let play_button =
+        button(if is_playing { "pause" } else { "play" }).on_press(Message::TogglePlayback);
+
+    let loop_controls = row![
+        button(if is_looping { "free" } else { "loop" }).on_press(Message::ToggleLoop),
+        button("-").on_press(Message::LoopLength(loop_len.saturating_sub(1))),
+        text(if is_looping {
+            format!("{step_num}/{loop_len}")
+        } else {
+            format!("{loop_len}")
+        }),
+        button("+").on_press(Message::LoopLength(loop_len.saturating_add(1)))
+    ]
+    .spacing(10);
+
+    let speed_controls = row![
+        button("<<").on_press(Message::SpeedChanged(bpm.saturating_sub(5))),
+        button("<").on_press(Message::SpeedChanged(bpm.saturating_sub(1))),
+        text(format!("{bpm}")).size(16),
+        button(">").on_press(Message::SpeedChanged(bpm.saturating_add(1))),
+        button(">>").on_press(Message::SpeedChanged(bpm.saturating_add(5))),
+    ]
+    .width(Length::Fill)
+    .align_items(Alignment::Center)
+    .spacing(10);
+
+    let other_controls = row![button("quit")
+        .on_press(Message::Quit)
+        .style(theme::Button::Destructive),]
+    .width(Length::Fill)
+    .align_items(Alignment::Center)
+    .spacing(10);
+
+    row![play_button, loop_controls, speed_controls, other_controls]
+        .padding(10)
+        .spacing(40)
+        .align_items(Alignment::Center)
+        .into()
+}
+
+pub fn bottom_controls<'a>(
+    prob: f32,
+    rand: f32,
+    vmin: u8,
+    vmax: u8,
+    chan: u8,
+) -> Element<'a, Message> {
+    let probability = row![
+        slider(0.0..=100.0, prob * 100.0, |x| Message::ProbChanged(
+            x / 100.0
+        )),
+        text(format!("{prob}")),
+        text("probability a cell gets triggered")
+            .style(theme::Text::Color(iced::Color::from_rgb8(0x40, 0x40, 0x40)))
+    ]
+    .padding(10)
+    .spacing(10)
+    .align_items(Alignment::Center);
+
+    let randomize = row![
+        slider(0.0..=100.0, rand * 100.0, |x| Message::RandChanged(
+            x / 100.0
+        )),
+        text(format!("{rand}")),
+        text("percent of board to fill on randomize")
+            .style(theme::Text::Color(iced::Color::from_rgb8(0x40, 0x40, 0x40)))
+    ]
+    .padding(10)
+    .spacing(10)
+    .align_items(Alignment::Center);
+
+    let map_controls = row![
+        button("save")
+            .on_press(Message::Save)
+            .style(theme::Button::Positive),
+        button("clear")
+            .on_press(Message::Clear)
+            .style(theme::Button::Destructive),
+        button("reset")
+            .on_press(Message::Reset)
+            .style(theme::Button::Secondary),
+        button("random")
+            .on_press(Message::Randomize)
+            .style(theme::Button::Primary),
+    ]
+    .padding(10)
+    .spacing(10)
+    .align_items(Alignment::Center);
+
+    let map = column![map_controls, randomize];
+
+    let velocity = column![
+        row![
+            slider(0..=127, vmin, Message::NewVMin),
+            text(format!("{vmin}")),
+            text("minimum velocity")
+                .style(theme::Text::Color(iced::Color::from_rgb8(0x40, 0x40, 0x40)))
+        ]
+        .padding(10)
+        .spacing(10)
+        .align_items(Alignment::Center),
+        row![
+            slider(0..=127, vmax, Message::NewVMax),
+            text(format!("{vmax}")),
+            text("maximum velocity")
+                .style(theme::Text::Color(iced::Color::from_rgb8(0x40, 0x40, 0x40)))
+        ]
+        .padding(10)
+        .spacing(10)
+        .align_items(Alignment::Center)
+    ]
+    .padding(10)
+    .spacing(10)
+    .align_items(Alignment::Center);
+
+    let midi = row![
+        button("-").on_press(Message::ChannelChange(chan.saturating_sub(1))),
+        text(format!("{chan}")),
+        button("+").on_press(Message::ChannelChange(chan.saturating_add(1))),
+        velocity
+    ]
+    .padding(10)
+    .spacing(10)
+    .align_items(Alignment::Center);
+
+    column![probability, map, midi]
+        .width(Length::Fill)
+        .height(Length::Fill)
+        .padding(10)
+        .spacing(40)
+        .align_items(Alignment::Center)
+        .into()
+}
index aacac03d397de1438197b499e5ea63a6c815400e..09525af576fafa8f594f59790ad84392a7b07c44 100644 (file)
@@ -1,8 +1,8 @@
 use iced::{
     executor,
-    theme::{self, Theme},
+    theme::Theme,
     time,
-    widget::{button, column, container, row, text},
+    widget::{column, container, row},
     {Alignment, Application, Command, Element, Length, Point, Subscription},
 };
 
@@ -10,10 +10,12 @@ use itertools::Itertools;
 use rustc_hash::FxHashSet;
 use std::time::{Duration, Instant};
 
+mod display;
 mod map;
 mod mask;
 mod midi;
 
+use display::*;
 use map::*;
 use mask::*;
 pub use midi::*;
@@ -61,6 +63,11 @@ pub struct CellSeq {
     is_looping: bool,
     loop_len: usize,
     step_num: usize,
+    probability: f32,
+    randomness: f32,
+    velocity_min: u8,
+    velocity_max: u8,
+    channel: u8,
 }
 
 #[derive(Debug, Clone)]
@@ -77,6 +84,11 @@ pub enum Message {
     SpeedChanged(usize),
     ToggleLoop,
     LoopLength(usize),
+    ProbChanged(f32),
+    RandChanged(f32),
+    NewVMin(u8),
+    NewVMax(u8),
+    ChannelChange(u8),
     Quit,
 }
 
@@ -116,8 +128,14 @@ impl Application for CellSeq {
                     self.map.tick()
                 };
 
-                let midi = self.mask.tick(map);
+                let midi = self.mask.tick(map.clone());
+
                 let mut commands = Vec::new();
+
+                commands.push(Command::perform(async move { map }, |m| {
+                    Message::Map(map::Message::Ticked(m))
+                }));
+
                 for message in midi {
                     commands.push(Command::perform(async move { message }, |m| {
                         Message::Midi(m)
@@ -134,7 +152,7 @@ impl Application for CellSeq {
             }
             Message::SpeedChanged(bpm) => self.bpm = bpm,
             Message::Clear => self.map.clear(),
-            Message::Randomize => self.map.randomize(),
+            Message::Randomize => self.map.randomize(self.randomness),
             Message::Reset => self.map.reset(),
             Message::Save => self.map.save(),
             Message::ToggleLoop => {
@@ -145,6 +163,11 @@ impl Application for CellSeq {
             }
             Message::LoopLength(len) => self.loop_len = len,
             Message::Quit => todo!(),
+            Message::ProbChanged(prob) => self.probability = prob,
+            Message::RandChanged(rand) => self.randomness = rand,
+            Message::NewVMin(v) => self.velocity_min = v,
+            Message::NewVMax(v) => self.velocity_max = v,
+            Message::ChannelChange(chan) => self.channel = chan,
         }
 
         Command::none()
@@ -159,13 +182,14 @@ impl Application for CellSeq {
     }
 
     fn view(&self) -> Element<Message> {
-        let controls = view_controls(
+        let top = top_controls(
             self.is_playing,
             self.bpm,
             self.is_looping,
             self.loop_len,
             self.step_num,
         );
+
         let map = row![
             self.map.view().map(Message::Map),
             self.mask.view().map(Message::Mask)
@@ -175,7 +199,15 @@ impl Application for CellSeq {
         .spacing(40)
         .padding(20);
 
-        let content = column![controls, map,];
+        let bottom = bottom_controls(
+            self.probability,
+            self.randomness,
+            self.velocity_min,
+            self.velocity_max,
+            self.channel,
+        );
+
+        let content = column![top, map, bottom];
 
         container(content)
             .width(Length::Fill)
@@ -187,60 +219,3 @@ impl Application for CellSeq {
         Theme::Dark
     }
 }
-
-fn view_controls<'a>(
-    is_playing: bool,
-    bpm: usize,
-    is_looping: bool,
-    loop_len: usize,
-    step_num: usize,
-) -> Element<'a, Message> {
-    let playback_controls = row![
-        button(if is_playing { "pause" } else { "play" }).on_press(Message::TogglePlayback),
-        button(if is_looping { "free" } else { "loop" }).on_press(Message::ToggleLoop),
-        button("-").on_press(Message::LoopLength(loop_len.saturating_sub(1))),
-        text(if is_looping {
-            format!("{step_num}/{loop_len}")
-        } else {
-            format!("{loop_len}")
-        }),
-        button("+").on_press(Message::LoopLength(loop_len.saturating_add(1)))
-    ]
-    .spacing(10);
-
-    let speed_controls = row![
-        button("<<").on_press(Message::SpeedChanged(bpm.saturating_sub(5))),
-        button("<").on_press(Message::SpeedChanged(bpm.saturating_sub(1))),
-        text(format!("{bpm}")).size(16),
-        button(">").on_press(Message::SpeedChanged(bpm.saturating_add(1))),
-        button(">>").on_press(Message::SpeedChanged(bpm.saturating_add(1))),
-    ]
-    .width(Length::Fill)
-    .align_items(Alignment::Center)
-    .spacing(10);
-
-    let other_controls = row![
-        button("save").on_press(Message::Save),
-        button("reset")
-            .on_press(Message::Reset)
-            .style(theme::Button::Secondary),
-        button("random")
-            .on_press(Message::Randomize)
-            .style(theme::Button::Positive),
-        button("clear")
-            .on_press(Message::Clear)
-            .style(theme::Button::Destructive),
-        button("quit")
-            .on_press(Message::Quit)
-            .style(theme::Button::Destructive),
-    ]
-    .width(Length::Fill)
-    .align_items(Alignment::Center)
-    .spacing(10);
-
-    row![playback_controls, speed_controls, other_controls]
-        .padding(10)
-        .spacing(40)
-        .align_items(Alignment::Center)
-        .into()
-}
index 950a6322a111af45243a7c4af57bc55dd1fe22af..13582ca14b4e45c6164c96b0430f8c3b5f61b12a 100644 (file)
@@ -10,29 +10,29 @@ pub fn main() -> Result<()> {
     let (midi_snd, mut midi_rcv) = channel::<Option<u8>>(256);
 
     // setting up jack client
-    let (jack_client, _status) = Client::new("cellseq", ClientOptions::empty())?;
-    let mut midi_port = jack_client.register_port("cellseq_midi", MidiOut::default())?;
+    // let (jack_client, _status) = Client::new("cellseq", ClientOptions::empty())?;
+    // let mut midi_port = jack_client.register_port("cellseq_midi", MidiOut::default())?;
 
-    let process_handler = ClosureProcessHandler::new(move |_: &Client, scope: &ProcessScope| {
-        let mut writer = midi_port.writer(scope);
-        let mut bytes = Vec::new();
+    // let process_handler = ClosureProcessHandler::new(move |_: &Client, scope: &ProcessScope| {
+    //     let mut writer = midi_port.writer(scope);
+    //     let mut bytes = Vec::new();
 
-        while let Ok(Some(byte)) = midi_rcv.try_recv() {
-            bytes.push(byte);
-        }
+    //     while let Ok(Some(byte)) = midi_rcv.try_recv() {
+    //         bytes.push(byte);
+    //     }
 
-        let time = scope.frames_since_cycle_start();
-        writer
-            .write(&RawMidi {
-                time,
-                bytes: &bytes[0..bytes.len()],
-            })
-            .unwrap();
+    //     let time = scope.frames_since_cycle_start();
+    //     writer
+    //         .write(&RawMidi {
+    //             time,
+    //             bytes: &bytes[0..bytes.len()],
+    //         })
+    //         .unwrap();
 
-        Control::Continue
-    });
+    //     Control::Continue
+    // });
 
-    let jack = jack_client.activate_async((), process_handler)?;
+    // let jack = jack_client.activate_async((), process_handler)?;
 
     let midi = MidiLink::new(midi_snd);
 
@@ -47,7 +47,7 @@ pub fn main() -> Result<()> {
         ..Settings::default()
     })?;
 
-    jack.deactivate()?;
+    // jack.deactivate()?;
 
     Ok(())
 }
index 259c3ab3443f521bf1c895b35e723f556868a6b4..2b6a559e32094ccadc2da16a43466f8b81b9634f 100644 (file)
@@ -100,10 +100,10 @@ impl Map {
         self.seed = self.cells.clone();
     }
 
-    pub fn randomize(&mut self) {
+    pub fn randomize(&mut self, level: f32) {
         self.cells.clear();
         for (i, j) in (-32..=32).cartesian_product(-32..=32) {
-            if random::<f32>() > 0.5 {
+            if random::<f32>() < level {
                 self.cells.insert(Cell { i, j });
             }
         }