Skip to content

Commit 71e1ea8

Browse files
stream_wav.py: add hardware volume control
uses shift but doesn't seem to work
1 parent 0cc1ca0 commit 71e1ea8

1 file changed

Lines changed: 39 additions & 3 deletions

File tree

internal_filesystem/lib/mpos/audio/stream_wav.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
import sys
99
import time
1010

11+
# Toggle to enable I2S.shift-based volume scaling when available.
12+
# Set to False to use legacy software scaling only.
13+
USE_I2S_SHIFT_VOLUME = False
14+
1115
# Volume scaling function - Viper-optimized for ESP32 performance
1216
# NOTE: The line below is automatically commented out by build_mpos.sh during
1317
# Unix/macOS builds (cross-compiler doesn't support Viper), then uncommented after build.
@@ -141,6 +145,21 @@ def _scale_audio_powers_of_2(buf: ptr8, num_bytes: int, shift: int):
141145
buf[i] = s & 0xFF
142146
buf[i+1] = (s >> 8) & 0xFF
143147

148+
149+
# Would be faster to use a lookup table here
150+
def _volume_to_shift(scale_fixed):
151+
"""Convert fixed-point volume (0..32768) to a right-shift amount (0..16)."""
152+
if scale_fixed >= 32768:
153+
return 0
154+
if scale_fixed <= 0:
155+
return 16
156+
shift = 0
157+
threshold = 32768
158+
while shift < 16 and scale_fixed < threshold:
159+
shift += 1
160+
threshold >>= 1
161+
return shift
162+
144163
class WAVStream:
145164
"""
146165
WAV file playback stream with I2S output.
@@ -400,8 +419,8 @@ def play(self):
400419
)
401420

402421
self._playback_rate = playback_rate
403-
#ibuf = playback_rate # doesnt account for stereo vs mono...
404-
ibuf = 32000
422+
# ibuf = playback_rate # doesnt account for stereo vs mono...
423+
ibuf = 32000
405424

406425
print(f"WAVStream: {original_rate} Hz, {bits_per_sample}-bit, {channels}-ch")
407426
print(f"WAVStream: Playback at {playback_rate} Hz (factor {upsample_factor})")
@@ -523,7 +542,24 @@ def play(self):
523542
scale = self.volume / 100.0
524543
if scale < 1.0:
525544
scale_fixed = int(scale * 32768)
526-
_scale_audio_optimized(raw, len(raw), scale_fixed)
545+
if (
546+
USE_I2S_SHIFT_VOLUME
547+
and self._i2s
548+
and hasattr(self._i2s, "shift")
549+
):
550+
shift = _volume_to_shift(scale_fixed)
551+
if shift >= 16:
552+
for i in range(len(raw)):
553+
raw[i] = 0
554+
elif shift > 0:
555+
try:
556+
self._i2s.shift(raw, 16, shift) # triggers exception
557+
except Exception as e:
558+
print(f"_i2s.shift got exception, falling back to software scaling: {e}")
559+
_scale_audio_optimized(raw, len(raw), scale_fixed)
560+
else:
561+
print("_i2s has no shift attribute, falling back to software scaling")
562+
_scale_audio_optimized(raw, len(raw), scale_fixed)
527563

528564
# 4. Output to I2S (blocking write is OK - we're in a separate thread)
529565
if self._i2s:

0 commit comments

Comments
 (0)