The easiest thing would be a digital low-pass filter. But implementation might be tricky.

You'll need a decent analog anti-aliasing filter as well, because the Arduino is slow.

Since you only want an estimate of the bass frequencies, a couple of EMAs might be enough, with a peak detector on the output.

Here's a fast EMA implementation:

https://tttapa.github.io/Pages/Mathematics/Systems-and-Control-Theory/Digital-filters/Exponential%20Moving%20Average/C++Implementation.htmlIt's just a couple of load and store instructions, one 16-bit addition, one 8-bit addition, one 16-bit subtraction, and K shifts. (If you're using 10 ADC bits and K < 7.)

uint_t must be at least ADC bits - K bits wide.

Here's a formula for the cut-off frequency:

https://tttapa.github.io/Pages/Mathematics/Systems-and-Control-Theory/Digital-filters/Exponential%20Moving%20Average/Exponential-Moving-Average.html#cutoff-frequency (α = 2

^{-K})

But you have to know the sample frequency, and you have to take it with a grain of salt, because the roll-off is pretty bad.

Don't use the analogRead function, because it's very slow. Instead, start a new conversion before filtering, so the measurement happens during the calculation and you don't waste time.

If your anti-aliasing filter is bad, you might want to change the ADC prescaler and use only 8 ADC bits. The ATmega328P's datasheet has all the necessary details. That only helps if your filtering and processing can keep up, of course.

Pieter