Cornell University ECE4760
Partial Differential Equation string synthesis

Pi Pico RP2350

PDE string and user interface
Sound is generated by solving the difference equation of a string, then sending the amplitude at one string node to the DAC. If you can solve it fast enough, you can play the solution through the DAC to make sounds. Since you are solving a string, if you give it a non-zero initial condition then it should sound like a plucked string. Adding an approximate bowing function to drive the string allows adding periodic energy to the string during the solution. On the rp2350, the floating point version produces a new audio sample at 40 Ksample/second rate.

The actual string sample update is performed by numerical solution of the wave equation.
Study Notes on Numerical Solutions of the Wave Equation with the Finite Difference Method, equation 2.15 yields the finite difference form to step the solution forward one sample.

Where un+1 is the displacement at the new time step and i represents the distance along the string. ρ is the propagation speed (range 0 to 1.0 for Courant stability). η is the dissipation which is small (typically 0.001 or so). Because η is small, we can Taylor expand and show that

Rho sets the fundamental frequency of the string.
F = Fs*sqrt(rho)/(2*(string_size-2))
Where F is the string fundamental, and Fs is the synthesis rate 1/delta_t.
The numerical stability (Courant stability) requires rho<1.0 which limits the top frequency
for a given length string.

Physical bow model.
we want to simulate moving a bow across the string, using a reasonable physical model for the string-bow interaction. The model used is a simplified version of the model in Two-Polarisation Physical Model of Bowed Strings with Nonlinear Contact and Friction Forces, and Application to Gesture-Based Sound Synthesis by Charlotte Desvages and Stefan Bilbao.
If (dui)/dt is the string velocity at some point on the string, i, and vbow is the bow speed set by the user, then define
Vrel = (dui)/dt - vbow
and the input force added to the PDE solution at point i is
Fbow = Abow * sign(Vrel) * (eps + exp(-abs(Vrel)/v_width))
Where Abow is a drive force, v_width is a speed scale, and eps is a small constant, all set by the user.
In the curent code, the exponential is replaced by unity for small absolute relative velocity, and zero for values greater than v_width.
The input force Fbow*0.5 is assigned to points i-1 and i+1 and Fbow*0.25 is assigned to points i-2 and i+2 to reduce spatial aliasing.
You can control the bow speed, vbow, the applied bow pressure, Abow, and
two parameters related to how sticky the bow is at low speed, v_width, and eps,
which set the level of speed-independent stickyness.

Plucking the string at the start of the solution.
Each position on the string is given a different initial position and initial velocity of zero.
The pluck waveform can be one of:

I tend to start with a Gaussian pulse and use the others if I want a metallic sound.

The parameters and user interface.
To use this program, you need to hook up an SPI DAC plus speakers, and a serial terminal. Connections are given in the lengthy comment at the start of the source code.
The serial input supports the settable parameters for a sound, plus play and stop commands:

The serial interface has a little formating to make it look nice.
It is full screen, formatted, and has some color-control. Parameters at the top of the screen are updated with each command.
All commands are listed in green. After typing a command and hitting <enter>, the screen updates in less than 60 mSec.
A bad command gives a message and returns to the command prompt.

Example sounds:


Code, Project ZIP


Copyright Cornell University February 14, 2025