|
8 | 8 | import sys |
9 | 9 | import time |
10 | 10 |
|
| 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 | + |
11 | 15 | # Volume scaling function - Viper-optimized for ESP32 performance |
12 | 16 | # NOTE: The line below is automatically commented out by build_mpos.sh during |
13 | 17 | # 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): |
141 | 145 | buf[i] = s & 0xFF |
142 | 146 | buf[i+1] = (s >> 8) & 0xFF |
143 | 147 |
|
| 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 | + |
144 | 163 | class WAVStream: |
145 | 164 | """ |
146 | 165 | WAV file playback stream with I2S output. |
@@ -400,8 +419,8 @@ def play(self): |
400 | 419 | ) |
401 | 420 |
|
402 | 421 | 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 |
405 | 424 |
|
406 | 425 | print(f"WAVStream: {original_rate} Hz, {bits_per_sample}-bit, {channels}-ch") |
407 | 426 | print(f"WAVStream: Playback at {playback_rate} Hz (factor {upsample_factor})") |
@@ -523,7 +542,24 @@ def play(self): |
523 | 542 | scale = self.volume / 100.0 |
524 | 543 | if scale < 1.0: |
525 | 544 | 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) |
527 | 563 |
|
528 | 564 | # 4. Output to I2S (blocking write is OK - we're in a separate thread) |
529 | 565 | if self._i2s: |
|
0 commit comments