Skip to content

Added volume control (for Pico) #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions examples/easy_wav_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@

elif os.uname().machine.count("Raspberry"):
from sdcard import SDCard
from machine import SPI
from machine import SPI, ADC

cs = Pin(13, machine.Pin.OUT)
spi = SPI(
Expand Down Expand Up @@ -84,6 +84,10 @@
I2S_ID = 0
BUFFER_LENGTH_IN_BYTES = 40000
# ======= I2S CONFIGURATION =======

# ======= ADC CONFIGURATION =======
adc = ADC(0) # ADC0 corresponds to GPIO26 on Raspberry Pi Pico
# ======= ADC CONFIGURATION =======

elif os.uname().machine.count("MIMXRT"):
from machine import SDCard
Expand Down Expand Up @@ -116,10 +120,14 @@
# wait until the entire WAV file has been played
while wp.isplaying() == True:
# other actions can be done inside this loop during playback
adc_value = adc.read_u16() # Read 16-bit ADC value (0-65535)
volume = adc_value / 65535 # Normalize to 0.0 - 1.0
wp.set_volume(volume)
time.sleep(0.05)
pass

wp.play("music-16k-16bits-mono.wav", loop=False)
time.sleep(10) # play for 10 seconds
wp.pause()
time.sleep(5) # pause playback for 5 seconds
wp.resume() # continue playing to the end of the WAV file
wp.resume() # continue playing to the end of the WAV file
46 changes: 45 additions & 1 deletion examples/wavplayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,46 @@ def __init__(self, id, sck_pin, ws_pin, sd_pin, ibuf, root="/sd"):
# allocate audio sample array buffer
self.wav_samples_mv = memoryview(bytearray(10000))

# Initialize volume control variable (0.0 to 1.0)
self.volume = 1.0
self.volume_int = 256 # 256 corresponds to 1.0 in fixed-point representation

def set_volume(self, volume):
if 0 <= volume <= 1:
self.volume = volume
self.volume_int = int(volume * 256) # Scale to 0-256
else:
raise ValueError("Volume must be between 0.0 and 1.0")

@micropython.viper
def adjust_volume_16bit(self, data_in: ptr8, length: int, volume_int: int):
data = ptr8(data_in)
n = int(length // 2)
for i in range(n):
# Read two bytes and combine them into a signed 16-bit integer
low = int(data[2 * i])
high = int(data[2 * i + 1])
sample = (high << 8) | low
if sample >= 32768:
sample -= 65536 # Convert to signed int16

# Adjust volume
sample = (sample * volume_int) >> 8

# Clip to int16 range
if sample > 32767:
sample = 32767
elif sample < -32768:
sample = -32768

# Convert back to unsigned int16
if sample < 0:
sample += 65536

# Store back into data buffer
data[2 * i] = sample & 0xFF
data[2 * i + 1] = (sample >> 8) & 0xFF

def i2s_callback(self, arg):
if self.state == WavPlayer.PLAY:
self.num_read = self.wav.readinto(self.wav_samples_mv)
Expand All @@ -69,6 +109,10 @@ def i2s_callback(self, arg):
_ = self.wav.seek(self.first_sample_offset)
_ = self.audio_out.write(self.silence_samples)
else:
# Adjust volume
if self.bits_per_sample == 16:
volume_int = self.volume_int # Integer between 0 and 256
self.adjust_volume_16bit(self.wav_samples_mv, self.num_read, volume_int)
_ = self.audio_out.write(self.wav_samples_mv[: self.num_read])
elif self.state == WavPlayer.RESUME:
self.state = WavPlayer.PLAY
Expand Down Expand Up @@ -181,4 +225,4 @@ def isplaying(self):
if self.state != WavPlayer.STOP:
return True
else:
return False
return False