From ce4c56b6c8df52767a35d11ee4c9f283719c69f7 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sat, 9 Aug 2025 14:44:04 -0400 Subject: [PATCH 01/10] Add audio output option file to Larsio and Chip's Challenge --- Fruit_Jam/Larsio_Paint_Music/sound_manager.py | 66 +++++++++++++++---- Metro/Metro_RP2350_Chips_Challenge/code.py | 11 +--- .../definitions.py | 52 ++++++++++++++- 3 files changed, 107 insertions(+), 22 deletions(-) diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index 5520669d5..ff88b8a3b 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -9,6 +9,7 @@ import math import time import array +import json import gc import os import digitalio @@ -22,6 +23,7 @@ import audiomixer import synthio import board +import adafruit_pathlib as pathlib import adafruit_tlv320 from adafruit_midi.note_on import NoteOn from adafruit_midi.note_off import NoteOff @@ -63,6 +65,15 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): # Setup PWM audio output on D10 self.audio = audiopwmio.PWMAudioOut(board.D10) else: # i2s + # optional configuration file for speaker/headphone setting, check current and root directory + launcher_config = {} + if pathlib.Path("launcher.conf.json").exists(): + with open("launcher.conf.json", "r") as f: + launcher_config = json.load(f) + elif pathlib.Path("/launcher.conf.json").exists(): + with open("/launcher.conf.json", "r") as f: + launcher_config = json.load(f) + try: # Import libraries needed for I2S #check for Metro RP2350 vs. Fruit Jam @@ -96,20 +107,49 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): wsel_pin = board.I2S_WS din_pin = board.I2S_DIN + # Check if DAC is connected + while not i2c.try_lock(): + time.sleep(0.01) + if 0x18 in i2c.scan(): + ltv320_present = True + else: + ltv320_present = False + i2c.unlock() + # Initialize TLV320 - self.tlv = adafruit_tlv320.TLV320DAC3100(i2c) - self.tlv.configure_clocks(sample_rate=11025, bit_depth=16) - self.tlv.headphone_output = True - self.tlv.headphone_volume = -15 # dB - - # Setup I2S audio output - important to do this AFTER configuring the DAC - self.audio = audiobusio.I2SOut( - bit_clock=bclck_pin, - word_select=wsel_pin, - data=din_pin - ) - - print("TLV320 I2S DAC initialized successfully") + if ltv320_present: + self.tlv = adafruit_tlv320.TLV320DAC3100(i2c) + + # set sample rate & bit depth + self.tlv.configure_clocks(sample_rate=11025, bit_depth=16) + + if "sound" in launcher_config: + if launcher_config["sound"] == "speaker": + # use speaker + self.tlv.speaker_output = True + self.tlv.speaker_volume = -60 + else: + # use headphones + self.tlv.headphone_output = True + self.tlv.headphone_volume = -15 # dB + else: + # default to headphones + self.tlv.headphone_output = True + self.tlv.headphone_volume = -15 # dB + + # Setup I2S audio output - important to do this AFTER configuring the DAC + self.audio = audiobusio.I2SOut( + bit_clock=bclck_pin, + word_select=wsel_pin, + data=din_pin + ) + + print("TLV320 I2S DAC initialized successfully") + + else: + print("TLV320 DAC not found, falling back to PWM audio output") + self.audio = audiopwmio.PWMAudioOut(board.D10) + except Exception as e: print(f"Error initializing TLV320 DAC: {e}") print("Falling back to PWM audio output") diff --git a/Metro/Metro_RP2350_Chips_Challenge/code.py b/Metro/Metro_RP2350_Chips_Challenge/code.py index e9b7d3f4f..8071dea90 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/code.py +++ b/Metro/Metro_RP2350_Chips_Challenge/code.py @@ -7,7 +7,6 @@ import picodvi import framebufferio import displayio -import adafruit_tlv320 import audiobusio from audio import Audio from game import Game @@ -39,16 +38,12 @@ displayio.release_displays() -i2c = board.I2C() -dac = adafruit_tlv320.TLV320DAC3100(i2c) -dac.configure_clocks(sample_rate=44100, bit_depth=16) -dac.headphone_output = True -dac.headphone_volume = -15 # dB - if hasattr(board, "I2S_BCLK"): audio_bus = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) -else: +elif hasattr(board, "D9") and hasattr(board, "D10") and hasattr(board, "D11"): audio_bus = audiobusio.I2SOut(board.D9, board.D10, board.D11) +else: + audio_bus = None audio = Audio(audio_bus, SOUND_EFFECTS) fb = picodvi.Framebuffer(320, 240, clk_dp=board.CKP, clk_dn=board.CKN, diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index df53dc158..b18597945 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -1,10 +1,60 @@ # SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams # # SPDX-License-Identifier: MIT +import json +import board from micropython import const +import adafruit_pathlib as pathlib +import adafruit_tlv320 + +# optional configuration file for speaker/headphone setting, check current and root directory +launcher_config = {} +if pathlib.Path("launcher.conf.json").exists(): + with open("launcher.conf.json", "r") as f: + launcher_config = json.load(f) +elif pathlib.Path("/launcher.conf.json").exists(): + with open("/launcher.conf.json", "r") as f: + launcher_config = json.load(f) + +# Check if DAC is connected +i2c = board.I2C() +while not i2c.try_lock(): + time.sleep(0.01) +if 0x18 in i2c.scan(): + ltv320_present = True +else: + ltv320_present = False +i2c.unlock() + +if ltv320_present: + dac = adafruit_tlv320.TLV320DAC3100(i2c) + + # set sample rate & bit depth + dac.configure_clocks(sample_rate=44100, bit_depth=16) + + if "sound" in launcher_config: + if launcher_config["sound"] == "speaker": + # use speaker + dac.speaker_output = True + dac.speaker_volume = -40 + elif launcher_config["sound"] != "mute": + # use headphones + dac.headphone_output = True + dac.headphone_volume = -15 # dB + else: + # default to headphones + dac.headphone_output = True + dac.headphone_volume = -15 # dB # Settings -PLAY_SOUNDS = True +if ltv320_present: + PLAY_SOUNDS = True +else: + PLAY_SOUNDS = False + +if "sound" in launcher_config: + if launcher_config["sound"] == "mute": + PLAY_SOUNDS = False # Timing Constants TICKS_PER_SECOND = const(20) From 986f736d17922591e75d1ce3a4a605cb18924849 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sat, 9 Aug 2025 15:21:41 -0400 Subject: [PATCH 02/10] pylint fixes --- Fruit_Jam/Larsio_Paint_Music/sound_manager.py | 3 ++- Metro/Metro_RP2350_Chips_Challenge/definitions.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index ff88b8a3b..ce5159b7c 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -65,7 +65,8 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): # Setup PWM audio output on D10 self.audio = audiopwmio.PWMAudioOut(board.D10) else: # i2s - # optional configuration file for speaker/headphone setting, check current and root directory + # optional configuration file for speaker/headphone setting + # check current directory first and then root directory launcher_config = {} if pathlib.Path("launcher.conf.json").exists(): with open("launcher.conf.json", "r") as f: diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index b18597945..447f21bac 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT import json +import time import board from micropython import const import adafruit_pathlib as pathlib From 5b726750dbb6b8c8ca42641d94807196778ef166 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sat, 9 Aug 2025 15:56:20 -0400 Subject: [PATCH 03/10] Replace possible infinite loops with 5 second max --- Fruit_Jam/Larsio_Paint_Music/sound_manager.py | 4 +++- Metro/Metro_RP2350_Chips_Challenge/definitions.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index ce5159b7c..1702d5b29 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -109,7 +109,9 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): din_pin = board.I2S_DIN # Check if DAC is connected - while not i2c.try_lock(): + for i in range(500): # try for 5 seconds + if i2c.try_lock(): + break time.sleep(0.01) if 0x18 in i2c.scan(): ltv320_present = True diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index 447f21bac..6194cf2ff 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -19,7 +19,9 @@ # Check if DAC is connected i2c = board.I2C() -while not i2c.try_lock(): +for i in range(500): # try for 5 seconds + if i2c.try_lock(): + break time.sleep(0.01) if 0x18 in i2c.scan(): ltv320_present = True From 33eceaf3fa353d770a03099c71cd7fb36bed0f37 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Fri, 15 Aug 2025 18:29:55 -0400 Subject: [PATCH 04/10] remove guard against missing DAC --- Fruit_Jam/Larsio_Paint_Music/sound_manager.py | 63 +++++++------------ 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index 1702d5b29..5a11be571 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -108,51 +108,34 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): wsel_pin = board.I2S_WS din_pin = board.I2S_DIN - # Check if DAC is connected - for i in range(500): # try for 5 seconds - if i2c.try_lock(): - break - time.sleep(0.01) - if 0x18 in i2c.scan(): - ltv320_present = True - else: - ltv320_present = False - i2c.unlock() - # Initialize TLV320 - if ltv320_present: - self.tlv = adafruit_tlv320.TLV320DAC3100(i2c) - - # set sample rate & bit depth - self.tlv.configure_clocks(sample_rate=11025, bit_depth=16) - - if "sound" in launcher_config: - if launcher_config["sound"] == "speaker": - # use speaker - self.tlv.speaker_output = True - self.tlv.speaker_volume = -60 - else: - # use headphones - self.tlv.headphone_output = True - self.tlv.headphone_volume = -15 # dB + self.tlv = adafruit_tlv320.TLV320DAC3100(i2c) + + # set sample rate & bit depth + self.tlv.configure_clocks(sample_rate=11025, bit_depth=16) + + if "sound" in launcher_config: + if launcher_config["sound"] == "speaker": + # use speaker + self.tlv.speaker_output = True + self.tlv.speaker_volume = -60 else: - # default to headphones + # use headphones self.tlv.headphone_output = True self.tlv.headphone_volume = -15 # dB - - # Setup I2S audio output - important to do this AFTER configuring the DAC - self.audio = audiobusio.I2SOut( - bit_clock=bclck_pin, - word_select=wsel_pin, - data=din_pin - ) - - print("TLV320 I2S DAC initialized successfully") - else: - print("TLV320 DAC not found, falling back to PWM audio output") - self.audio = audiopwmio.PWMAudioOut(board.D10) - + # default to headphones + self.tlv.headphone_output = True + self.tlv.headphone_volume = -15 # dB + + # Setup I2S audio output - important to do this AFTER configuring the DAC + self.audio = audiobusio.I2SOut( + bit_clock=bclck_pin, + word_select=wsel_pin, + data=din_pin + ) + + print("TLV320 I2S DAC initialized successfully") except Exception as e: print(f"Error initializing TLV320 DAC: {e}") print("Falling back to PWM audio output") From 118806a614964c6c0682370de6a92c63a3d83aab Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Fri, 15 Aug 2025 23:13:26 -0400 Subject: [PATCH 05/10] seperate PLAY_SOUNDS definition from default logic --- Metro/Metro_RP2350_Chips_Challenge/definitions.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index 6194cf2ff..31d9f1d40 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -49,15 +49,17 @@ dac.headphone_output = True dac.headphone_volume = -15 # dB -# Settings if ltv320_present: - PLAY_SOUNDS = True + _default_play_sounds = True else: - PLAY_SOUNDS = False + _default_play_sounds = False if "sound" in launcher_config: if launcher_config["sound"] == "mute": - PLAY_SOUNDS = False + _default_play_sounds = False + +# Settings +PLAY_SOUNDS = _default_play_sounds # Timing Constants TICKS_PER_SECOND = const(20) From 5c59c048bda4712a42e754e4701e3ac0f37c81ba Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sat, 16 Aug 2025 10:01:47 -0400 Subject: [PATCH 06/10] Add guard for boards without I2C defined --- .../definitions.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index 31d9f1d40..4302150a4 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -18,16 +18,19 @@ launcher_config = json.load(f) # Check if DAC is connected -i2c = board.I2C() -for i in range(500): # try for 5 seconds - if i2c.try_lock(): - break - time.sleep(0.01) -if 0x18 in i2c.scan(): - ltv320_present = True +if "I2C" in dir(board): + i2c = board.I2C() + for i in range(500): # try for 5 seconds + if i2c.try_lock(): + break + time.sleep(0.01) + if 0x18 in i2c.scan(): + ltv320_present = True + else: + ltv320_present = False + i2c.unlock() else: ltv320_present = False -i2c.unlock() if ltv320_present: dac = adafruit_tlv320.TLV320DAC3100(i2c) From 83d33d6641d2f77a2ccea7d181c9250f91db8d5f Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sun, 17 Aug 2025 15:54:20 -0400 Subject: [PATCH 07/10] eliminate app dictionay, use only root config file and fix tlv320 variable name --- Fruit_Jam/Larsio_Paint_Music/sound_manager.py | 17 ++++------ .../definitions.py | 32 +++++++++---------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index 5a11be571..ddb0276a4 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -66,12 +66,8 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): self.audio = audiopwmio.PWMAudioOut(board.D10) else: # i2s # optional configuration file for speaker/headphone setting - # check current directory first and then root directory launcher_config = {} - if pathlib.Path("launcher.conf.json").exists(): - with open("launcher.conf.json", "r") as f: - launcher_config = json.load(f) - elif pathlib.Path("/launcher.conf.json").exists(): + if pathlib.Path("/launcher.conf.json").exists(): with open("/launcher.conf.json", "r") as f: launcher_config = json.load(f) @@ -110,23 +106,24 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): # Initialize TLV320 self.tlv = adafruit_tlv320.TLV320DAC3100(i2c) + self.tlv.reset() # set sample rate & bit depth self.tlv.configure_clocks(sample_rate=11025, bit_depth=16) - if "sound" in launcher_config: - if launcher_config["sound"] == "speaker": + if "tlv320" in launcher_config: + if launcher_config["tlv320"].get("output") == "speaker": # use speaker self.tlv.speaker_output = True - self.tlv.speaker_volume = -60 + self.tlv.dac_volume = launcher_config["tlv320"].get("volume",5) # dB else: # use headphones self.tlv.headphone_output = True - self.tlv.headphone_volume = -15 # dB + self.tlv.dac_volume = launcher_config["tlv320"].get("volume",0) # dB else: # default to headphones self.tlv.headphone_output = True - self.tlv.headphone_volume = -15 # dB + self.tlv.dac_volume = 0 # dB # Setup I2S audio output - important to do this AFTER configuring the DAC self.audio = audiobusio.I2SOut( diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index 4302150a4..1e44c0707 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -8,12 +8,9 @@ import adafruit_pathlib as pathlib import adafruit_tlv320 -# optional configuration file for speaker/headphone setting, check current and root directory +# optional configuration file for speaker/headphone setting launcher_config = {} -if pathlib.Path("launcher.conf.json").exists(): - with open("launcher.conf.json", "r") as f: - launcher_config = json.load(f) -elif pathlib.Path("/launcher.conf.json").exists(): +if pathlib.Path("/launcher.conf.json").exists(): with open("/launcher.conf.json", "r") as f: launcher_config = json.load(f) @@ -25,40 +22,41 @@ break time.sleep(0.01) if 0x18 in i2c.scan(): - ltv320_present = True + tlv320_present = True else: - ltv320_present = False + tlv320_present = False i2c.unlock() else: - ltv320_present = False + tlv320_present = False -if ltv320_present: +if tlv320_present: dac = adafruit_tlv320.TLV320DAC3100(i2c) + dac.reset() # set sample rate & bit depth dac.configure_clocks(sample_rate=44100, bit_depth=16) - if "sound" in launcher_config: - if launcher_config["sound"] == "speaker": + if "tlv320" in launcher_config: + if launcher_config["tlv320"].get("output") == "speaker": # use speaker dac.speaker_output = True - dac.speaker_volume = -40 - elif launcher_config["sound"] != "mute": + dac.dac_volume = launcher_config["tlv320"].get("volume",5) # dB + else: # use headphones dac.headphone_output = True - dac.headphone_volume = -15 # dB + dac.dac_volume = launcher_config["tlv320"].get("volume",0) # dB else: # default to headphones dac.headphone_output = True - dac.headphone_volume = -15 # dB + dac.dac_volume = 0 # dB -if ltv320_present: +if tlv320_present: _default_play_sounds = True else: _default_play_sounds = False if "sound" in launcher_config: - if launcher_config["sound"] == "mute": + if launcher_config["tlv320"].get("output") == "mute": _default_play_sounds = False # Settings From db6b00dff956b47abe2ab97c8c804d3faecd343c Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 19 Aug 2025 10:55:48 -0400 Subject: [PATCH 08/10] remove unneeded dac.reset() statements --- Fruit_Jam/Larsio_Paint_Music/sound_manager.py | 1 - Metro/Metro_RP2350_Chips_Challenge/definitions.py | 1 - 2 files changed, 2 deletions(-) diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index ddb0276a4..db2e297fe 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -106,7 +106,6 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): # Initialize TLV320 self.tlv = adafruit_tlv320.TLV320DAC3100(i2c) - self.tlv.reset() # set sample rate & bit depth self.tlv.configure_clocks(sample_rate=11025, bit_depth=16) diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index 1e44c0707..9d62766b2 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -31,7 +31,6 @@ if tlv320_present: dac = adafruit_tlv320.TLV320DAC3100(i2c) - dac.reset() # set sample rate & bit depth dac.configure_clocks(sample_rate=44100, bit_depth=16) From a8e8e8d76f8f7337da070658f4d61ca4f348c82e Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Thu, 11 Sep 2025 01:12:09 -0400 Subject: [PATCH 09/10] refactor for fruitjam library new API --- Fruit_Jam/Larsio_Paint_Music/sound_manager.py | 73 +++++++++---------- Metro/Metro_RP2350_Chips_Challenge/audio.py | 2 +- Metro/Metro_RP2350_Chips_Challenge/code.py | 52 ++++++++----- .../definitions.py | 57 +-------------- .../Metro_RP2350_Chips_Challenge/savestate.py | 5 +- 5 files changed, 77 insertions(+), 112 deletions(-) diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index db2e297fe..67b16fce9 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -19,12 +19,11 @@ import adafruit_midi import audiocore import audiopwmio -import audiobusio import audiomixer import synthio import board import adafruit_pathlib as pathlib -import adafruit_tlv320 +import adafruit_fruitjam from adafruit_midi.note_on import NoteOn from adafruit_midi.note_off import NoteOff import usb_midi @@ -67,9 +66,13 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): else: # i2s # optional configuration file for speaker/headphone setting launcher_config = {} - if pathlib.Path("/launcher.conf.json").exists(): - with open("/launcher.conf.json", "r") as f: - launcher_config = json.load(f) + for directory in ("/", "/sd/", "/saves/"): + launcher_config_path = directory + "launcher.conf.json" + if pathlib.Path(launcher_config_path).exists(): + with open(launcher_config_path, "r") as f: + launcher_config = launcher_config | json.load(f) + if "audio" not in launcher_config: + launcher_config["audio"] = {} try: # Import libraries needed for I2S @@ -84,11 +87,17 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): time.sleep(0.1) # Pause 100ms reset_pin.value = True # Set high to release from reset - i2c = board.STEMMA_I2C() # initialize I2C + # Initialize TLV320 + fjPeriphs = adafruit_fruitjam.Peripherals( + audio_output=launcher_config["audio"].get("output", "headphone"), + safe_volume_limit=launcher_config["audio"].get("volume_override_danger",12), + sample_rate=11025, + bit_depth=16, + i2c=board.STEMMA_I2C() + ) - bclck_pin = board.D9 - wsel_pin = board.D10 - din_pin = board.D11 + self.tlv = fjPeriphs.dac + fjPeriphs.audio = audiobusio.I2SOut(board.D9, board.D10, board.D11) elif 'Fruit Jam' in board_type: print("Fruit Jam setup") @@ -98,38 +107,27 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): time.sleep(0.1) reset_pin.value = True - i2c = busio.I2C(board.SCL, board.SDA) + # Initialize TLV320 + fjPeriphs = adafruit_fruitjam.Peripherals( + audio_output=launcher_config["audio"].get("output", "headphone"), + safe_volume_limit=launcher_config["audio"].get("volume_override_danger",12), + sample_rate=11025, + bit_depth=16, + i2c=board.I2C() + ) - bclck_pin = board.I2S_BCLK - wsel_pin = board.I2S_WS - din_pin = board.I2S_DIN + self.tlv = fjPeriphs.dac - # Initialize TLV320 - self.tlv = adafruit_tlv320.TLV320DAC3100(i2c) - - # set sample rate & bit depth - self.tlv.configure_clocks(sample_rate=11025, bit_depth=16) - - if "tlv320" in launcher_config: - if launcher_config["tlv320"].get("output") == "speaker": - # use speaker - self.tlv.speaker_output = True - self.tlv.dac_volume = launcher_config["tlv320"].get("volume",5) # dB - else: - # use headphones - self.tlv.headphone_output = True - self.tlv.dac_volume = launcher_config["tlv320"].get("volume",0) # dB - else: - # default to headphones - self.tlv.headphone_output = True - self.tlv.dac_volume = 0 # dB + # If volume was specified use it, otherwise use the fruitjam library default + if "volume_override_danger" in launcher_config["audio"]: + fjPeriphs.volume = launcher_config["audio"]["volume_override_danger"] + elif "volume" in launcher_config["audio"]: + fjPeriphs.volume = launcher_config["audio"]["volume"] # FruitJam vol (1-20) # Setup I2S audio output - important to do this AFTER configuring the DAC - self.audio = audiobusio.I2SOut( - bit_clock=bclck_pin, - word_select=wsel_pin, - data=din_pin - ) + # Fruitjam library actually does this before we modify the configuration + # but after the initial default configuration is performed + self.audio = fjPeriphs.audio print("TLV320 I2S DAC initialized successfully") except Exception as e: @@ -617,6 +615,7 @@ def deinit(self): try: # For TLV320DAC3100, headphone_output = False will power down the output self.tlv.headphone_output = False + self.tlv.speaker_output = False except Exception: pass diff --git a/Metro/Metro_RP2350_Chips_Challenge/audio.py b/Metro/Metro_RP2350_Chips_Challenge/audio.py index a3e263d6e..d8ea59029 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/audio.py +++ b/Metro/Metro_RP2350_Chips_Challenge/audio.py @@ -14,7 +14,7 @@ def __init__(self, audio_bus, sounds): self.play(tuple(self._wav_files.keys())[0], wait=True) def play(self, sound_name, wait=False): - if not PLAY_SOUNDS: + if not PLAY_SOUNDS or self._audio is None: return if sound_name in self._wav_files: with open(self._wav_files[sound_name], "rb") as wave_file: diff --git a/Metro/Metro_RP2350_Chips_Challenge/code.py b/Metro/Metro_RP2350_Chips_Challenge/code.py index 8071dea90..d8edbf8fb 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/code.py +++ b/Metro/Metro_RP2350_Chips_Challenge/code.py @@ -2,13 +2,14 @@ # # SPDX-License-Identifier: MIT +import json import time import board -import picodvi -import framebufferio -import displayio +import supervisor import audiobusio from audio import Audio +import adafruit_pathlib as pathlib +import adafruit_fruitjam.Peripherals from game import Game from definitions import SECOND_LENGTH, TICKS_PER_SECOND @@ -36,24 +37,41 @@ "TIME_UP": "sounds/bell.wav" } -displayio.release_displays() +# optional configuration file for speaker/headphone setting +launcher_config = {} +for directory in ("/", "/sd/", "/saves/"): + launcher_config_path = directory + "launcher.conf.json" + if pathlib.Path(launcher_config_path).exists(): + with open(launcher_config_path, "r") as f: + launcher_config = launcher_config | json.load(f) +if "audio" not in launcher_config: + launcher_config["audio"] = {} -if hasattr(board, "I2S_BCLK"): - audio_bus = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) -elif hasattr(board, "D9") and hasattr(board, "D10") and hasattr(board, "D11"): - audio_bus = audiobusio.I2SOut(board.D9, board.D10, board.D11) + +fjPeriphs = adafruit_fruitjam.Peripherals.Peripherals( + audio_output=launcher_config["audio"].get("output", "headphone"), + safe_volume_limit=launcher_config["audio"].get("volume_override_danger",12), + sample_rate=44100, + bit_depth=16, + i2c=board.I2C() +) +if not hasattr(board, "I2S_BCLK") and hasattr(board, "D9") and hasattr(board, "D10") and hasattr(board, "D11"): + fjPeriphs.audio = audiobusio.I2SOut(board.D9, board.D10, board.D11) + +# If volume was specified use it, otherwise use the fruitjam library default +if "volume_override_danger" in launcher_config["audio"]: + fjPeriphs.volume = launcher_config["audio"]["volume_override_danger"] +elif "volume" in launcher_config["audio"]: + fjPeriphs.volume = launcher_config["audio"]["volume"] # FruitJam vol (1-20) + +if fjPeriphs.audio is not None: + audio = Audio(fjPeriphs.audio, SOUND_EFFECTS) else: - audio_bus = None -audio = Audio(audio_bus, SOUND_EFFECTS) + audio = None -fb = picodvi.Framebuffer(320, 240, clk_dp=board.CKP, clk_dn=board.CKN, - red_dp=board.D0P, red_dn=board.D0N, - green_dp=board.D1P, green_dn=board.D1N, - blue_dp=board.D2P, blue_dn=board.D2N, - color_depth=8) -display = framebufferio.FramebufferDisplay(fb) +adafruit_fruitjam.Peripherals.request_display_config(320, 240, 8) -game = Game(display, DATA_FILE, audio) +game = Game(supervisor.runtime.display, DATA_FILE, audio) tick_length = SECOND_LENGTH / 1000 / TICKS_PER_SECOND while True: start = time.monotonic() diff --git a/Metro/Metro_RP2350_Chips_Challenge/definitions.py b/Metro/Metro_RP2350_Chips_Challenge/definitions.py index 9d62766b2..df53dc158 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/definitions.py +++ b/Metro/Metro_RP2350_Chips_Challenge/definitions.py @@ -1,65 +1,10 @@ # SPDX-FileCopyrightText: 2025 Melissa LeBlanc-Williams # # SPDX-License-Identifier: MIT -import json -import time -import board from micropython import const -import adafruit_pathlib as pathlib -import adafruit_tlv320 - -# optional configuration file for speaker/headphone setting -launcher_config = {} -if pathlib.Path("/launcher.conf.json").exists(): - with open("/launcher.conf.json", "r") as f: - launcher_config = json.load(f) - -# Check if DAC is connected -if "I2C" in dir(board): - i2c = board.I2C() - for i in range(500): # try for 5 seconds - if i2c.try_lock(): - break - time.sleep(0.01) - if 0x18 in i2c.scan(): - tlv320_present = True - else: - tlv320_present = False - i2c.unlock() -else: - tlv320_present = False - -if tlv320_present: - dac = adafruit_tlv320.TLV320DAC3100(i2c) - - # set sample rate & bit depth - dac.configure_clocks(sample_rate=44100, bit_depth=16) - - if "tlv320" in launcher_config: - if launcher_config["tlv320"].get("output") == "speaker": - # use speaker - dac.speaker_output = True - dac.dac_volume = launcher_config["tlv320"].get("volume",5) # dB - else: - # use headphones - dac.headphone_output = True - dac.dac_volume = launcher_config["tlv320"].get("volume",0) # dB - else: - # default to headphones - dac.headphone_output = True - dac.dac_volume = 0 # dB - -if tlv320_present: - _default_play_sounds = True -else: - _default_play_sounds = False - -if "sound" in launcher_config: - if launcher_config["tlv320"].get("output") == "mute": - _default_play_sounds = False # Settings -PLAY_SOUNDS = _default_play_sounds +PLAY_SOUNDS = True # Timing Constants TICKS_PER_SECOND = const(20) diff --git a/Metro/Metro_RP2350_Chips_Challenge/savestate.py b/Metro/Metro_RP2350_Chips_Challenge/savestate.py index 7fdc4ba61..15f54e75d 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/savestate.py +++ b/Metro/Metro_RP2350_Chips_Challenge/savestate.py @@ -32,7 +32,10 @@ def _mount_sd_card(self): except OSError: pass - self._card_detect = DigitalInOut(board.SD_CARD_DETECT) + try: + self._card_detect = DigitalInOut(board.SD_CARD_DETECT) + except ValueError: + return False self._card_detect.switch_to_input(pull=Pull.UP) if self._card_detect.value: return False From c1dafe7f3291282a5c2762b2a33773a7f0435961 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Thu, 11 Sep 2025 01:27:13 -0400 Subject: [PATCH 10/10] pylint fixes --- Fruit_Jam/Larsio_Paint_Music/sound_manager.py | 9 +-------- Metro/Metro_RP2350_Chips_Challenge/code.py | 6 ++++-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py index 67b16fce9..47c979a14 100755 --- a/Fruit_Jam/Larsio_Paint_Music/sound_manager.py +++ b/Fruit_Jam/Larsio_Paint_Music/sound_manager.py @@ -13,10 +13,9 @@ import gc import os import digitalio -import busio - import adafruit_midi +import audiobusio import audiocore import audiopwmio import audiomixer @@ -54,12 +53,6 @@ def __init__(self, audio_output="pwm", seconds_per_eighth=0.25): self.audio_output_type = audio_output self.tlv = None - # Initialize these variables to avoid use-before-assignment issues - i2c = None - bclck_pin = None - wsel_pin = None - din_pin = None - if self.audio_output_type == "pwm": # Setup PWM audio output on D10 self.audio = audiopwmio.PWMAudioOut(board.D10) diff --git a/Metro/Metro_RP2350_Chips_Challenge/code.py b/Metro/Metro_RP2350_Chips_Challenge/code.py index d8edbf8fb..0954d158f 100755 --- a/Metro/Metro_RP2350_Chips_Challenge/code.py +++ b/Metro/Metro_RP2350_Chips_Challenge/code.py @@ -49,13 +49,15 @@ fjPeriphs = adafruit_fruitjam.Peripherals.Peripherals( - audio_output=launcher_config["audio"].get("output", "headphone"), + audio_output=launcher_config["audio"].get("output", "headphone"), safe_volume_limit=launcher_config["audio"].get("volume_override_danger",12), sample_rate=44100, bit_depth=16, i2c=board.I2C() ) -if not hasattr(board, "I2S_BCLK") and hasattr(board, "D9") and hasattr(board, "D10") and hasattr(board, "D11"): +if not hasattr(board, "I2S_BCLK") and \ + hasattr(board, "D9") and hasattr(board, "D10") and hasattr(board, "D11"): + fjPeriphs.audio = audiobusio.I2SOut(board.D9, board.D10, board.D11) # If volume was specified use it, otherwise use the fruitjam library default