Audio via Serial, not soundcard - draw() too slow to analyze

Hey all, I’m trying to figure out the best way to attack this problem. I have a Mic (Max4466) -> ADC (ADS1115) -> Arduino Nano 33 IoT -> Processing via Serial (USB).

My current test sketches work like this:

-Arduino is continually getting Mic values in loop(), and when it gets a ‘1’ from Processing, it sends the current Mic value via Serial. Mic values can be either -1 to 1 or abs(-1 to 1), depending on what Processing will need.

-Processing sends a ‘1’ then a ‘0’ to the Arduino every frame of draw(), receives the current mic value, and prints the value to console.

That’s all well and good, but draw() is only running at 60fps and the ADC’s sample rate is 44.1 KHz. Arduino’s loop() runs at about 117 KHz.

I have a few audio-visualizer sketches that use the Sound library’s amplitude and fft classes, and the audio input. I want to modify them to use the serial values instead of the sound card so that i can use the Arduino with my RasPi. For fft to work it’s going to need to call the values from the Arduino at samplerate, not framerate. At the same time, draw() still needs to run at framerate because it’s drawing the visualizations.

Other than buying a a soundcard for the RasPi (which is still an option if this is too complicated), how can i get the Processing sketch to read the serial values at 44.1 KHz or get the serial values into the Sound input?

Test Sketch Processing:

import processing.serial.*;

Serial myPort;

String inString = "";


void setup()
{
  size(200, 200);
  
  // Show serial ports
  printArray(Serial.list());
  
  // Set up Serial ports
  String portName = Serial.list()[4];
  myPort = new Serial(this, portName, 9600);
  
  // Show selected port names
  println("");
  println(portName);
  println(myPort);
}


void draw()
{
  // Call to Arduino
  myPort.write('1');
  myPort.write('0');
  
  // Get from Arduino
  int lf = 10;
  while (myPort.available() > 0)
  {
    inString = myPort.readStringUntil(lf);
  }
   
  float arduinoVal = float(inString);
  println(arduinoVal);
}

Mic Sketch Arduino:

#include<Wire.h>
#include <Adafruit_ADS1015.h>


// ADC
Adafruit_ADS1115 ads;

// Mic Level
float outVal = 0.0f;

// Store Processing Call Variable
char processingCallVal;


void setup() 
{
  Serial.begin(9600);

  // ADS1115 setup
  ads.setGain(GAIN_ONE);
  ads.begin();
}


void loop() 
{
  // Process Mic/ADC input
  int16_t adc0 = ads.readADC_SingleEnded(0);
  float multiplier = 0.125f;

  //outVal = abs( 1 - ( (adc0 * multiplier) / 1644.0f ) );  // amplitude between 0 and 1
  outVal = 1 - ( (adc0 * multiplier) / 1644.0f );   // Amplitude between -1 and 1

  // If there's incoming serial data from Processing, read it
  if (Serial.available())
  {
    processingCallVal = Serial.read();
  }

  // If the Processing value is 1, send the current Mic/ADC value and reset to 0
  if (processingCallVal == '1')
  {
    Serial.println( outVal );
    processingCallVal = '0';
  }
  else
  {
    processingCallVal = '0';
  }
  
}

1 Like

Good Morning @RFullum and Welcome to the our Community!
Is not possible to read values at 44.1 KHz it is three orders of magnitute faster… Also, even if it were possible, you wouldn’t be able to see at that frequency.
I worked as a sound enginer for 10 years and the best way of visual rappresentation audio are the average of samples and the peak level. In Your case, between the calls from Processing, the Arduino sketch will have to calculate an average of the measurements, this approach avoids losing audio data between Processing calls. I’m not an very expert coder but I hope I was helpful, Best Regards.

1 Like

Cool. Thanks @Dennis. I had a feeling that was going to be the response with my current setup. I thought if i could have Processing get the audio values from the Arduino at 44.1K, i could use it in the fft(), and then have Processing draw() at sampleRate from the averaged values.

pseudocode:

import processing.sound.*;

FFT fft;

float arduinoVal = 0.0f;
int bands = 128;

void setup()
{
  fft = new FFT(this, bands);
  fft.input(arduinoVal);
  
  String portName = Serial.list()[4];
  myPort = new Serial(this, portName, 9600);
}

void draw()
{
  // Somehow get this to run at 44.1k
  arduinoVal = incomingValuesFromArduino;
  fft.analyze();
  {do fft smoothing}
  
  // This can run at normal 60+/- fps
  for (int i=0; i<bands; i++)
  {
    {use smoothed fft values to draw pretty things}
  }
}

I think buying the sound card might be the best bet so i can just use the Sound library’s AudioIn at an audio sampleRate for FFT, and i can use the arduino for another project for making music or visualizing music. Thanks again for the feedback!

*I’m aware to get values over serial at audio sample rate i’d have to bump up the baud rate too

2 Likes

I might have a look at how the Sound library runs things at samplerate and see if i can EASILY implement any of that. Otherwise, it never hurts to have an extra sound card. :grin:

1 Like

Hi @RFullum Yes, I think so!

I’m aware to get values over serial at audio sample rate i’d have to bump up the baud rate too

As You as guessed the data transmission at that frequency it’s not within Arduino’s reach, for this task You must use the external equipment.

It was a pleasure, have a nice Day!
Dennis

2 Likes