snd-fft as a list?

Hello everyone.

I’m trying to do something like this:

for each 8 samples
     find the frequency component with the highest amplitude to the nearest 256 Hz
     apply a highpass filter to those samples centered on the bottom of that frequency range
end for

The code I’ve come up with is:

(defun peakof (x)
  (* 256 (member (max  x) x))
(hp s (peakof (snd-fft (snd-copy s) 256 8 NIL)) 512)

However, Nyquist says that the input to the MAX function is the wrong type. It seems unwilling to consider the output of snd-fft a list, even though the documentation claims to output an array, and it seems to display as one.

Any idea how to accomplish what I want to accomplish?

(max (list 1 2 3 4 5 4 3 2 1))

error: bad argument type - (1 2 3 4 5 4 3 2 1)

(max 1 2 3 4 5 4 3 2 1)

Returns: 5

‘snd-fft’ Returns an Array, not a list.
You must first convert each element to a cons cell, before you can apply any of the convenient list functions (member, sort, subst etc).
Furthermore, you can’t treat the fft values in the manner you do.
The Output gives back real and imaginary parts of the cosines that make up the current Frame. But you rather Need a Magnitude (or Amplitude) /Phase spectrum to search for the max peak.
Since you want to produce a dynamic high pass filter, you should work with an iterator object, where in every “:next” method the Peak is searched and the bins (as they apppear in the original Frame i.e. real/complex) are set to 0 above your found frequency and the whole array-stream (the iterator object) is then converted back to a Sound with ‘snd-ifft’.
That’s all horribly complicated (as Steve can confirm, I guess).
There is an high pass filter example in the stand-alone Version of Nyquist under Demos/fft (html and .lsp).
But it is static (constant cut-off frequency) and is not windowed (which causes distortion and aliasing).
If I were you, I’d employ the ‘snd-yin’ function.
It Returns a Array with two elements: (aref my-yin 0) gives back the strongest notes from a certain midi-note upwards. The second Sound (aref my-yin 1) tells you how much noise is at the found place, i.e. how periodic the found Sound is.

(setf my-yin (yin s 59 71 172))

The first Argument “s” is the input-Sound (which must be monophonic). It is followed by two midi note values “steps”. 59 is B4, which lies slightly under 256 Hz and 71 means that we search up to 512 Hz (one octave).
The last value is the aproximated sample length (44100 / 256). Thus, the Sound will also have a samplerate of 256 Hz.
In principle, the first array-element can directly be passed to ‘hp’ and sets the cut-off frequency for the filter every 172 samples.
I know, you want a step size of 8 samples, but I can’t guess why. Besides, all values inbetween will be interpolated.

(hp s (step-to-hz (aref my-yin 0)))

would be the last Statement of the code. (Nota bene: Hp takes only two arguments, the value 512 from your code above will produce an error)
If you put it all together and in a function, you can use ‘multichan-expand’ to process Stereo sounds. I hope this helps a Little bit further.

Uh… wow. Complicated indeed. :confused:

I guess I’ll have to dig into the language more than I thought. Since that will take time, and you’ve given me a good approach, you can consider this solved.