From d2015edcefc713a22e9c1072ca524911e5df1bfa Mon Sep 17 00:00:00 2001
From: moon2 <moon2protonmail@protonmail.com>
Date: Tue, 19 Sep 2023 21:54:43 +0000
Subject: [PATCH] shoegaze: enable chord borrowing from chord organ

harmonic demo: rename to chord organ in flow3r.toml only,
add "tones_readonly" chord tone information to savefile
---
 docs/badge/usage.rst                          |   8 +-
 python_payload/apps/demo_harmonic/__init__.py |   1 +
 python_payload/apps/demo_harmonic/flow3r.toml |   2 +-
 python_payload/apps/shoegaze/__init__.py      | 140 +++++++++---------
 4 files changed, 79 insertions(+), 72 deletions(-)

diff --git a/docs/badge/usage.rst b/docs/badge/usage.rst
index 7eb4192ade..e982b59151 100644
--- a/docs/badge/usage.rst
+++ b/docs/badge/usage.rst
@@ -88,7 +88,7 @@ We ship some noise-making apps by default:
 shoegaze
 ^^^^^^^^
 
-Electric guitar simulator with fuzz and reverb. Tilt for wiggle stick. App button middle switches between render modes: Lo Fi has lower framerate, default has slower input response time. App button left turns delay on and off. Top petals play notes in chord, bottom petals change chord.
+Electric guitar simulator with fuzz and reverb. Tilt for wiggle stick. Top petals play notes in chord, bottom petals change chord. App button left turns delay on and off, app button right checks for chords in the savefile of chord organ and toggles between them if found.
 
 Otamatone
 ^^^^^^^^^
@@ -112,8 +112,8 @@ be reset when passing it, if they're "open" they let the sequencer pass through
 
 Your beat is saved in flash at ``/sys/gay_drums.json`` when exiting gay drums! Make sure to wait until the menu screen appears before turning the power off though :D!
 
-harmonic demo
-^^^^^^^^^^^^^
+chord organ
+^^^^^^^^^^^
 
 A chord organ! The top petals always play the 5 notes of the selected chord.
 
@@ -146,7 +146,7 @@ Samples are saved in flash at ``/sys/samples/tiny_sample_*.wav``.
 
 .. _usage_apps:
 
-Applications
+Apps
 ------------
 
 Audio passthrough
diff --git a/python_payload/apps/demo_harmonic/__init__.py b/python_payload/apps/demo_harmonic/__init__.py
index 160e38bec0..a995239d35 100644
--- a/python_payload/apps/demo_harmonic/__init__.py
+++ b/python_payload/apps/demo_harmonic/__init__.py
@@ -305,6 +305,7 @@ class HarmonicApp(Application):
             chord["nine"] = self.chords[i].nine
             chord["root"] = self.chords[i].root
             chord["voicing"] = self.chords[i].voicing
+            chord["tones_readonly"] = self.chords[i].notes
             if not file_is_different:
                 user_chord = user_settings["chords"][i]
                 if self._file_settings is None:
diff --git a/python_payload/apps/demo_harmonic/flow3r.toml b/python_payload/apps/demo_harmonic/flow3r.toml
index 4b20e89b97..863bc6dedd 100644
--- a/python_payload/apps/demo_harmonic/flow3r.toml
+++ b/python_payload/apps/demo_harmonic/flow3r.toml
@@ -1,5 +1,5 @@
 [app]
-name = "harmonic demo"
+name = "chord organ"
 menu = "Music"
 
 [entry]
diff --git a/python_payload/apps/shoegaze/__init__.py b/python_payload/apps/shoegaze/__init__.py
index aac0dfa0ca..fb2064d9a6 100644
--- a/python_payload/apps/shoegaze/__init__.py
+++ b/python_payload/apps/shoegaze/__init__.py
@@ -5,6 +5,7 @@ from st3m.input import InputState
 from ctx import Context
 
 import json
+import errno
 import math
 import captouch
 import bl00mbox
@@ -33,7 +34,7 @@ class ShoegazeApp(Application):
         self.blm: Optional[bl00mbox.Channel] = None
         self.chord_index = 0
         self.chord: List[int] = []
-        self._set_chord(3)
+        self._organ_chords = [None] * 5
         self._tilt_bias = 0.0
         self._detune_prev = 0.0
         self._git_string_tuning = [0] * 4
@@ -43,8 +44,8 @@ class ShoegazeApp(Application):
         self._rand_limit = 16
         self._rand_rot = 0.0
         self.delay_on = True
-        self.fuzz_on = True
-        self._lofi = False
+        self.organ_on = False
+        self._set_chord(3)
 
     def _build_synth(self) -> None:
         if self.blm is None:
@@ -95,51 +96,64 @@ class ShoegazeApp(Application):
 
         self.main_mixer.signals.gain = 2000
         self.main_lp.signals.reso = 2000
+
+        self.bass_lp.signals.gain = 32767
+        self.git_lp.signals.gain = 32767
+        self.main_lp.signals.freq = 2500
+        self.main_lp.signals.gain = 2000
+        self.git_mixer.signals.gain = 4000
+        self.main_lp.signals.input = self.main_fuzz.signals.output
         self._update_connections()
 
     def _update_connections(self) -> None:
         if self.blm is None:
             return
-        if self.fuzz_on:
-            self.bass_lp.signals.gain = 32767
-            self.git_lp.signals.gain = 32767
-            self.main_lp.signals.freq = 2500
-            self.main_lp.signals.gain = 2000
-            self.git_mixer.signals.gain = 4000
-            self.main_lp.signals.input = self.main_fuzz.signals.output
-            if self.delay_on:
-                self.git_delay.signals.input = self.git_fuzz.signals.output
-                self.main_mixer.signals.input0 = self.git_delay.signals.output
-            else:
-                self.main_mixer.signals.input0 = self.git_fuzz.signals.output
+        if self.delay_on:
+            self.git_delay.signals.input = self.git_fuzz.signals.output
+            self.main_mixer.signals.input0 = self.git_delay.signals.output
         else:
-            self.bass_lp.signals.gain = 2000
-            self.git_lp.signals.gain = 2000
-            self.main_lp.signals.freq = 6000
-            self.main_lp.signals.gain = 4000
-            self.git_mixer.signals.gain = 500
-            self.main_lp.signals.input = self.main_mixer.signals.output
-            if self.delay_on:
-                self.git_delay.signals.input = self.git_lp.signals.output
-                self.main_mixer.signals.input0 = self.git_delay.signals.output
-            else:
-                self.main_mixer.signals.input0 = self.git_lp.signals.output
-
-    def fuzz_toggle(self) -> None:
-        self.fuzz_on = not self.fuzz_on
-        self._update_connections()
+            self.main_mixer.signals.input0 = self.git_fuzz.signals.output
+
+    def _try_load_settings(self, path):
+        try:
+            with open(path, "r") as f:
+                return json.load(f)
+        except OSError as e:
+            if e.errno != errno.ENOENT:
+                raise  # ignore file not found
+
+    def _load_settings(self):
+        settings_path = "/flash/harmonic_demo.json"
+
+        settings = self._try_load_settings(settings_path)
+        if settings is not None:
+            for i, chord in enumerate(settings["chords"]):
+                if i > 4:
+                    break
+                self._organ_chords[i] = chord["tones_readonly"]
+
+    def organ_toggle(self) -> None:
+        self.organ_on = not self.organ_on
+        if self.organ_on and self._organ_chords[0] is None:
+            self._load_settings()
+            if self._organ_chords[0] is None:
+                self.organ_on = False
+        self._set_chord(self.chord_index, force_update=True)
 
     def delay_toggle(self) -> None:
         self.delay_on = not self.delay_on
         self._update_connections()
 
-    def _set_chord(self, i: int) -> None:
+    def _set_chord(self, i: int, force_update=False) -> None:
         hue = int(54 * (i + 0.5)) % 360
-        if i != self.chord_index:
+        if i != self.chord_index or force_update:
             self.chord_index = i
             leds.set_all_hsv(hue, 1, 0.2)
             leds.update()
-            self.chord = chords[i]
+            if self.organ_on and self._organ_chords[i] is not None:
+                self.chord = self._organ_chords[i]
+            else:
+                self.chord = chords[i]
 
     def draw(self, ctx: Context) -> None:
         ctx.text_align = ctx.CENTER
@@ -159,38 +173,46 @@ class ShoegazeApp(Application):
         ctx.text("bass")
 
         rot = self._spinny  # + self._detune_prev
-        ctx.rgb(0, 0.5, 0.5)
         ctx.rotate(rot + self._rand_rot)
-        ctx.move_to(0, -10)
-        ctx.text("shoegazeshoegazeshoe")
-        ctx.move_to(0, 10)
-        ctx.text("gazeshoegazeshoegaze")
+        if self.organ_on:
+            ctx.rgb(0.5, 0, 0.6)
+            ctx.rotate(0.69)
+            ctx.move_to(0, -10)
+            ctx.text("chordorganchordorganchord")
+            ctx.move_to(0, 10)
+            ctx.text("organchordorganchordorgan")
+            ctx.rotate(4.20 + 0.69)
+        else:
+            ctx.rgb(0, 0.5, 0.5)
+            ctx.move_to(0, -10)
+            ctx.text("shoegazeshoegazeshoe")
+            ctx.move_to(0, 10)
+            ctx.text("gazeshoegazeshoegaze")
         ctx.rotate(-2.2 * (rot + self._rand_rot) - 0.5)
 
+        if self.organ_on:
+            rgb = (0.7, 0.7, 0)
+        else:
+            rgb = (0, 0.8, 0)
+
         ctx.move_to(40, 40)
+
         if self.delay_on:
-            ctx.rgb(0, 0.8, 0)
+            ctx.rgb(*rgb)
             ctx.text("delay ON!")
         else:
-            ctx.rgb(0, 0.6, 0)
+            ctx.rgb(*tuple([x * 0.75 for x in rgb]))
             ctx.text("delay off")
+            ctx.rgb(*rgb)
 
         ctx.rotate(0.2 + self._rand_rot)
-
         ctx.move_to(50, -50)
         detune = "detune: " + str(int(self._detune_prev * 100))
-        ctx.rgb(0, 0.8, 0)
+        ctx.rgb(*rgb)
         ctx.text(detune)
-
         ctx.rotate(-2.5 * (rot + 4 * self._rand_rot))
-
         ctx.move_to(-50, 50)
-        if self.fuzz_on:
-            ctx.rgb(0, 0.8, 0)
-            ctx.text("fuzz ON!")
-        else:
-            ctx.rgb(0, 0.6, 0)
-            ctx.text("fuzz off")
+        ctx.text("fuzz ON!")
 
     def think(self, ins: InputState, delta_ms: int) -> None:
         super().think(ins, delta_ms)
@@ -208,10 +230,7 @@ class ShoegazeApp(Application):
         if buttons.app.right.pressed:
             self.delay_toggle()
         if buttons.app.left.pressed:
-            pass
-            # self.fuzz_toggle()
-        if buttons.app.middle.pressed:
-            self.lofi = not self.lofi
+            self.organ_toggle()
 
         for i in range(1, 10, 2):
             if petals[i].whole.pressed:
@@ -235,21 +254,8 @@ class ShoegazeApp(Application):
             self.bass_string.decay = 1000
             self.bass_string.signals.trigger.start()
 
-    @property
-    def lofi(self):
-        return self._lofi
-
-    @lofi.setter
-    def lofi(self, val):
-        self._lofi = bool(val)
-        if self._lofi:
-            sys_display.set_mode(2313)
-        else:
-            sys_display.set_mode(912)
-
     def on_enter(self, vm: Optional[ViewManager]) -> None:
         super().on_enter(vm)
-        self.lofi = self.lofi
         if self.blm is None:
             self._build_synth()
         self.blm.foreground = True
-- 
GitLab