1

I am thinking about trying to make an Arduino synthesizer using the true analog output on the Due. However I would like to be able to play multiple notes at the same time on a single buzzer. Is this possible and how would I do it?

1
  • what is buzzer? .... is it able to produce different tones?
    – jsotola
    Commented Oct 26, 2019 at 19:02

2 Answers 2

1

You just have to add the waveforms. For example, if you want to play pure tones (the simplest and most boring timbre), you generate a sine wave for each of them and add them together:

struct Note {
    float frequency;
    float phase;
    bool is_active;
} notes[MAX_NOTES];

void output_sample()
{
    static uint32_t previous_time;
    uint32_t now = micros();
    uint32_t elapsed_time = now - previous_time;
    previous_time = now;
    float output = 0;
    for (int i = 0; i < MAX_NOTES; i++) {
        Note *note = &notes[i];
        if (note->is_active) {
            output += cos(note->phase);
            note->phase += 2*M_PI*note->frequency*1e-6*elapsed_time;
            if (note->phase >= 2*M_PI) {
                note->phase -= 2*M_PI;
            }
        }
    }
    analogWrite(DAC_PIN, 2048 + round(output * (2047.0 / MAX_NOTES)));
}

The function output_sample() should be called as frequently as possible. You can change the notes array any time to add, remove or change notes.

There is some room for optimization here, like:

  • storing 2*M_PI*note->frequency*1e-6 as the “frequency” in order to save some calculations

  • using a wave table instead of the cos() function (I don't know how good is the Due at transcendental math)

  • replacing elapsed_time by a constant if you can manage to output the samples at a fixed rate.


Edit: I wrote “You can change the notes array any time to add, remove or change notes.” Here is how to start or stop a note, i.e. to add or remove it from the list of active notes:

// Start a note. Returns an index to be used with stop_note(), or -1 if
// we couldn't start the note because we are already outputting the
// maximum number of simultaneous notes.
int start_note(float frequency)
{
    int i;  // index of the note in the notes[] array

    // Find a free slot in the array.
    for (i = 0; i < MAX_NOTES; i++)
        if (!notes[i].is_active) break;  // found

    // Couldn't find a free slot?
    if (i == MAX_NOTES) return -1;

    // Setup the note parameters.
    notes[i].frequency = frequency;
    notes[i].phase = 0;
    notes[i].is_active = true;
    return i;
}

// Stop the note with the given index.
void stop_note(int index)
{
    if (index >=0 && index < MAX_NOTES)
        notes[index].is_active = false;
}
3
  • How would I add notes here? I am not extremely familiar with structs.
    – Someone
    Commented Nov 29, 2019 at 18:36
  • @Someone: You find a cell in the array where is_active is false, and you set the desired frequency, and set is_active to true. Commented Nov 29, 2019 at 19:17
  • how would I add an item to the note array?
    – Someone
    Commented Dec 1, 2019 at 3:04
0

Sound is nothing else than a multiple simple waves combined in to one. So, theoretically you can play as many sounds (tones) as you like on a single pin. If you want to go true analog than you probably want to use a sin wave to generate sound. However, in that case you can do the following: Either make a function that would be capable of generating a sin wave of your desired frequency. In case of true analog this would probably be done by calculating actual sin values and using the map() function mapping 0 - 1 to 0 - 1024 and writing to the pin. The frequency can be adjusted by changing the delay between each step of changing the voltage or DAC value. However, this will not allow for multiple frequencies. Alternatively for multiple frequencies to be played at the same time you would need to calculate the Fourier inversion of all the waves you want to play and send the results of that to the DAC.

6
  • And you would need to use a speaker instead of a buzzer, since they can produce a single tone at a time.
    – Coder_fox
    Commented Oct 26, 2019 at 19:10
  • 1
    Fourier inversion” is needless math jargon for what is simply the sum of the tones. Commented Oct 26, 2019 at 19:32
  • @EdgarBonet yes, it's basically a sum.
    – Coder_fox
    Commented Oct 26, 2019 at 20:06
  • How would I go about doing this?
    – Someone
    Commented Oct 26, 2019 at 21:02
  • 1
    Mixing sounds is not as simple as summing them mathematically (nor summing and averaging to bring the level back down). I made that mistake once years ago, and the results were crap. Once I found a proper sound mixing function I never looked back...
    – Majenko
    Commented Oct 26, 2019 at 21:30

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.