Skip to content

Commit f504199

Browse files
authored
Merge pull request #3033 from jedgarpark/larsio-music
LPM for Fruit Jam and Metro RP2350
2 parents c5bec45 + 565f129 commit f504199

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3107
-0
lines changed

Fruit_Jam/Larsio_Paint_Music/code.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# SPDX-FileCopyrightText: 2025 John Park and Claude AI for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""
5+
Larsio Paint Music
6+
Fruit Jam w mouse, HDMI, audio out
7+
or Metro RP2350 with EYESPI DVI breakout and TLV320DAC3100 breakout on STEMMA_I2C,
8+
pin D7 reset, 9/10/11 = BCLC/WSEL/DIN
9+
"""
10+
# pylint: disable=invalid-name,too-few-public-methods,broad-except,redefined-outer-name
11+
12+
# Main application file for Larsio Paint Music
13+
14+
import time
15+
import gc
16+
from sound_manager import SoundManager
17+
from note_manager import NoteManager
18+
from ui_manager import UIManager
19+
20+
# Configuration
21+
AUDIO_OUTPUT = "i2s" # Options: "pwm" or "i2s"
22+
23+
class MusicStaffApp:
24+
"""Main application class that ties everything together"""
25+
26+
def __init__(self, audio_output="pwm"):
27+
# Initialize the sound manager with selected audio output
28+
# Calculate tempo parameters
29+
BPM = 120 # Beats per minute
30+
SECONDS_PER_BEAT = 60 / BPM
31+
SECONDS_PER_EIGHTH = SECONDS_PER_BEAT / 2
32+
33+
# Initialize components in a specific order
34+
# First, force garbage collection to free memory
35+
gc.collect()
36+
37+
# Initialize the sound manager
38+
print("Initializing sound manager...")
39+
self.sound_manager = SoundManager(
40+
audio_output=audio_output,
41+
seconds_per_eighth=SECONDS_PER_EIGHTH
42+
)
43+
44+
# Give hardware time to stabilize
45+
time.sleep(0.5)
46+
gc.collect()
47+
48+
# Initialize the note manager
49+
print("Initializing note manager...")
50+
self.note_manager = NoteManager(
51+
start_margin=25, # START_MARGIN
52+
staff_y_start=int(240 * 0.1), # STAFF_Y_START
53+
line_spacing=int((240 - int(240 * 0.1) - int(240 * 0.2)) * 0.95) // 8 # LINE_SPACING
54+
)
55+
56+
gc.collect()
57+
58+
# Initialize the UI manager
59+
print("Initializing UI manager...")
60+
self.ui_manager = UIManager(self.sound_manager, self.note_manager)
61+
62+
def run(self):
63+
"""Set up and run the application"""
64+
# Setup the display and UI
65+
print("Setting up display...")
66+
self.ui_manager.setup_display()
67+
68+
# Give hardware time to stabilize
69+
time.sleep(0.5)
70+
gc.collect()
71+
72+
# Try to find the mouse with multiple attempts
73+
MAX_ATTEMPTS = 5
74+
RETRY_DELAY = 1 # seconds
75+
76+
mouse_found = False
77+
for attempt in range(MAX_ATTEMPTS):
78+
print(f"Mouse detection attempt {attempt+1}/{MAX_ATTEMPTS}")
79+
if self.ui_manager.find_mouse():
80+
mouse_found = True
81+
print("Mouse found successfully!")
82+
break
83+
84+
print(f"Mouse detection attempt {attempt+1} failed, retrying...")
85+
time.sleep(RETRY_DELAY)
86+
87+
if not mouse_found:
88+
print("WARNING: Mouse not found after multiple attempts.")
89+
print("The application will run, but mouse control may be limited.")
90+
91+
# Enter the main loop
92+
self.ui_manager.main_loop()
93+
94+
95+
# Create and run the application
96+
if __name__ == "__main__":
97+
# Start with garbage collection
98+
gc.collect()
99+
print("Starting Music Staff Application...")
100+
101+
try:
102+
app = MusicStaffApp(audio_output=AUDIO_OUTPUT)
103+
app.run()
104+
except Exception as e: # pylint: disable=broad-except
105+
print(f"Error with I2S audio: {e}")
106+
107+
# Force garbage collection
108+
gc.collect()
109+
time.sleep(1)
110+
111+
# Fallback to PWM
112+
try:
113+
app = MusicStaffApp(audio_output="pwm")
114+
app.run()
115+
except Exception as e2: # pylint: disable=broad-except
116+
print(f"Fatal error: {e2}")

0 commit comments

Comments
 (0)