[SOLVED] SinOsc in draw loop is very choppy (Sound Library)

I am a novice programmer having a problem with the Sound library. I am trying to use the SinOsc function to generate a smooth sine wave. I also want it to vary the pitch as it reads serial data (range 0 to 255) that is generated by my Arduino every 33 microseconds. The problem is that since the SinOsc function is in the “draw” loop, the audio output is VERY choppy to the point where all you hear is a buzzsaw effect and no sinewave. If I move the SIne wave code out of the “draw” loop, it will not pick up the new serial data that is being generated to vary the pitch. The code has no errors and compiles nicely, but the sound is terrible!

Are there any ideas as to how I can make this a smooth sounding sine wave that varies in pitch based on the values I am receiving from the serial data stream?

Thank you much for looking at the code I included below:

//******************************************************************************
// Sound example
//
// To be used with the Arduino connected and running program:
// "p13_TouchSensorLamp_with_scaled_Serial_Output"
// already loaded to create the serial data that 
// varies from 0 to 255, read by this sketch
//
//******************************************************************************

import processing.sound.*;
import processing.serial.*;
Sound s;
Serial myPort;

// Global Constants
final int BAUD_RATE     = 9600; // MUST be same as the Arduino

// Global variable(s)
int pitchinput = 0; // holds the "pitchinput" value

void setup() {
  
  // print a list of available serial ports to the
  // Processing status window (Just one available in my case)
  println("Available serial ports:");
  println(Serial.list());

  // Tell the serial object the information it needs to communicate
  myPort = new Serial(this, Serial.list()[0], BAUD_RATE);
  
  size(200, 200);
  // Create a Sound object for globally controlling the output volume.
  s = new Sound(this);
}

void draw() {
  // Map vertical mouse position to volume.
  float amplitude = map(mouseY, 0, height, 0.4, 0.0);

  // Instead of setting the volume for every oscillator individually, we
  // control the overall output volume of the whole Sound library.
  s.volume(amplitude);
  
    if (myPort.available() > 0) {

      // read and print for easy debugging
      pitchinput = myPort.read();
      println(pitchinput); 
  }
  
  // Play sine oscillator
  SinOsc sin = new SinOsc(this);
  sin.play(500 + pitchinput * 4, 1);
}
1 Like

This way, you are deleting the old sine wave instance and making a new one every single time draw() is called, which is(usually) 60 times a second.
What you need to do is to create the SinOsc object only once, and then use its freq() function to adjust the pitch of it.
Try this:


...
// Global variable(s)
...
SinOsc sin;
...
void setup() {
...
  sin=new SinOsc(this);
  sin.play(0, 1); //Frequency doesn't matter here, as we are going to change it on every draw() call
...
}
...
void draw() {
  ...
  sin.freq(500 + pitchinput * 4);
...
}

Three dots being parts of your code.

1 Like

I tried it that way and had a small problem which was easily solved. I put this line in instead:

SinOsc sin = new SinOsc(this);

instead of the line you suggested since the compiler was unhappy with it. But that was the only change.

Everything else I did was the way you suggested. I brought the sin.play into the setup, so it would be created just once. Then I used the sin.freq command as you suggested (Brilliant!).

The code now compiles now. It gives a smooth sine wave that I can vary with the Arduino sensors with their corresponding serial data stream to the Processing sketch. Plus, I can vary the volume with the mouse (which had been working before.

I am learning with each project I tackle and try to fix the problems myself, but my depth of knowledge is quite shallow, so I resort to the Forums to gain the depth that I need to learn.

All is well now thanks to you! Thank you for your expertise.

bob

No problem!

Global variables that keep existing between draw() calls are quite a thing. On quite big projects I end up having to make another tab just to store them! lol

And initializing things is also quite a thing - there are many classes(like this SinOsc) that refuse to compile if they are defined outside of any function, so you have to create them as a global variable, but set them to anything inside setup().

Also, for learning functions of objects easier, enable code completion on CTRL+SPACE in Processing preferences. Then, you can type “Sin.” and press CTRL+SPACE, and it will show a list of all functions you can perform with it - that’s how I just found out about the freq() function!