@@ -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+
101144class 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