Valentin Regnault
Valentin Regnault

Reputation: 75

How to buffer a stream in a functional programming?

I'm trying to do realtime audio processing in functional programming (in rust, but this is not the point).

So my idea is to take the inputs samples from a library called cpal (it reads the default input of my computer, i.e my microphone), then pass them through a process() function that takes a input sample, and returns a output sample, and finally send this output sample back to cpal, to my speakers.

The process function would be a composition of functions, so that I can create some "effects" functions, and combine them in different ways.

First question : is that a good idea ? Is there a better way to do signal processing in a functionnal style ? Is there limitations to this "architecture" ?

If I want to make for example a delay effect, that takes the sound and repeat it with a slight lag, and a little quieter, what would my function look like ? In a object oriented design I would have a Delay class, with a buffer (ring buffer) property and a process method. The process method would first push the sample to the end of the buffer, then pop the first element of that same buffer, and finally return the sample + the first element * some coefficient.

But in a functional style, I can't find a way to do that. Question 2 : As it is more a step by step process, how should I communicate from a step to the next ?

Upvotes: 0

Views: 292

Answers (1)

Matt Timmermans
Matt Timmermans

Reputation: 59174

Efficient audio processing really requires the ability to reuse buffers and usually to modify samples in place, so a strict functional style, in which every object is immutable, isn't really appropriate.

Also:

  • Many audio processes require state, so processing stages cannot really be functions unless they process the entire stream in one call. They should be objects or stateful closures
  • Pass fixed-size blocks, not individual samples
  • passing a block from one stage to the next should transfer ownership of the block, so that it can be modified in place
  • blocks that come out the end of the pipeline should eventually be reused so you don't need to allocate an unbounded number of blocks.

Upvotes: 3

Related Questions