Skip to content

Commit b2f441a

Browse files
AudioFlinger: optimize volume scaling further
1 parent a60a7cd commit b2f441a

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-7
lines changed

internal_filesystem/apps/com.micropythonos.musicplayer/assets/music_player.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ def onCreate(self):
6969
self._slider_label.set_text(f"Volume: {AudioFlinger.get_volume()}%")
7070
self._slider_label.align(lv.ALIGN.TOP_MID,0,lv.pct(4))
7171
self._slider=lv.slider(qr_screen)
72-
self._slider.set_range(0,100)
73-
self._slider.set_value(AudioFlinger.get_volume(), False)
72+
self._slider.set_range(0,16)
73+
self._slider.set_value(int(AudioFlinger.get_volume()/6.25), False)
7474
self._slider.set_width(lv.pct(90))
7575
self._slider.align_to(self._slider_label,lv.ALIGN.OUT_BOTTOM_MID,0,10)
7676
def volume_slider_changed(e):
77-
volume_int = self._slider.get_value()
77+
volume_int = self._slider.get_value()*6.25
7878
self._slider_label.set_text(f"Volume: {volume_int}%")
7979
AudioFlinger.set_volume(volume_int)
8080
self._slider.add_event_cb(volume_slider_changed,lv.EVENT.VALUE_CHANGED,None)

internal_filesystem/lib/mpos/audio/stream_wav.py

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,49 @@ def _scale_audio_rough(buf: ptr8, num_bytes: int, scale_fixed: int):
9898
buf[i] = sample & 255
9999
buf[i + 1] = (sample >> 8) & 255
100100

101+
@micropython.viper
102+
def _scale_audio_shift(buf: ptr8, num_bytes: int, shift: int):
103+
"""Rough volume scaling for 16-bit audio samples using right shifts for performance."""
104+
if shift <= 0:
105+
return
106+
107+
# If shift is 16 or more, set buffer to zero (volume too low)
108+
if shift >= 16:
109+
for i in range(num_bytes):
110+
buf[i] = 0
111+
return
112+
113+
# Apply right shift to each 16-bit sample
114+
for i in range(0, num_bytes, 2):
115+
lo: int = int(buf[i])
116+
hi: int = int(buf[i + 1])
117+
sample: int = (hi << 8) | lo
118+
if hi & 128:
119+
sample -= 65536
120+
sample >>= shift
121+
buf[i] = sample & 255
122+
buf[i + 1] = (sample >> 8) & 255
123+
124+
@micropython.viper
125+
def _scale_audio_powers_of_2(buf: ptr8, num_bytes: int, shift: int):
126+
if shift <= 0:
127+
return
128+
if shift >= 16:
129+
for i in range(num_bytes):
130+
buf[i] = 0
131+
return
132+
133+
# Unroll the sign-extend + shift into one tight loop with no inner branch
134+
inv_shift: int = 16 - shift
135+
for i in range(0, num_bytes, 2):
136+
s: int = int(buf[i]) | (int(buf[i+1]) << 8)
137+
if s & 0x8000: # only one branch, highly predictable when shift fixed shift
138+
s |= -65536 # sign extend using OR (faster than subtract!)
139+
s <<= inv_shift # bring the bits we want into lower 16
140+
s >>= 16 # arithmetic shift right by 'shift' amount
141+
buf[i] = s & 0xFF
142+
buf[i+1] = (s >> 8) & 0xFF
143+
101144
class WAVStream:
102145
"""
103146
WAV file playback stream with I2S output.
@@ -330,6 +373,12 @@ def play(self):
330373
# 6144 => audio stutters and quasibird at ~17fps
331374
# 7168 => audio slightly stutters and quasibird at ~16fps
332375
# 8192 => no audio stutters and quasibird runs at ~15fps
376+
# with shift volume scaling:
377+
# 6144 => audio slightly stutters and quasibird at ~16fps?!
378+
# 8192 => no audio stutters, quasibird runs at ~13fps?!
379+
# with power of 2 thing:
380+
# 6144 => audio sutters and quasibird at ~18fps
381+
# 8192 => no audio stutters, quasibird runs at ~14fps
333382
chunk_size = 8192
334383
bytes_per_original_sample = (bits_per_sample // 8) * channels
335384
total_original = 0
@@ -363,10 +412,8 @@ def play(self):
363412
raw = self._upsample_buffer(raw, upsample_factor)
364413

365414
# 3. Volume scaling
366-
scale = self.volume / 100.0
367-
if scale < 1.0:
368-
scale_fixed = int(scale * 32768)
369-
_scale_audio_optimized(raw, len(raw), scale_fixed)
415+
shift = 16 - int(self.volume / 6.25)
416+
_scale_audio_powers_of_2(raw, len(raw), shift)
370417

371418
# 4. Output to I2S
372419
if self._i2s:

0 commit comments

Comments
 (0)