home *** CD-ROM | disk | FTP | other *** search
- FFT.HMSL
-
- version 1.0
- September 19, 1988
-
-
- INTRODUCTION
-
- FFT stands for Fast Fourier Transform. There are a variety of ways to
- describe what a Fourier Transform is and what it does.
- I'll stick to a purely musical description, specifically:
- what a Fourier Transform does to a sound sample.
- The FFT accepts a sequence of sample points as input, and outputs
- the energies contained in its partials. A single FFT tells you nothing about
- how a sound changes over time, only that its first partial has "this" much
- power, its second "this" much, its third "that" much, etc. Timbres are
- completely describable in terms of how much energy is contained in the
- various partials.
- However, most sounds change considerably from start to finish. The
- strategy, then, is to do a sequence of small FFT's on little chunks of the
- sample, maybe 32 points at a time. This 32 point spread is called a "window".
- The window scoots along the sample, taking FFT's at every stop. What you're
- finally left with is a nice report of how each partial of the original sound
- changed over time. This is what the routine FFT.H does.
- An inverse Fourier Transform does the opposite: it recombines all the
- partials into a single sound sample. This is done by the routine IFFT.H
- The power of these two routines is dramatic. After doing an FFT.H on
- a sound, you can go in and change partials around: delete some, invert others,
- reverse them, draw your own, write routines to generate or alter them in
- ways that God never intended. Then run the IFFT.H routine to recombine them,
- and listen to your new sound! Or create sounds from scratch by using IFFT.H
- alone.
-
- ************************** RUNNING THE CODE ******************************
-
- PLEASE DO THE TUTORIAL BEFORE YOU TRY THIS SECTION!!!!!!!!
-
- 1) Get HMSL up and running.
-
- 2) INCLUDE 4th:FFT/FFT.HMSL ( read file READMEFIRST about renaming disk. etc)
- If your version of JForth is v1.2, edit the file X*.ASM and remove the
- HASH.ON and HASH.OFF lines before you do this.
-
- 3) Load up a sample into any OB.SAMPLE like this:
- " MY-SOUND-FILE" LOAD: SAMPLE-IN
- I instantiated two sample objects: SAMPLE-IN and SAMPLE-OUT in this file.
- Use them for convenience only; the code doesn't rely on them.
-
- 4) Now type INIT.FFT.HMSL (you only have to do this step once, even if you
- load other samples later)
-
- 5) To run the FFT routine, type:
- SAMPLE-IN FFT.H
-
- 6) wait a while (roughly 12 seconds for a sample with 2048 points)
-
- 7) get the shape editor up by typing HMSL, and you'll see two objects
- in there called MAGNITUDES and PHASE INDICES. MAGNITUDES is the shape
- which contains the amplitudes of the various partials. Flip through
- the dimensions.
- PHASE INDICES might look a bit anti-intuitive. Its even numbered
- dimensions store phase angle information in terms of index values to
- a trig lookup table instead of in terms of degrees. This is done so
- for speed, and is extremely necessary.
- Odd numbered dimensions contain -1's and 0's, which store the signs of
- some values needed for the IFFT.
- Hit the close box to get back.
-
- 8) To run the inverse FFT routine, instantiate a target sample: let's say
- OB.SAMPLE SAMPLE.OUT
- and type:
- SAMPLE-OUT IFFT.H
-
- 9) wait a while.
-
- 10) listen to the result START: SAMPLE-OUT
-
- IMPORTANT:
- If you look through the source code, you'll see that the FFT.H and IFFT.H
- routines don't necessarily expect OB.SAMPLE's. You can pass them OB.ARRAY's
- if you care to. The data width of the object you pass it is also variable,
- so any of you who have routines for loading samples from external samplers
- should bear this in mind.
-
- *************************** CHANGING PARAMETERS *****************************
-
- As mentioned above, a "window" creeps over your sample, taking FFT's as
- it goes. The size of the window defaults to 32, which you can change with
- SET.WINDOW.SIZE ( size -- ). Just don't try any size that's not a power
- of 2. Use 2, 4, 8, 16, 32, 64, 128, or 256. I've never tried values that
- aren't in this list, but I'm not too curious about what would happen to tell you
- the truth.
- The FFT presumes that the width of the window = width of the lowest period
- in the sample.
- At 10k sample rate, window size of 32 means the lowest frequency you can
- resolve is about 312 Hz. A window size of 64 means you can do pretty well
- down to around 156 Hz. The tradeoff: The wider the window, the coarser
- the detail of spectral change over time. On the other hand, a narrow window
- will yield few partials. The number of partials generated equals half the
- window size. You'll get 16 partials with a 32 wide window.
-
- The amount of the sample you want to work with can be set with
- SET.SAMPLE.SIZE ( size -- ). It defaults to 2048. This means you'll be running
- the FFT on the first 2048 values of your input sample, and that your output
- sample will be allocated a size of 2048. If your input sample has more
- than 2048 points, the rest will be ignored, if it has less, the surplus will
- be padded with zeros. The input sample will be unharmed in any case.
-
-
- *************** A LITTLE MORE ON MAGNITUDES and PHASE-INDICES ***********
-
- The number of dimensions in these shapes correspond to the number of
- partials generated by the FFT. This number depends on the window size.
- A window 64 wide will generate 32 partials (half).
- MAGNITUDES would in this case have 33 dimensions; one for each partial
- and an extra dimension that stores a very important value:
- the WINDOWSIZE/2+1st "partial".
- PHASE-INDICES will have 64 dimensions: two for each of 32 partials
- ( one to hold the index to a sine lookup table, one to hold on to the
- sign of the real component generated by the FFT).
- The number of elements (MANY:) in these two shapes will equal the sample
- size you set divided by the window size.
- Looking at MAGNITUDES in the shape editor means you can click through the
- partials and see how the magnitude of that partial changes over the course
- of the sample. You can and should mess with them. Same with
- PHASE-INDICES: each even numbered dimension will show you how the phase
- relationships of the sample's partials change over time, while the odd
- numbered dimensions hold 0 or -1, used for IFFT.
-
- ********************************* TOOLS **************************
-
- To get some nice tools to make your acoustic debauchery faster and easier,
-
- INCLUDE FFT.TOOLS
-
- Here's a glossary of words contained in this file
-
-
- COMPARE.THEM ( start -- )
- testing only. Prints values from SAMPLE-IN and SAMPLE-OUT starting at
- start, continuing until terminal hit. Used to compare original sample
- with sample after FFT.H and IFFT.H
-
-
- ENV-TEMPLATE
- This is not a word, this is an OB.SHAPE used to generate n-stage magnitude
- envelopes. It has two dimensions. Dimension 0 is an increasing series
- of values, and should not be altered unless low-to-high ordering is preserved.
- Dimension 1 contains "magnitude" values. The "shape" of this dimension
- is used to carve out a nearly identical profile in any dimension of
- MAGNITUDES.
- see STAGE.ENVELOPE, FILL.DIM.ENV
-
- FILL.DIM.ENV ( dimension -- )
- Creates a new set of points in selected MAGNITUDES dimension. Uses INTERP
- between values in ENV-TEMPLATE.
- example:
- 5 FILL.DIM.ENV
- takes the current n-stage envelope prescribed by ENV-TEMPLATE and leaves
- the fifth MAGNITUDE dimension filled with values that follow the profile
- of ENV-TEMPLATE.
-
- FILL.DIM.MAG ( value dim -- )
- Fills magnitude values of a given partial with given value.
-
-
- FILL.DIM.PHASE ( value dim -- )
- Fills phase values of a given partial with given value.
-
-
- INIT.INSTRUMENTS ( -- )
- Used for testing. Loads the object SAMPLE-IN into INS-AMIGA-1
- and SAMPLE-OUT into INS-AMIGA-2. Puts TUNING-EQUAL into these instruments.
-
-
-
- PLAY.BOTH ( end-note start-note -- )
- Used for testing. Plays SAMPLE-IN and SAMPLE-OUT alternately up selected
- range of notes by NOTE.ON:ing INS-AMIGA-1 and INS-AMIGA-2
- INIT.INSTRUMENTS first.
-
- PLAY.OUT ( end-note start-note -- )
- Used for testing. Plays SAMPLE-IN up selected
- range of notes by NOTE.ON:ing INS-AMIGA-2
- INIT.INSTRUMENTS first.
-
- PLOT.M ( -- )
- Plots contents of MAGNITUDES in mountain-style graph. Only plots
- 50 elements, so if MAGNITUDES has, say, 200 elements, PLOT.M will plot
- every 4th.
- Frequency increases left to right, time axis increases "away" from you.
- Magnitude is vertical.
-
- PLOT.FIRST.50 ( -- )
- Plots first 50 elements of MAGNITUDES.
- A nice detailed look at the attack portion of your sound.
-
- STAGE.ENVELOPE ( #stages -- )
- Sets up how many stages in magnitude envelope. Initializes ENV-TEMPLATE.
- Initializes all with value 30.
- example:
- 10 STAGE.ENVELOPE
- sets up a 10 point envelope that you can edit and apply to any MAGNITUDE
- dimension with FILL.DIM.ENV
-
-
- ZERO.DIM.MAG ( dim# -- )
- zeros out all magnitude values of a given partial
- same as 0 dim# FILL.DIM: MAGNITUDES.
-
-
- ZERO.ALL.MAG ( -- )
- zeros out all magnitude values of all partials.
-
-
- ZERO.DIM.PHASE ( dim# -- )
- zeros out all phase values of a given partial
-
-
- ZERO.ALL.PHASE
- zeros out all phase values of all partials.
-
-
-
-
- ************************** A QUICK TUTORIAL ******************************
-
- We'll run various routines on the sample P2. This sound, by the way, is
- the second note of the Indonesian Pelog scale, as sampled from an instrument
- I borrowed from Gamelan Son of Lion (NYC based new music group).
-
- Load up HMSL and CD 4th:fft ( read file READMEFIRST about renaming disks, etc)
-
- 1) INCLUDE FFT.HMSL
- If your version of JForth is v1.2, edit the file X*.ASM and delete the
- HASH.ON and HASH.OFF lines before you do this.
-
- 2) INCLUDE FFT.TOOLS
-
- 3) " P2" LOAD: SAMPLE-IN
-
- 4) INIT.FFT.HMSL
-
- 5) SAMPLE-IN FFT.H
- That should take less than 12 seconds.
-
- 6) HMSL
- Look through the MAGNITUDES dimensions. All have a tendency to slope down
- because the sound fades out. Notice dimension 11. Large values there.
- That's the "ching" of the mallet. A high bright partial. Want a better
- view? Close the HMSL screen and type:
-
- 7) PLOT.M
- This is a "mountain graph" of MAGNITUDE values. There's a long smooth
- ridge far left. That's the lowest partial of the sound. There's another
- ridge around the middle of the screen. That's a higher partial (the 6th).
- See that nice big peak far right? That's the high "ching"!
-
- 8) GR.CLOSECURW closes the graphing window.
-
- 9) Now let's recombine all the partials to resynthesize a sample.
- SAMPLE-OUT IFFT.H
- That should take less than 10 seconds.
-
- 10) SAMPLE-OUT now contains the resynthesized data, and you can play it like
- any other sample. Compare SAMPLE-IN with SAMPLE-OUT:
- 40 35 PLAY.BOTH
- You hear that SAMPLE-OUT is noisier and shorter than SAMPLE-IN.
-
- 11) Use SET.SAMPLE.SIZE ( size -- ) to change how much of the sample is being
- used. (The size defaulted to 2048 when you INIT.FFT.HMSL'ed.)
- type:
- 6000 SET.SAMPLE.SIZE
- Now try, just as before:
- SAMPLE-IN FFT.H
- SAMPLE-OUT IFFT.H
- 40 35 PLAY.BOTH
- You'll note that the resynthesized sample is longer. Try typing:
- MANY: SAMPLE-OUT .
- It's not 6000, is it? That's because SET.SAMPLE.SIZE divides your request
- by the current window size and dumps the remainder. Remember that the
- window scans your sample end-to-end, and a fraction of a window is
- a meaningless thing to subject to an FFT.
-
- 12) Use SET.WINDOW.SIZE ( size -- ) to change the size of the window. As
- mentioned above, this will increase or decrease the number of partials
- generated (#partials=half-of-window-width).
- type:
- 64 SET.WINDOW.SIZE
- Now do your FFT.H and IFFT.H, and use PLAY.BOTH to compare the input
- sample with the resynthesized sample. Enter the shape-editor by typing
- HMSL and look through the MAGNITUDE dimensions. Notice that there are
- 32 partials this time, but that there is a loss of profile detail.
- The bigger the window, the less it will be able to track fine changes in
- the source sample.
- As was mentioned above, a window size that is not a power of 2 is
- meaningless. Use 2, 4, 8, 16, 32, 64, 128, or 256 as arguments to
- SET.WINDOW.SIZE.
-
- 13) Now to edit partials for resynthesis.
- First, reset window size to 32 and sample size to 2048.
- Run the FFT.H on SAMPLE-IN.
- You now have 16 partials to play with. We'll establish a, say, ten-stage
- envelope and use this to carve out magnitude profiles of selected
- partials. Set up the envelope:
- 10 STAGE.ENVELOPE
- You'll want to be able to edit it with the mouse, so type:
- ENV-TEMPLATE ADD: SHAPE-HOLDER
-
- 14) Type HMSL to enter the editor, and flip through until you see and select
- ENV-TEMPLATE.
- You'll see that dimension 0 is a rising line. Leave it alone. These
- are index values to MAGNITUDES.
- Flip to dimension 1. It's named AMP for AMPlitude. Make sure your
- SET MODE is on REPLACE. Go ahead and chisel out a profile. Don't
- set values too high. I find that even very small values have a great
- effect (around 10-20). Exit the editor.
-
- 15) Type PLOT.M (not necessary, but a good demo)
- Apply the envelope to the, say, thirteenth partial by typing:
- 13 FILL.DIM.ENV
- PLOT.M again. See what you just did?
-
- *** Go back and forth between steps 14 and 15 as often as you like. ***
-
- 16) Finally, do a SAMPLE-OUT IFFT.H and listen to it.
- You should be able to get some extremely interesting sounds this way.
-
-
- **************************** END OF TUTORIAL ****************************
-
- General notice to users:
-
- Anyone who can make this thing faster and more accurate, please contact me.
-
- This code is free and in the public domain. Please pass on the origin of
- the included sample P2 along to anyone you give it to. If you change the
- source code, please comment, date, and sign your handiwork before you
- upload it somewhere or otherwise pass it on.
-
- Feel free to call or write for support, but don't feel snubbed if it takes
- a day or two for me to return your call.
-
- Nick Didkovsky
- 171 east 99th street #2O
- NYC NY 1OO29
- (212) 369-1733
-
- Great thanks to Robert Marsanyi who helped inestimably during the great
- "HMSL Blowout, Summer '88" This code would not exist without him.
-