From 1b94695d5778e19e39f99c87cc342850abfb905b Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Thu, 2 May 2024 22:19:17 +0200
Subject: [PATCH] master wave

---
 src/main.rs               | 89 ++++++++++++++++++++++++++-------------
 src/patterns/alternate.rs |  2 +-
 src/patterns/mod.rs       |  4 +-
 src/patterns/wave_fade.rs | 43 +++++++++++++++++++
 src/scene_library.rs      | 32 +++++++++++++-
 src/waveform.rs           | 37 ++++++++++++++++
 6 files changed, 173 insertions(+), 34 deletions(-)
 create mode 100644 src/patterns/wave_fade.rs
 create mode 100644 src/waveform.rs

diff --git a/src/main.rs b/src/main.rs
index 3b079e1..28fa5b7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -19,6 +19,7 @@ mod setup;
 mod view;
 mod stripe_driver;
 mod jack;
+mod waveform;
 
 mod patterns;
 mod scene_library;
@@ -30,21 +31,24 @@ use crate::{
     stripe_driver::StripeDriver,
     util::get_angle,
 
-    scene_library::SceneLibrary
+    scene_library::SceneLibrary,
+    waveform::Waveform
 };
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct Inputs {
     t: Duration,
     transition_time: Duration,
 
     scene_select: usize,
-
-    intensity: f32,
     cycle_len: Duration,
-
     wave_peak: f32,
-    wheel: i32
+
+    master_wave: Option< Waveform >,
+    master_subdivision: i32,
+    master_intensity: f32,
+    wheel: i32,
+    wheel2: i32,
 }
 
 #[async_std::main]
@@ -64,13 +68,16 @@ async fn main() {
         Inputs {
             t: Duration::from_millis(0),
             transition_time: Duration::from_millis(0),
-
-            intensity: 0.5,
             cycle_len: Duration::from_millis(300),
             wave_peak: 0.5,
 
             scene_select: 0,
-            wheel: 0
+
+            master_wave: None,
+            master_subdivision: 0,
+            master_intensity: 1.0,
+            wheel: 0,
+            wheel2: 0
         }
     ));
 
@@ -118,7 +125,7 @@ async fn main() {
         lighting_setup.update_buffers();
 
         if active {
-            for i in 1..4 {
+            for i in 1..5 {
                 lighting_setup.update_outputs(i);
             }
         }
@@ -148,6 +155,7 @@ async fn main() {
                         winit::keyboard::Key::Character(c) => {
                             eprintln!("pressed {}", c);
 
+                            let mut inputs = inputs.write().unwrap();
                             match &c[0..1] {
                                 "x" => {
                                     // tap tempo
@@ -155,61 +163,84 @@ async fn main() {
                                     last_tap = std::time::Instant::now();
 
                                     if (last_tap - old_tap) < Duration::from_millis(20000) {
-                                        inputs.write().unwrap().cycle_len = last_tap - old_tap;
+                                        inputs.cycle_len = last_tap - old_tap;
                                     }
                                 }
 
                                 "q" => {
                                     // sync
-                                    inputs.write().unwrap().t = Duration::from_millis(0);
+                                    inputs.t = Duration::from_millis(0);
                                     tbegin = std::time::Instant::now();
                                 },
 
                                 "0" => {
-                                    inputs.write().unwrap().scene_select = 0;
+                                    inputs.scene_select = 0;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "1" => {
-                                    inputs.write().unwrap().scene_select = 1;
+                                    inputs.scene_select = 1;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "2" => {
-                                    inputs.write().unwrap().scene_select = 2;
+                                    inputs.scene_select = 2;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "3" => {
-                                    inputs.write().unwrap().scene_select = 3;
+                                    inputs.scene_select = 3;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "4" => {
-                                    inputs.write().unwrap().scene_select = 4;
+                                    inputs.scene_select = 4;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "5" => {
-                                    inputs.write().unwrap().scene_select = 5;
+                                    inputs.scene_select = 5;
                                     transition_begin = std::time::Instant::now();
                                 },
                                 "6" => {
-                                    inputs.write().unwrap().scene_select = 6;
+                                    inputs.scene_select = 6;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "7" => {
-                                    inputs.write().unwrap().scene_select = 7;
+                                    inputs.scene_select = 7;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "8" => {
-                                    inputs.write().unwrap().scene_select = 8;
+                                    inputs.scene_select = 8;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "9" => {
-                                    inputs.write().unwrap().scene_select = 9;
+                                    inputs.scene_select = 9;
                                     transition_begin = std::time::Instant::now();
                                 }
                                 "a" => {
-                                    inputs.write().unwrap().scene_select = 10;
+                                    inputs.scene_select = 10;
                                     transition_begin = std::time::Instant::now();
                                 }
-                                "m" => {
+                                "p" => {
+                                    inputs.scene_select = 11;
+                                    transition_begin = std::time::Instant::now();
+                                }
+                                "r" => { inputs.master_wave = match inputs.master_wave {
+                                    None => Some(Waveform::Sine),
+                                    Some(Waveform::Sine) => Some(Waveform::Triangle),
+                                    Some(Waveform::Triangle) => Some(Waveform::Square),
+                                    Some(Waveform::Square) => Some(Waveform::Sawtooth),
+                                    Some(Waveform::Sawtooth) => None
+                                }
+                                }
+                                "," => { inputs.master_wave = None; }
+                                "n" => { inputs.master_intensity += 0.1; }
+                                "m" => { inputs.master_intensity -= 0.1; }
+                                "s" => { inputs.master_subdivision +=1; }
+                                "b" => { inputs.master_subdivision -=1; }
+                                "o" => { inputs.wheel +=1; }
+                                "z" => { inputs.wheel -=1; }
+                                "e" => { inputs.wheel2 += 1; }
+                                "p"=> { inputs.wheel2 -= 1; }
+
+                                "-" => {inputs.master_intensity *= -1.0; }
+                                "." => {
                                     if active {
                                         eprintln!("DEACTIVATED");
                                         active = false;
@@ -218,15 +249,13 @@ async fn main() {
                                         eprintln!("ACTIVATED");
                                     }
                                 }
-                                "+" => {
-                                    inputs.write().unwrap().wheel +=1;
-                                }
-                                "-" => {
-                                    inputs.write().unwrap().wheel -=1;
-                                }
 
                                 _=>{}
                             }
+
+                            eprintln!("--------------");
+                            eprintln!("updated inputs:\n {:?}", inputs);
+                            eprintln!("--------------");
                         }
                         _ => {}
                     }
diff --git a/src/patterns/alternate.rs b/src/patterns/alternate.rs
index 2e4f3dd..52f57d8 100644
--- a/src/patterns/alternate.rs
+++ b/src/patterns/alternate.rs
@@ -35,7 +35,7 @@ impl ColorGrid for Alternate {
             if t < 0.5 {
                 Rgb::new(0.05, 0.05, 0.05)
             } else {
-                Rgb::new(0.3, 0.3, 0.6)
+                Rgb::new(0.0, 0.0, 0.6)
             }   
         }
 
diff --git a/src/patterns/mod.rs b/src/patterns/mod.rs
index 98529f0..ea1796a 100644
--- a/src/patterns/mod.rs
+++ b/src/patterns/mod.rs
@@ -5,6 +5,7 @@ pub mod arctic_rain;
 pub mod pastel_fade;
 pub mod gastel_fade;
 pub mod wheel;
+pub mod wave_fade;
 pub mod alternate;
 
 #[path = "uboot_prüfstand_fade.rs"]
@@ -16,9 +17,10 @@ pub use {
     arctic_rain::ArcticRain,
     pastel_fade::PastelFade,
     gastel_fade::GastelFade,
+    wave_fade::WaveFade,
     uboot::UbootPrüfstandFade,
     wheel::Wheel,
     alternate::Alternate
 };
 
-    
+
diff --git a/src/patterns/wave_fade.rs b/src/patterns/wave_fade.rs
new file mode 100644
index 0000000..d71643f
--- /dev/null
+++ b/src/patterns/wave_fade.rs
@@ -0,0 +1,43 @@
+use {
+    std::num::NonZeroU32,
+    std::sync::{Arc, RwLock, Mutex},
+    std::rc::Rc,
+    winit::event::{Event, WindowEvent},
+    winit::event_loop::{ControlFlow, EventLoop},
+    winit::window::WindowBuilder,
+    prisma::{Rgb,Hsv,FromColor, Lerp},
+    cgmath::{Point2, Vector2},
+    std::time::Duration,
+    angle::Turns,
+
+    crate::{Inputs, view::ColorGrid, util::get_angle, waveform::Waveform}
+};
+
+pub struct WaveFade { pub inputs: Arc<RwLock< Inputs >>,
+                        pub hue: f32,
+}
+
+impl ColorGrid for WaveFade {
+    fn get(&self, p: &Vector2<f32>) -> Rgb<f32> {
+        let inputs = self.inputs.read().unwrap().clone();
+
+        let nt = ( inputs.t.as_millis() as f32 / inputs.cycle_len.as_millis() as f32 );
+
+        let i =
+            match inputs.wheel % 4 {
+                0 => Waveform::Sine{}.get_norm(nt),
+                1 => Waveform::Triangle{}.get_norm(nt),
+                2 => Waveform::Sawtooth{}.get_norm(nt),
+                3 => Waveform::Square{}.get_norm(nt),
+                _ => 0.0
+            };
+
+        Rgb::from_color(
+            &Hsv::<f32, Turns<f32>>::new(
+                Turns( self.hue ),
+                0.5,
+                i
+            )
+        )
+    }
+}
diff --git a/src/scene_library.rs b/src/scene_library.rs
index 3c703c1..a6c2490 100644
--- a/src/scene_library.rs
+++ b/src/scene_library.rs
@@ -39,7 +39,7 @@ impl SceneLibrary {
                 Box::new( Strobe{ inputs: inputs.clone(), subdivision: 16 } ),
 
                 // others
-                Box::new( PastelFade{ inputs: inputs.clone() } ),
+                Box::new( WaveFade{ inputs: inputs.clone(), hue: 0.5 } ),
                 Box::new( UbootPrüfstandFade{ inputs: inputs.clone() } ),
                 Box::new( ArcticRain{ inputs: inputs.clone() } ),
 
@@ -48,6 +48,7 @@ impl SceneLibrary {
 
 
                 Box::new( Alternate{ inputs: inputs.clone() } ),
+                Box::new( PastelFade{ inputs: inputs.clone() } ),
             ],
             current_scene: RwLock::new(0),
             inputs,
@@ -62,9 +63,35 @@ impl ColorGrid for SceneLibrary {
 
         let sc = *self.current_scene.read().unwrap();
 
+        let mut intensity: f32 = inputs.master_intensity;
+        if intensity > 1.0 {
+            intensity = 1.0;
+        }
+        if intensity < -1.0 {
+            intensity = -1.0;
+        }
+
+        if let Some(w) = inputs.master_wave {
+            intensity *= w.get_doub(
+                inputs.t.as_millis() as f32
+                    / inputs.cycle_len.as_millis() as f32
+            );
+        }
+
+
         if inputs.scene_select == sc {
             // display only one animation
-            self.library[ sc ].get(p)
+            let mut hsv = Hsv::from_color(
+                &self.library[ sc ].get(p)
+            );
+
+            hsv = Hsv::<f32>::new(
+                hsv.hue(),
+                hsv.saturation(),
+                hsv.value() * (0.5 + 0.5*intensity)
+            );
+
+            Rgb::from_color(&hsv)
         } else {
             // display transition
             let cur_scene = &self.library[ sc ];
@@ -83,6 +110,7 @@ impl ColorGrid for SceneLibrary {
                     &nxt_scene.get(p),
                     w
                 )
+                
         }
     }
 }
diff --git a/src/waveform.rs b/src/waveform.rs
new file mode 100644
index 0000000..7c7527a
--- /dev/null
+++ b/src/waveform.rs
@@ -0,0 +1,37 @@
+
+#[derive(Clone, Debug)]
+pub enum Waveform {
+    Triangle,
+    Sawtooth,
+    Square,
+    Sine,
+}
+
+impl Waveform {
+    pub fn get_doub(&self, x: f32) -> f32 {
+        self.get_norm(x) * 2.0 - 1.0
+    }
+
+    pub fn get_norm(&self, x: f32) -> f32 {
+        match self {
+            Waveform::Sine => 0.5 + 0.5*(x * 2.0*3.1415926).sin(),
+            Waveform::Square =>
+                if x % 1.0 < 0.5 {
+                    0.0
+                } else {
+                    1.0
+                }
+            Waveform::Sawtooth => {
+                x % 1.0
+            }
+            Waveform::Triangle => {
+                if (x%1.0) > 0.5 {
+                    1.0-(x%1.0)
+                } else {
+                    x%1.0
+                }
+            }
+        }
+    }
+}
+