Ph LU Te

Author: Scott Gravenhorst

Verilog, designed for Spartan-3E SK, certainly adaptable for others.

Digital Waveguide phLUTe


This project is an FPGA based MIDI monophonic synthesizer implementing a digital waveguide physical model of an open ended cylindrical bore excited by a jet of air. The design is based on Perry Cook's slide-flute model. This model changes pitch by changing the length of the waveguides (making sure that the bore delay line is always twice the length of the jet delay line). The state machine to perform the functions required currently uses 14 clocks (50 MHz) and one for init. The output sample rate of the synth is 100 KHz.

Access to the system is provided by an embedded MIDI controller.

Block Diagram

The reflection filter is a first order lowpass IIR filter. a0 and b1 (not shown in the drawing) are the reflection filter control parameters. These numbers can be performance controls and can be used to limit or enhance the ability of the model to period halve when overblown. R is the DC blocker parameter (and is not a performance control). R is set to the nominal value of 0.995. SCL1 and SCL2 are bore waveguide feedback scaling values which control the resonant behavior of the system. They are performance values. Nominally they are SCL1=.50 and SCL2=.55. Changing them changes the character of the sound and period halving behavior. The performance control values can receive input from various MIDI continuous controllers.

The block diagram represents the instrument when it is being energized. The cubic polynomial nonlinearity is an approximation of the nonlinearity present in a real flute when the jet is present. When the jet is not present, neither is the nonlinearity. In my implementation, the design zeros the output of the nonlinearity when the envelope value is equal to zero. If this is not done, the system will continue to oscillate even in the absence of the jet.

This is a work in progress. At this point, I've tested C versions of the logic required in fixed point binary using both 18 bit signed integer and 32 bit signed integer arithmetic. I've translated the C code into Verilog.

The FPGA version is now working at a basic level. The instrument's range spans 5 octaves starting at middle C.

Issues Encountered:

One main issue encountered during development was that the model would not resonate with a seemingly random, but consistent collection of notes. Examination of the C version's output number stream indicated that because the Lagrange interpolators use very small numbers, loss of significant digits was causing the output to be zero when the interpolator delay amount was near 1.0. This was fixed by both increasing calculation width to 35 bits signed from 18 bits signed and by adjusting the Lagrange interpolator subtrahend by a factor of 2^19 and then dividing the multiplier product by 2^19 to restore proper magnitude. This fixed the dead notes and also provides a much more consistent waveform and tonal quality from note to note.

The remaining issue is that the bore takes a long time to begin resonating from zero signal, especially at long wavelengths. A Model Adjustment Program (MAP) is being developed so that easy experimentation can be done with jet force magnitude, the jet force ADSR and other factors. I believe the reason for this slow rise to resonation is caused by a poor model of the jet. I will try bandwidth limited noise (with a ROM so that both a filter parameter and an amplitude corrector can be implemented for each note of the scale) as a better model since bandwidth limited noise will have more energy at lower frequencies than will straight white noise.

Once the model begins to resonate, the tone is very flute like. The model also exhibits flute like performance behavior in overblowing.

Band limiting the noise did not help.

I noticed that my C implementation does the same thing, so it seems inherent in this simple model. Feedback scale #2 has an affect on both waveform and a kind of overall gain. I believe that it's nominal value of 0.55 shows a model at resonance. In my C implementation, I added an envelope to control it's value from 0.99 at start (from 0 signal in the delay line) ending at 0.55. This works the get the bore at full amplitude quickly. At the same time, I see a good deal of harmonic activity during the first second or so. I also noticed that higher frequency notes need a much faster decay than lower ones, distortion results. Next to add a ROM and an ADSR to control feedback scale 2. I suspect it will not give a classical flute attack sound. But it could be interesting anyway.

The ADSR experiment was interesting and it seems to help. I'm now thinking more about a servo loop using the conditions in the bore to calculate an optimum value for scale 2. I can use an absolute value process to make DC out of my bore signal. This DC signal can then be used to calculate the scale 2 value. The more signal in the bore, the closer scale 2 should be to .55. The less DC signal, the closer to .9999 it should be. Abs(bore) to a single pole IIR should make an envelope follower which I will try next.

An envelope follower driving the servo speeds up bore resonance and may also be contributing to the ability of the instrument to do what I call Jovian trill harmonics. Certain trills cause the bore to begin resonating at one of several different harmonics. If one note is held after playing one of these trills, the harmonic continues to resonate for several seconds or indefinately depending on how pure the harmonic is.

I found the bits that did the ADSR level control were just wrong. Fixed them and now I get a much more expressive instrument. I also found the cause of some annoying distortion associated with the transient caused by bore length changes. This was caused by summers that were allowed to wrap. I fixed that with detection and clipping instead of wrapping.

Features I would like to add:

  • Polyphonic version - I think 4 bores are possible.

When I have finished making a usable musical instrument out of this, I will post code.

Here is a sample of some note changes and overblowing. The pops at note changes are caused by transients generated when the instrument changes pitch. A slight portamento should help. <- actually portamento did NOT help and made the instrument either sound silly or it caused a zipper effect during pitch changes in the low register.

A Mozart string quartet played with phLUTes:

Much of the quartet sounds very much like flutes, but there are parts that sound almost brassy and others that sound like bowed strings. These characteristics are controllable to a good degree using the model adjustment program.

The phLUTe playing the 1st violin part is given an increased velocity, so it will often be overblown. The phLUTe playing the 2nd violin is more tame playing it's fundamental. The lower phLUTes playing viola and cello parts go in and out of an overblown state with less velocity because the model overblows easier on lower notes.

From the looks of the resource usage in an XC3S500E FPGA, there is room for as many as 4 phLUTes total in this design (without using external RAM). There is also plenty of time to calculate 4 instances in the state machine. I may move to a polysynth version at some later time.

This project ended without a design I like. Mainly due to the transient generated when the waveguide length is changed.

I've decided to revive this project and have re-examined the model implementation finding some curious things. I noticed that the code uses the MCU's gate signal to mute the bore. This should not be necessary! The bore/jet system seems to self oscillate once first excited. First guess is that one or more components has too much gain. I noticed that the muting has been present in every version. If I remove the mute logic, the system oscillates after excitation. I have changed FBscale2 to be adjustable by mod wheel from 0.5 to just above 0.55. At 0.5, the oscillation will fade to zero. I will examine all of the other components that could contribute gain and make sure the settings are accurate and that there isn't some arithmetic anomoly contributing to some extra unwanted gain.