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 framebufferio
import picodvi
import simpleio
import storage
import supervisor
from digitalio import DigitalInOut, Direction, Pull
@ -133,13 +134,16 @@ def get_display_config():
class Peripherals:
"""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:
neopixels (NeoPxiels): The NeoPixels on the Fruit Jam board.
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._buttons = []
@ -155,11 +159,13 @@ class Peripherals:
# set sample rate & bit depth
self._dac.configure_clocks(sample_rate=11030, bit_depth=16)
# use headphones
self._dac.headphone_output = True
self._dac.headphone_volume = -15 # dB
self.audio_output = audio_output
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
sd_pins_in_use = False
@ -252,3 +258,62 @@ class Peripherals:
self.audio.stop()
if self.wavfile is not None:
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