MSP Analysis Tutorial 2: Oscilloscope and Spectroscope
There are times when seeing a picture of a signal is instructive. in the real world, this is done with an oscilloscope, which shows a graph of amplitude over time. Max has two ways to do this. The old school method uses a dedicated scope~ object, and the new school method uses jitter. The new has not replaced the old, there are applications for each.
There are two problems to overcome when plotting a graph of a signal in real time. First of all, in order for your eye to follow a time-varying signal, an excerpt of the signal must be captured and displayed for a certain period of time (long enough for you really to see it). Therefore, the graph must be displayed periodically, and will always lag a bit behind what you hear. Second, there aren't enough pixels on the screen for you to see a plot of every single sample (at least, not without the display being updated at blinding speed), so the display has to use a single pixel to summarize many samples.
Old School: scope~
The scope~ object shows up as a rectangular display subdivided with a faint grid. When audio is on, there is a horizontal line showing the waveform connected to the left inlet. (This line is called the trace.) The principle of operation is simple. A group of samples is gathered and a composite value is calculated and placed at one point in a buffer. The process repeats until the buffer is full. When the buffer is full, lines are drawn from point to point across the display. The number of samples per point is set by the attribute (this can be changed by an int in the left inlet). The number of points is set by the attribute (this can be changed by an int in the right inlet). Getiing a useful display depends on the selection of and , and those depend on what you are trying to show.
When a steady signal is applied to scope~, what you see depends on the relationship between the frequency, sampling rate, and . should be as high as possible, so set it to the width of the object up to the maximun of 256. In general, the lower is, the more detail is shown, (it is effectively downsampling the waveform) so it's usually best to start at 2. Use more for very low frequency, but 16 will get you down to 10 Hz.
Chances are a steady waveform won't look too steady—it will drift across the display. (OK, it will probably whizz across the display!) The solution to this problem is the scope~ object will wait for the wave to cross the in the indicated direction before if begins a new display cycle. Thus a simple waveform will usualy show nice and steady. With a complex waveform, may need some adjustment for best results.attribute, which defaults to but should usually be set to . This will lock the display to a certain value in the waveform: . If triggering is on, the
Note how the wave slides back and forth asis changed from -1 to 1.
Sometimes we want to look at the long term behavior of a signal. This is akin to turning the sweep rate of a hardware oscilloscope way down. You see the envelope of the signal rather than the individual waves. The equivalant setting on scope~ is a high value of . 128 would be a good start. The first thing you will notice is the display takes forever to update. How long? Well, the number of samples needed to fill the dissplay is * , so divide this by the sampling rate to get the numebr of seconds between updates. With a of 128 and 256, the update time comes out 0.75 seconds. The same math will help estimate the appropriate to showing a complete waveform—you want the calculation to match the period of the wave: one over the frequency.
What do the gridlines mean?
The scope~ is divided into a grid by horizontal and vertical lines. The center horizontal line marks the zero point. The other horizontals are simply halfway to the edges. The values at the top and bottom are set by the attribute, which defaults to ±1.0. The meaning of the vertical lines depends on and . As mentioned above, the product of these divided by the sample rate determine the display period. The vertical lines divide this by 8. So if is 2 and 256, the display period will be 0.0116 at 44.1 kHz. The inverse of this gives the frequency of a waveform that would exactly fill the window, so 86.1 Hz should just fit. The time interval represented by the vertical lines is about 1.5 ms.
If you connect an audio signal to the right inlet of scope~ that signal will be used to determine the X location (left to right) of each point. If the same signal is connected to left and right, you get a diagonal line from lower left to upper right. If the signal in the right is an out of phase version of the left, the line slants the other way. When a stereo signal is connected, the result is sort of a scribble, and you can estimate the phase difference of left and right by the width and slope of the shape.
If you connect geometric waveforms to both inlets of scope~, you can generate some interesting evolving shapes. These shapes are called Lissajous figures, and are worth some exploration in themselves. The scope~ help file has some examples.
New School: jit.catch~ and jit.graph
We can also display waveforms in Jitter with the jit.catch~ and jit.plot objects. Jit.catch~ takes samples from an audio signal and packs them into a one dimensional matrix. The number of samples per matrix is set by the attribute, and has exactly the same meaning as the * calculation in scope~. Jit.catch~ has several operation modes, but the one we are interested is , which is triggered in an oscilloscope-like way. Of course jit.catch~ requires a series of bangs to prompt the output of matrices.
Jit.graph displays data in one dimensional matrices in a two dimension array of char. Connect that between jit.catch~ and a jit.pwindow, and you have a waveform display. Jit.graph also has modes, which determine the style of display:
3: Bi-polar area
Lines is the most scope-like.
The threshold feature in jit.catch~ is a bit odd in that the threshold point is always placed in the scope~ does with the same wave. The display can be further altered with the and attributes which set the values that hit the bottom or top of the display. There is also a height attribute, which sets the vertical dimension of the matrix. This should be set to match the height of the jit.pwindow to avoid size conversion artifacts.of the matrix. Thus, if you adjust , the waveform will remain centered in the display. That also means that the trigger direction ( ) has to be set in the down (1) mode to match what
The choice between using scope~ or Jitter to display audio depends on what you want to do. If an audio display is needed in the patch, scope~ is usually the best choice. If you want to process the image further à la iTunes, Jitter is the way to go.
Plotting a spectrum
Two popular buzzwords in the DSP community are time domain and frequency domain. Time domain simply means we are graphing how signal values change over time, as we have shown above. The frequency domain shows audio at one moment in time, but shows the Fourier frequency content. Thus the graph (called a spectrogram) has frequency across the bottom. You will remember the Fourier theorm states that any waveform can be deconstructed into a sum of sine waves. A spectrogram plots the amplitude of those sine waves. We will go into detail in Analysis Chapter 4: Simple Fourier Analysis. Here we will just explore a simple way to display a spectrogram.
The spectroscope~ object displays a lovely spectrogram right out of the box. The peaks in the trace show the frequency and amplitude of the partials in the triangle waveform. In an ideal system, these peaks would be thin lines, but the algorithm required to show a spectrum in real time produces "skirts" at the bottom of the peaks. The main attribute to be aware of is the frequency axis scaling, which is chosen by the attribute and shown as in the attrui. In linear mode the entire audible range of 20-22 kHz is evenly spaced left to right. The spectroscope~ display should show a nice set of evenly spaced harmonics. It's actually every other harmonic, as you can see by selecting . If you choose most of the action will be crowded into the left side. That's because music is mostly confined to a fairly low range of frequencies.
In logarithmic mode, octaves are evenly spaced across the display. The display should show a wide peak about a third of the way in. (Ignore what is to the left of the peak—the display resolution is only 43 Hz, so anything below that is garbage.) Now change the frequency to 86 Hz and note how the peak moves. As you step up octaves: 129, 172, 215, etc., the peak will move an equal amount. The peak will get narrower, too. The 43 Hz band of resolution is less of the total as we move up. Now select. The music fills the display nicely.
Both modes of display are very useful: Linear mode shows the harmonic structure of steady waveforms and logarithmic mode shows the tonal balance of music in an intuitive way.
We can get both time domain and frequency domain information in one display by choosing sonogram mode.
You should now see an image drawn with streaks of black, grey, and white. A sonogram is a two dimensional plot showing time across the bottom and frequency from bottom to top. The amplitude at each point is represented by the darkness of the color. As you listen to the music you will see how the low notes and high notes show up and even see the harmonic structure of the sound. (The attrui and choose . Now the intensity of the frequency components show as red fading through yellow and green to purple.mode affects sonograms also.) For an extra special treat, select in the
The spectroscope~ object can be customized in varioius ways, including vertical orientation, drawing or scrolling mode, reverse direction, and colors. You can also restrict the range to display to get more detail in a small speace.
The scope~ object gives an oscilloscope view of a signal, graphing amplitude over time. Waveforms can also be displayed in the Jitter matrix format by jit.catch~ and jit.graph. The spectroscope~ object can display frequency content as either a dynamic spectrogram or as a moving sonogram.
|scope~||Visualize an audio signal|
|jit.catch~||Transform signal data into matrices|
|jit.graph||Perform floating-point data visualization|
|spectroscope~||Signal spectrogram or sonogram|