Multiple potentiometers for volume?

Hey guys, I'm currently working on something which I'm having quite a lot of trouble with and seem to struggle finding any more information on how to do this.

Using the Mozzi synthesis library, I'm trying to make my Arduino play 2 different sine waves at different frequencies. This I believe I have already done. What I'm struggling on is making one potentiometer for the volume of one wave, another for the volume of the second wave, and finally one for master volume. After that, I want to make it so that I can attach a button to turn on/off each of the waves (so this will require 2 buttons). Could anyone please help me? This is my code so far:

#include <MozziGuts.h>
#include <Oscil.h> // oscillator template
#include <tables/sin2048_int8.h> // sine table for oscillator

// use #define for CONTROL_RATE, not a constant
#define CONTROL_RATE 64 // powers of 2 please

// use: Oscil <table_size, update_rate> oscilName (wavetable), look in .h file of table #included above
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin(SIN2048_DATA);
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin2(SIN2048_DATA);

const int8_t INPUT_PIN = 0; // Set the input for the knob to analog pin 0

// To convery the volume level from updateControl() to updateAudio()
uint8_t volume;

void setup()
{
Serial.begin(9600); // Set up the Serial output so we can look at the input values

startMozzi(CONTROL_RATE); // set a control rate of 64 (powers of 2 please)
aSin.setFreq(440); // set the frequency
aSin2.setFreq(880); // second oscillator frequency

}

void updateControl()
{
// Read the variable resistor for volume
int sensor_value = mozziAnalogRead(INPUT_PIN); // Value is 0-1023

// Map it to an 8-bit range for efficient calculations in updateAudio
volume = map(sensor_value, 0, 1023, 0, 255);

// Print the value to the Serial monitor for debugging
Serial.print("volume = ");
Serial.println((int)volume);
}

int updateAudio()
{
return ((int)aSin.next() * volume)>>8; // Return an int signal centred around 0 + shift back into range after multiplying by 8-bit value
return ((int)aSin2.next() * volume)>>8; // Return an int signal centred around 0 + shift back into range after multiplying by 8-bit value

return 0;
}

void loop()
{
audioHook(); // Required here
}

Thanks in advance!

Please read the two sticky posts at the top of this section, especially the part about posting code.

You seem to be using a library for the wave synthesis - from the look of it, the library calls updateAudio() to get the current value to be output, and I guess the original implementation just called aSIN.next() to calculate the next value.

If you want to combine both sine waves into a single output channel then the return value should probably be the average of the two sine waves.

int chanA = ((int)aSin.next() * volume)>>8;
int chanB = ((int)aSin2.next() * volume)>>8;
return (chanA + chanB) / 2;

If you want to have a separate volume control for each sine wave then declare separate variables and update them both.

If you want to have a master volume as well then define yet another volume variable and use that to scale the average before you return it.

If you ever expect to have more than two of these sine wave generators then it would be a good idea to learn about arrays and FOR loops as it will save you duplicating code.

Thanks for replying! And ah yes, sorry; my bad.

So in order to make the sound come out of the same output I would use the following code? :

int chanA = ((int)aSin.next() * volume)>>8;
int chanB = ((int)aSin2.next() * volume)>>8;
return (chanA + chanB) / 2;

Also, I'm sorry about this but I'm new to programming. What do you mean by "to scale the average before you return it"? I am wanting to have a separate volume control (as a potentiometer) for each sine wave as well as using a third potentiometer for master volume as you said :slight_smile:

Suppose your three volumes are held in variables volumeA, volumeB, masterVolume. Suppose each volume was held as a value between 0 .. 255. Your code to generate the output could look something like this:

int updateAudio()
{
    int valueA = ((int)aSin.next() * volumeA)>>8;
    int valueB = ((int)aSin2.next() * volumeB)>>8;
    int average = (valueA + valueB) / 2;
    return (average * masterVolume) >>8;
}

I would recommend choosing better names for aSin and aSin2 and then using the same scheme to name the other related variables, but hopefully you get the idea of how the averaging and scaling would be done.

Would I have to declare "volumeA" and "volumeB" as an integer? Because when I click verify it says "'volumeA' was not declared in this scope"

Thanks again!

These are intended to be global variables which hold the current volume levels. You will need to add definitions for them at the top of the sketch, and put code elsewhere to read the analog inputs and assign the corresponding values to each volume variable. Initially you might choose to just initialise them with a fixed value.