Digital Signal Processing - Part 2/6
Check it out here: Github
In this blog we will cover the Karplus Strong algorithm which is a reverse delay loop, we will use python to construct a reverse delay loop.
To understand how the algorithm works let us go through some basic terms that will be used and reused throughout the digital signal processing series.
These signals repeat themselves after a certain period for infinite duration.
The general notation for periodic signals is:
They carry the same information as that of a finite length signal of length N. It is a natural bridge between finite and infinite lengths.
Building Periodic Signals
Given a discrete-time signal x[n] and an integer N > 0 we can always write formally:
This is a method of physical modelling. The signal y[n], if it exists, is an N-periodic sequence. The periodic signal y[n] is “manufactured” by superimposing infinite copies of the original signal x[n] spaced N samples apart. We can distinguish three cases:
If x[n] is finite-support and N is bigger than the size of the support, then the copies in the sum do not overlap; in the limit, if N is exactly equal to the size of the support, then y[n] corresponds to the periodic extension of x[n] considered as a finite-length signal.
If x[n] is finite-support and N is smaller than the size of the support then the copies in the sum do overlap; for each n, the value of y[n] is the sum of at most a finite number of terms.
If x[n] has infinite support, then each value of y[n] is the sum of an infinite number of terms. Existence of y[n] depends on the properties of x[n].
Delay: We signify the delay using the shifting elementary operation:
You can watch the video linked here to know more about real life applications of DSP.
Karplus Strong algorithm
Karplus Strong algorithm is a simple digital feedback loop with an internal buffer of M samples.
We loop and repeat the signal until it becomes periodic. If we supply random values to it, we will get a considerably basic harpsichord sound.
Building sound using Karplus Strong Algorithm
1. We first create a function with initial buffer x and to produce an N-Sample output.
a. To do this, we define a function, and we make a new variable with a copy of the initial signal.
b. We loop until the length of the copy of the buffer is less than N.
c. We append the copy with y and x.
d. We return the value of y and trim the excess.
2. We set the sampling rate to 16Khz.
3. With this sampling rate, since the period of the generated signal is equal to the length of the initial buffer, we will be able to compute the fundamental frequency of the resulting sound.
4. For instance, if we in it the K-S algorithm with a vector of 50 values, the buffer will fit times in a second's worth of samples or, in other words, the resulting frequency will be 320Hz, which corresponds roughly to a E4 on a piano.
5. The good thing about the Karplus Strong Algorithm is that we can use any initial buffer.
6. For this we used a random array of values.
7. We now use the initial Karplus Strong function to produce a 2 second audio clip.
a. For this we supply i.e.,
8. We now play this as an audio. The sound is remarkably similar to a harpsichord.
9. To decrease the octave, we supply a longer array to the function and play it.
10. We then implement the K-S algorithm as a signal processing loop.
11. This loop is basically the mathematical formula given above, but we take this a step further.
12. We implement the loop
13. Plotting the output from the loop gives us the following:
14. Now the sound is fading and sounds more realistic than ever, it sounds almost like a guitar.
15. It is important to note that the higher the pitch the faster its decay since
16. To compensate for that we will adjust the alpha so that all notes have a decay comparable to that of the buffer length.
17. Images below show the:
a. Adjusted alpha for the buffer length.
b. Non adjusted alpha.
1. To play music we need to realise that all western music uses the note A4 as the lock in frequency and the other notes are relative to it.
2. Here n = number of half notes. Each half note is between 2 pure notes.
C, C#, D, D#, E, F, F#, G, G#, A, A#, B
3. We have total 12 notes in the western music scale, now each of them also has an octave, for example.
C0, D0, E0, F0, G0, A0, B0, C0
4. The 0 in front of the note specifies the octave of the note.
5. To play music we use the Karplus strong Algorithm for a specific frequency that locks in with the note.
6. Each note is generated using a separate Karplus-Strong algorithm. We try to mix the different "instruments" by assigning a different gain to each note. Also, we sustain Paul's D note on the bass a bit longer by changing the corresponding decay factor.
7. We can also create harmonies by creating a set of arrays with different frequencies that lock in with the same note but with a different octave and then concatenate them and join them to play music.
Check out the notebook on Github