PDM to PCM audio conversion

Hi everyone,
I am currently following the thread on this git repo: Error in setup · Issue #1 · wady101/PYNQ_Z2-Audio · GitHub . In this repo there is a modified version of Pynq where I can get directly the audio stream, but I have found that is encoded as PDM, whereas I need PCM encoding. Is there a way to have a conversion to PCM? I have tried to use a lowpass filter but is not working, so I am trying to implement manually a sinc3 filter but it seems not working. Here is the code:

def process(self):

    k = 0
    for i in range(0, len(self._input_signal)):
        
        if self._input_signal[i] == 1:
            self._acc1 = self._acc1 + 1
        self._acc2 = self._acc2 + self._acc1
        self._acc3 = self._acc3 + self._acc2
        
        if i == (self._decimation_factor-1)*(k+1):
            self._diff1 = self._acc3 - self._acc3_d2
            self._diff2 = self._diff1 - self._diff1_d
            self._diff3 = self._diff2 - self._diff2_d
            self._acc3_d2 = self._acc3
            self._diff1_d = self._diff1
            self._diff2_d = self._diff2
            self._data[k] = self._diff3
            k = k + 1

    return self._data 

Do you have any suggestions?

Thanks in advance,

Guglielmo

Unsure if this will work for your case, but this is how I’ve accomplished PDM → PCM/WAV audio translation on the PYNQ-Z1 in the past. It makes use of numpy and scipy:

import numpy as np
from scipy import signal

“”"
Step 1: Preprocessing
In this step, we first convert the 32-bit integer buffer to 16-bit.
Then we divide 16-bit words (16 1-bit samples each) into 8-bit words with 1-bit sample each.
“”"
def preprocess(audio_buffer):

af_uint8 = np.unpackbits(audio_buffer.astype(np.int16).byteswap(True).view(np.uint8))
return af_uint8

“”"
Step 2: Converting PDM to PCM
We now convert PDM to PCM by decimation. The sample rate is reduced from 3MHz to 32kHz.
We will remove the first and last 10 samples in case there are outliers introduced by decimation.
We will also remove the DC offset from the waveform.
“”"
def convert(af_uint8):

af_dec = signal.decimate(af_uint8, 8, zero_phase=True)
af_dec = signal.decimate(af_dec, 6, zero_phase=True)
af_dec = signal.decimate(af_dec, 2, zero_phase=True)
af_dec = (af_dec[10:-10] - af_dec[10:-10].mean())
return af_dec

First preprocess() must be invoked for a buffer of PDM audio data (for my use case, audio_buffer was the singleton AudioDirect IP object’s buffer, accessed as BaseOverlay('base.bit').audio.buffer, but perhaps it will work for you by passing your _input_signal buffer). So this code may work for you like:

pcm_audio = convert(preprocess(self._input_buffer))

I’m not sure if this will, but I hope this can help somewhat.