i2s volume control with miketeachman's firmware

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
DDude
Posts: 2
Joined: Thu May 21, 2020 8:15 pm

i2s volume control with miketeachman's firmware

Post by DDude » Thu May 21, 2020 9:40 pm

Hello all,

I just set up my ESP32 board with a PCM5102 module. I have flashed the miketeachman's firmware (Huge thanks to him !) available at https://github.com/miketeachman/micropy ... r/firmware, and every thing is working fine while using the example given on the same repo. I can hear the example sound (also downloaded on the repo) out of my hearphones connected to the jack of the PCM5012 module.

Now my issue is that I can't find a way to change the volume from software. Different sounds that I tryed seem to output at maximal volume only. So far, the only lead that I have is to play arround with the raw byte array extracted from the wav file.

If any one have done that before I would be glad to have some clue.

Example code that I am using is the following:

# The MIT License (MIT)
# Copyright (c) 2020 Mike Teachman
# https://opensource.org/licenses/MIT

# Purpose:
# - read 16-bit audio samples from a stereo formatted WAV file
# stored in the internal MicroPython filesystem
# - write audio samples to an I2S amplifier or DAC module
#
# Sample WAV file in wav_files folder:
# "side-to-side-8k-16bits-stereo.wav"
#
# Hardware tested:
# - PCM5102 stereo DAC module
#
# The WAV file will play continuously until a keyboard interrupt is detected or
# the ESP32 is reset

from machine import I2S
from machine import Pin

#======= USER CONFIGURATION =======
#WAV_FILE = 'side-to-side-8k-16bits-stereo.wav'
WAV_FILE = 'gto_wav_very_small.wav'
SAMPLE_RATE_IN_HZ = 8000
#======= USER CONFIGURATION =======

bck_pin = Pin(18)
ws_pin = Pin(21)
sdout_pin = Pin(19)

# channelformat setting:
# stereo WAV: channelformat=I2S.RIGHT_LEFT
audio_out = I2S(
I2S.NUM1,
bck=bck_pin, ws=ws_pin, sdout=sdout_pin,
standard=I2S.PHILIPS,
mode=I2S.MASTER_TX,
dataformat=I2S.B16,
channelformat=I2S.RIGHT_LEFT,
samplerate=SAMPLE_RATE_IN_HZ,
dmacount=10, dmalen=512)

wav = open(WAV_FILE,'rb')

# advance to first byte of Data section in WAV file
pos = wav.seek(44)

# allocate sample arrays
# memoryview used to reduce heap allocation in while loop
wav_samples = bytearray(2048)
wav_samples_mv = memoryview(wav_samples)

print('Starting')
# continuously read audio samples from the WAV file
# and write them to an I2S DAC
while True:
try:
num_read = wav.readinto(wav_samples_mv)
num_written = 0
# end of WAV file?
if num_read == 0:
# advance to first byte of Data section
pos = wav.seek(44)
else:
# loop until all samples are written to the I2S peripheral
while num_written < num_read:
num_written += audio_out.write(wav_samples_mv, timeout=0)
except (KeyboardInterrupt, Exception) as e:
print('caught exception {} {}'.format(type(e).__name__, e))
break

wav.close()
audio_out.deinit()
print('Done')

That's also my first post on this forum, so let me quickly introduce myself: I'm quite new in the ESP32 - micropython community. Actually, I recently switched from raspberryPi to ESP for emmbeded purpose, but also for the challenge! I have plenty of projects in my head but I will start with a simple music - press button toy for my kid (embedded an undestructible). Thanks for the help !

User avatar
Mike Teachman
Posts: 155
Joined: Mon Jun 13, 2016 3:19 pm
Location: Victoria, BC, Canada

Re: i2s volume control with miketeachman's firmware

Post by Mike Teachman » Sat May 23, 2020 12:20 am

Hey ! Welcome to the MicroPython forum :)
DDude wrote:
Thu May 21, 2020 9:40 pm
I can't find a way to change the volume from software.
I also needed volume control for an alarm clock project I'm working on. My solution was to add a new I2S helper module to my custom build. The module is called i2stools and includes a function called shift(). shift() takes a block of audio samples and performs an arithmetic (signed) shift on each audio sample (either 16 or 32 bits). Left shift = volume increase by 6dB, Right shift = volume decrease by 6dB. shift() is found in the file called i2stools.c. It is written in C, so it's fast.

Unfortunately to use this feature you will need to make a custom build. Or, perhaps someone can suggest a pure python way to do a fast arithmetic shift on a buffer of audio samples.

i2stools.c is in a github repo if you would like to try integrating it into a build. The file includes usage documentation
branch: https://github.com/miketeachman/micropy ... -littlevgl

commit when shift() was added:
https://github.com/miketeachman/micropy ... ed60c595bb

commit for integrating i2stools.c into the build:
https://github.com/miketeachman/micropy ... e170751ffd

Here is a snip of code showing volume control on a block of 16-bit audio samples

Code: Select all

import i2stools

buf_out = bytearray(SAMPLE_BUF_LEN)
audio_samples = bytearray(w.read(SAMPLE_BUF_LEN))
i2stools.shift(bufin=audio_samples, bufout=buf_out, shift=-3, format=i2stools.B16)
numwritten = audio_out.write(buf_out, timeout=0)

DDude
Posts: 2
Joined: Thu May 21, 2020 8:15 pm

Re: i2s volume control with miketeachman's firmware

Post by DDude » Sat May 23, 2020 9:53 pm

Hi @Mike Teachman, thanks a lot for your complete answer and your work. Well I was hoping not having to deal with custom build that early but I guess it's now time :D .

Post Reply