0
$\begingroup$

For context: I'm trying to create a simple "level monitor" animation of audio data streaming from a microphone. I'm running this code on an iOS device and leaning heavily on the Accelerate framework for DSP calculations.

A lot of what I have so far is heavily influenced by this example project from Apple: https://developer.apple.com/documentation/accelerate/visualizing_sound_as_an_audio_spectrogram

Here are the current steps I'm taking:

  1. Start receiving (Int16) samples from the microphone using AVFoundation.
  2. Store samples until I have at least 1024, then send the first 1024 samples to my processing algorithm.
  3. Convert samples to denormalized Float (single-precision floating point).
  4. Apply a Hanning Window to the samples to prevent aliasing since the number of samples is fairly low, for performance reasons.
  5. Run a Forward DCT-II transformation of the time-domain samples into frequency-domain samples.
  6. Absolute value on all frequency-domain samples.
  7. "Bin" the samples to match the number of bars I have to animate... for each 1024/n samples, find the maximum value in each range.
  8. Normalize each of the bins into the 0...1 range by dividing each by the highest magnitude sample that has been encountered, globally.

Honestly, after step 5, I just have no intuitive understanding of what is going on with the frequency domain values. I get that a higher value means the frequency represented by a single value is more prevalent in the time-domain data... but I don't know what a value of, say 12 vs 6492 means.

Anyway, the end result is that the lowest bin (0...255) has a power that is basically just the overall amplitude, while the higher 3 bins never rise above 0.001. I feel like I'm on the right track, but that my ignorance of what the DCT output means is preventing me from figuring out what is going wrong here. I could also use FFT, if that would produce a better result, but I'm given to understand that FFT and DCT produce analogous results and Apple recommends DCT for performance.

Full disclosure, I have also asked this on Stack Overflow, but nobody has responded.

$\endgroup$
6
  • 3
    $\begingroup$ What type of data are you using in your testing (is it mic input only?) ? You could try by feeding 0 - Fs/2 sweep signal (constant amplitude) from file? $\endgroup$
    – Juha P
    Commented May 2 at 7:00
  • $\begingroup$ So the microphone produces 44.1kHz, 16-bit audio. I suppose I could re-jigger it to run off an imported sound file, but that's not really the use-case for the final implementation. I played some opera with sopranos singing VERY high notes and still only my bottom quarter of bins (0-255) showed any movement. $\endgroup$ Commented May 2 at 12:28
  • 1
    $\begingroup$ Use sweep etc. generated audio signal for testing purposes ... . Soprano goes little above 1kHz (+ few harmonics) so, if bins in your implementation covers whole frequency range (0 - 22.05kHz @ 44.1kHz sampling) you sure understand that using vocals in testing your software is not the best practice. $\endgroup$
    – Juha P
    Commented May 2 at 14:58
  • $\begingroup$ Point taken. I'm playing a little fast and loose as this is just for a simple animation, not a scientifically or statistically valid analysis of a waveform. $\endgroup$ Commented May 2 at 16:18
  • 1
    $\begingroup$ You can prepare such constant amplitude sweep (chirp) signal file with Audacity. $\endgroup$
    – Juha P
    Commented May 2 at 18:19

1 Answer 1

0
$\begingroup$

So the conversation with Juha P made me realize that I had been badly misinterpreting the results of the DCT. Once I used a sweep tone, it became clear that my data was fine, but the range was crazy-inappropriate for my intended use.

I found out that iPhone microphones record at 48kHz by default, making my Nyquist frequency 24kHz. Given that human speech is generally in the 100-300Hz range, the problem was that all of the usable data was in the bottom few bins of the result.

I changed the "grouping" step (#7) to only look at bins 1-41 (out of 1024), using 10 bins per "output" value. Immediately, I could see the effect I wanted, with the bars responding to changes in pitch in my voice.

Big thanks to Juha P for helping me figure this out!

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.