Requesting For Comments for a new simple-dsp library

Dear cafe and Dr. Henning Thielemann, I'd like to propose a new package named simple-dsp. I couldn't figure out how to use the existing dsp library, so I made my own version featuring a little GUI to try the code in realtime. I'd be happy to contribute this work directly to dsp. My goal is to be able to extract sensible discrete values from a sound input at 60 Hz for video production. I implemented low/band/high pass filters to compute 3 RMS volumes, but the values I'm getting are not sharp enough, e.g. the band pass picks the low end. Ideally I would extract the transient events of the percusive sound and the note pitch of the melodic elements. I have very little understanding of DSP, and I'm sure there are better ways to achieve this goal, so I would appreciate it if someone more experienced could take a look: * Doc: https://tristancacqueray.github.io/simple-dsp/ * Candidate: https://hackage.haskell.org/package/simple-dsp-0.1/candidate * Forum: https://discourse.haskell.org/t/rfc-a-new-simple-dsp-library/9094 Thanks in advance, -Tristan

On Thu, 21 Mar 2024, Tristan Cacqueray wrote:
I'd like to propose a new package named simple-dsp. I couldn't figure out how to use the existing dsp library, so I made my own version featuring a little GUI to try the code in realtime.
I'd be happy to contribute this work directly to dsp.
The 'dsp' package is pretty old, predating any Vector data type or refined numeric type class hierarchies. I decided to leave it as it is, for educational reasons, since it contains many literal translations of signal processing algorithms from various text books. I have not used most of the contained functions myself.
My goal is to be able to extract sensible discrete values from a sound input at 60 Hz for video production. I implemented low/band/high pass filters to compute 3 RMS volumes, but the values I'm getting are not sharp enough, e.g. the band pass picks the low end. Ideally I would extract the transient events of the percusive sound and the note pitch of the melodic elements.
For a filter that computes lowpass, highpass and bandpass in one go, I use the "universal filter", also known as "state variable filter": https://hackage.haskell.org/package/synthesizer-core-0.8.3/docs/Synthesizer-... You can see running examples here: https://hackage.haskell.org/package/synthesizer-core-0.8.3/docs/src/Synthesi... Frequencies are specified as ratio with respect to the sampling rate, e.g. 440 Hz resonance frequency at 44100 Hz sampling rate translates to 440/44100. For working on storable vectors you would instead use Universal.causal and apply this to Data.StorableVector.Lazy. For very fast processing I have the synthesizer-llvm package, which however depends on the LLVM package in a compatible version. (LLVM-16 currently preferred.) Unfortunately I do not understand your application well, thus I do not know whether the state variable filter is the right choice for your application.

On Thu, Mar 21, 2024 at 19:04 Henning Thielemann wrote:
On Thu, 21 Mar 2024, Tristan Cacqueray wrote:
I'd like to propose a new package named simple-dsp. I couldn't figure out how to use the existing dsp library, so I made my own version featuring a little GUI to try the code in realtime.
I'd be happy to contribute this work directly to dsp.
The 'dsp' package is pretty old, predating any Vector data type or refined numeric type class hierarchies. I decided to leave it as it is, for educational reasons, since it contains many literal translations of signal processing algorithms from various text books. I have not used most of the contained functions myself.
My goal is to be able to extract sensible discrete values from a sound input at 60 Hz for video production. I implemented low/band/high pass filters to compute 3 RMS volumes, but the values I'm getting are not sharp enough, e.g. the band pass picks the low end. Ideally I would extract the transient events of the percusive sound and the note pitch of the melodic elements.
For a filter that computes lowpass, highpass and bandpass in one go, I use the "universal filter", also known as "state variable filter": https://hackage.haskell.org/package/synthesizer-core-0.8.3/docs/Synthesizer-...
You can see running examples here: https://hackage.haskell.org/package/synthesizer-core-0.8.3/docs/src/Synthesi...
Frequencies are specified as ratio with respect to the sampling rate, e.g. 440 Hz resonance frequency at 44100 Hz sampling rate translates to 440/44100. For working on storable vectors you would instead use Universal.causal and apply this to Data.StorableVector.Lazy. For very fast processing I have the synthesizer-llvm package, which however depends on the LLVM package in a compatible version. (LLVM-16 currently preferred.)
I see, thank you for the details, that sounds useful. The 'step' function looks simple to use too. It's surprising that such a filter seems to only need 2 values for its state.
Unfortunately I do not understand your application well, thus I do not know whether the state variable filter is the right choice for your application.
The final application is named animation-fractal, it renders a video at 60 fps, using external inputs to drive a generative art function (shader). For each frame, the process: - collects inputs such as midi events or audio frames. - applies a modulation function to produce discrete values. - updates the shader input with the modulation outputs. In this demo, I used 6 sound stems and extracted their peak RMS volume (using 735 samples per frame, or 44100 / 60): https://www.youtube.com/watch?v=qZTqUQumC6s My goal with simple-dsp, is to enable using a single sound file to drive the animation, for example, by extracting the peak RMS volume of the low/mid/high frequency to approximate the drum/melody/hats elements of a sound and use that as the animation source. In a previous implementation, I used an fft to extract such values, but it was challenging to get a smooth result and that's why I'm looking into filters. For what it's worth, my current implementation is done in the 'mkFilters' and 'updateFilters' of: https://gitlab.com/TristanCacqueray/animation-fractal/-/blob/main/src/Animat... Note that it's ok if the signal gets distorted, as long as the value somehow represent a meaningful element of the sound input. Thanks again for getting back to me, I'll give synthesizer-core a try soon. -Tristan

On Thu, 21 Mar 2024, Tristan Cacqueray wrote:
I see, thank you for the details, that sounds useful. The 'step' function looks simple to use too. It's surprising that such a filter seems to only need 2 values for its state.
The state variable filter models a very simplistic solver of a linear differential equation of second order. This is done by two integrations, each integration maintains a running sum. These sums form the state.
In this demo, I used 6 sound stems and extracted their peak RMS volume (using 735 samples per frame, or 44100 / 60): https://www.youtube.com/watch?v=qZTqUQumC6s
Nice!
Thanks again for getting back to me, I'll give synthesizer-core a try soon.
Btw. there is a mailing list dedicated to any form of Art produced with
Haskell:
Haskell Art Mailing list
participants (2)
-
Henning Thielemann
-
Tristan Cacqueray