6.2 Implementation
Last updated
Was this helpful?
Last updated
Was this helpful?
Below are the LPC utility functions provided in the .
The function ld
(for performing the Levinson-Durbin recursion) is not suitable for a microcontroller C implementation, as we have array operations (np.dot
) and memory is allocated on the fly (np.r_
concatenates values into a new row vector).
We will therefore re-implement the ld
function so that porting it to C will be much more straightforward. Below we provide you an incomplete function ld_eff
that is meant to implement Levinson-Durbin recursion in a "C-friendly" manner.
As for bac
, for our microcontroller implementation of ld_eff
in C
, we may wish to pre-allocate global arrays for a
and a_prev
.
process
functionIn fact, it is possible to use the same function for "vanilla" and LPC granular synthesis pitch shifting. We can do this by introducing a boolean variable use_LPC
.
We can now begin adding the code for LPC! Let's remind ourselves of the steps we mentioned in the previous section:
Hints:
You can rewrite into the concatenated raw samples vector, NOT input_buffer
!
Don't forget to apply GAIN
!
This is already done with your code from the granular synthesis effect!
Hints:
We are applying an IIR filter in this case.
You can rewrite into the resampled grain vector.
Use lpc_prev_out
for the previous output samples.
If you notice some strange output, make sure you are casting (when appropriate) to int
; this is a common point for mistakes.
Congrats on incorporating this LPC component to your granular synthesis pitch shifter! Given the Python implementation, the porting to C should be more straightforward. As noted earlier, it may be useful to pre-allocate memory for the LPC coefficients and their computation.
The function bac
is sufficient from a real-time microcontroller "point of view" as it performs operations sample-by-sample in order to compute the entries of the (biased) autocorrelation matrix . For our microcontroller implementation in C
, we may, however, wish to pre-allocate a global array for r
, as its values will change for each grain.
TASK 1: Complete the above function ld_eff
in the file so that it correctly implements Levinson-Durbin recursion.
Hint: we refer you to (p. 5) in order to determine the correct expression for k
and a[j]
.
You can test your implementation by running the script . The script should print CORRECT!
if you have successfully implemented the function; otherwise it will print Something's wrong...
or error out if you have a bug in your implementation.
Below, we provide the incomplete process
function, which you can find in .
TASK 2: As a sanity check, you can first copy your code from your granular synthesis implementation into the above process
function and the init
function in the script . (Copy the appropriate lines under the comments # copy from granular synthesis
.)
We are applying an FIR filter in this case; recall your implementation from the Digital Filter Design chapter, notably the code from . In this case input_buffer
should be the concatenated raw samples vector, x
should be lpc_prev_in
, and there is no equivalent to y
since this is an FIR filter.
And that's all the extra code needed for this LPC feature! Try out your completed script with the fixed WAV file (make sure use_LPC=True
) and listen to the output to see if it sounds correct.
TASK 6: When your implementaton works with the fixed WAV file, you can complete the in order to run the effect in real-time with your laptop's soundcard.
In the , we implement a DFT-based pitch shifter. With this effect, we will shift our speech up in order to create a chipmunk-like voice; no need to inhale helium!