audio volume and interface APIs

This commit is contained in:
foamyguy 2025-08-19 11:31:14 -05:00
parent a0327ac8e6
commit f35068b0d3

View file

@ -38,6 +38,7 @@ import digitalio
import displayio import displayio
import framebufferio import framebufferio
import picodvi import picodvi
import simpleio
import storage import storage
import supervisor import supervisor
from digitalio import DigitalInOut, Direction, Pull from digitalio import DigitalInOut, Direction, Pull
@ -133,13 +134,16 @@ def get_display_config():
class Peripherals: class Peripherals:
"""Peripherals Helper Class for the FruitJam Library """Peripherals Helper Class for the FruitJam Library
:param audio_output: The audio output interface to use 'speaker' or 'headphone'
:param safe_volume_limit: The maximum volume allowed for the audio output. Default is 15
Using higher values can damage some speakers, change at your own risk.
Attributes: Attributes:
neopixels (NeoPxiels): The NeoPixels on the Fruit Jam board. neopixels (NeoPxiels): The NeoPixels on the Fruit Jam board.
See https://circuitpython.readthedocs.io/projects/neopixel/en/latest/api.html See https://circuitpython.readthedocs.io/projects/neopixel/en/latest/api.html
""" """
def __init__(self): def __init__(self, audio_output="headphone", safe_volume_limit=15):
self.neopixels = NeoPixel(board.NEOPIXEL, 5) self.neopixels = NeoPixel(board.NEOPIXEL, 5)
self._buttons = [] self._buttons = []
@ -155,11 +159,13 @@ class Peripherals:
# set sample rate & bit depth # set sample rate & bit depth
self._dac.configure_clocks(sample_rate=11030, bit_depth=16) self._dac.configure_clocks(sample_rate=11030, bit_depth=16)
# use headphones self.audio_output = audio_output
self._dac.headphone_output = True
self._dac.headphone_volume = -15 # dB
self._audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) self._audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN)
if safe_volume_limit < 1 or safe_volume_limit > 20:
raise ValueError("safe_volume_limit must be between 1 and 20")
self.safe_volume_limit = safe_volume_limit
self._volume = 13
self._apply_volume()
self._sd_mounted = False self._sd_mounted = False
sd_pins_in_use = False sd_pins_in_use = False
@ -252,3 +258,62 @@ class Peripherals:
self.audio.stop() self.audio.stop()
if self.wavfile is not None: if self.wavfile is not None:
self.wavfile.close() self.wavfile.close()
@property
def volume(self) -> int:
"""
The volume level of the Fruit Jam audio output. Valid values are 1-20.
"""
return self._volume
@volume.setter
def volume(self, volume_level: int) -> None:
"""
:param volume_level: new volume level 1-20
:return: None
"""
if volume_level < 1 or volume_level > 20:
raise ValueError("Volume level must be between 1 and 20")
if volume_level > self.safe_volume_limit:
raise ValueError(
f"Volume level must be less than or equal to "
+ f"safe_volume_limit: {self.safe_volume_limit}. "
+ f"Using higher values could damage speakers. "
+ f"To override this limitation pass a value larger than 15 "
+ f"for the safe_volume_limit argument of the constructor."
)
self._volume = volume_level
self._apply_volume()
@property
def audio_output(self) -> str:
"""
The audio output interface. 'speaker' or 'headphone'
:return:
"""
return self._audio_output
@audio_output.setter
def audio_output(self, audio_output: str) -> None:
"""
:param audio_output: The audio interface to use 'speaker' or 'headphone'.
:return: None
"""
if audio_output == "headphone":
self._dac.headphone_output = True
self._dac.speaker_output = False
elif audio_output == "speaker":
self._dac.headphone_output = False
self._dac.speaker_output = True
else:
raise ValueError("audio_output must be either 'headphone' or 'speaker'")
def _apply_volume(self) -> None:
"""
Map the basic volume level to a db value and set it on the DAC.
"""
db_val = simpleio.map_range(self._volume, 1, 20, -63, 23)
self._dac.dac_volume = db_val