Arduinos offers only a digital output: the output is either on (+ 5 V) or off (0 V). The tone() function, which I expect you to encounter at this point, outputs a square wave with a given frequency.
Say you need a 100 Hz tone. 100 Hz means that the output is repeated every 1/100 second or 10 ms. Thus, tone(PIN,100) will set a timer interrupt every 5 ms. The first time the interrupt is called, it sets the output minimum and returns to what your program did. The next time it is called, it sets the output maximum. Thus, every 5 ms the output changes, and you get a square wave with a duty cycle of 50%, which means that the output works exactly in half the cases.
All this is very good, but most of the audio signals are not rectangular. If you want to play two rectangular tones at the same time or even control the volume of one square wave, you will need to output more values ββthan just "on" and "off".
The good news is that you can use what is called pulse width modulation (usually abbreviated as PWM). The idea is that you can only set one of two values, but you can do it very quickly. People can hear audio frequencies up to 20 kHz. If you do this faster, say, at a frequency of 200 kHz (within the capabilities of an Arduino operating at a frequency of 16 MHz), you will not hear individual output transitions, but the average value over a longer period.
Imagine generating a 200 kHz tone() using tone() . It's too high to hear, but the average is halfway between turning it on and off (50% of the duty cycle, remember?). So now we have three possible output values: on, off and halfway. This is enough to allow us to play two square waves at the same time: 
High fidelity sound requires far more value than that. CDs store 16-bit sound, which means there are 65,536 possible values. And although we donβt get audio with CD quality from Arduino, we can get more output by choosing a duty cycle other than 50%. In fact, Arduino has the equipment for this for us.
Meet analogWrite() . This fakes various output levels using the PWM Arduino built-in hardware. The bad news is that the PWM frequency is usually 500 Hz, which is great for reducing the brightness of the LED, but too low for the sound. Therefore, we must program the hardware registers ourselves.
Secrets of Arduino PWM contains additional information, and here is a detailed link on how to implement PWM DAC on Arduino.
I chose a 7-bit resolution, which means that the output is a 16 MHz / 128 = 125 kHz square wave with 128 possible duty cycles.
Of course, once you finish working with PWM, the fun is just beginning. With a few voices, you cannot rely on interrupts to set the frequency of your waveforms; you must stretch them yourself. Knowledge of basic digital signal processing (DSP) will be very convenient. You will need hard code to generate audio data from the interrupt handler, and then you will need playroutine to run the correct notes at the right time. The sky is the limit!
Anyway, here is the code:
#define PIN 9 const uint16_t frtab[] = { 30578, 28861, 27241, 25712, 24269, 22907, 21621, 20408, 19262, 18181, 17161, 16198 }; #define VOICES 4 struct voice { uint16_t freq; int16_t frac; uint8_t octave; uint8_t off; int8_t vol; const uint8_t *waveform; } voice[VOICES]; #define PITCH 50 const uint8_t square_50[] = { 0, 0, 0, 0, 0, 0, 0, 0,15,15,15,15,15,15,15,15 }; const uint8_t square_25[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15,15,15,15 }; const uint8_t square_12[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15,15 }; const uint8_t square_6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15 }; const uint8_t sawtooth[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 }; const uint8_t triangle[] = { 0, 2, 4, 6, 8,10,12,14,15,13,11, 9, 7, 5, 3, 1 }; const uint8_t nicebass[] = { 0, 8,14,18,22,23,24,25,26,25,24,23,22,18,14, 8 }; void setup() { pinMode(PIN, OUTPUT); TCCR1A = 0x80; TCCR1B = 0x11; ICR1H = 0; ICR1L = 0x7f; TIMSK1 = 1; OCR1AH = 0; for (uint8_t i=0; i<VOICES; i++) clear_voice(i); } void set_voice(uint8_t v, uint8_t note, uint8_t volume, const uint8_t *waveform) { note += PITCH; voice[v].octave = note/12; voice[v].freq = frtab[note%12]; voice[v].frac = 0; voice[v].off = 0; voice[v].waveform = waveform; voice[v].vol = volume; } void clear_voice (uint8_t v) { voice[v].freq = 0; } uint8_t s = 0; ISR(TIMER1_OVF_vect) { /* Calculate new data every 4 pulses, ie at 125/4 = 31.25kHz. Being interrupted unnecessarily is kinda wasteful, but using another timer is messy. */ if (s++ & 3) return; int8_t i; int8_t out = 0; for (i=0; i<VOICES; i++) { if (voice[i].freq) { voice[i].frac -= 128<<voice[i].octave; if (voice[i].frac < 0) { /* overflow */ voice[i].frac += voice[i].freq; voice[i].off++; } /* warning: vol isn't a real volume control, only for square waves */ out += (voice[i].waveform[voice[i].off & 15]) & voice[i].vol; } } /* out is in the range 0..127. With 4-bit samples this gives us headroom for 8 voices. Or we could use more than 4-bit samples (see nicebass). */ OCR1AL = out; } /* tune data */ const uint8_t bass[8][4] = { { 12, 19, 23, 24 }, { 5, 12, 19, 21 }, { 12, 19, 23, 24 }, { 5, 12, 19, 21 }, { 14, 16, 17, 21 }, { 7, 19, 14, 19 }, { 14, 16, 17, 21 }, { 7, 19, 14, 19 } }; const uint8_t melody[2][8][16] = { {/* first voice */ {31, 0, 0, 0, 0, 1, 2, 3,31,29,28,29, 0,28,26,24 }, { 0, 0, 0, 0, 0, 1, 2, 3,53,54,53,54, 0, 1, 2, 3 }, {31, 0, 0, 0, 0, 1, 2, 3,31,29,28,29, 5,28, 5,26 }, { 5,28,24, 0, 0, 1, 2, 3,53,54,56,54, 0, 1, 2, 3 }, {29, 0, 0, 0, 0, 1, 2, 3,31,29,28,29, 5, 0,28, 5 }, {28, 5, 0,26, 0, 1, 2, 3,54,56,58,56, 0, 1, 2, 3 }, {29, 0, 0, 0, 0, 1, 2, 3,31,29,28,29, 5, 0,28, 5 }, {28, 5, 0,26, 0, 1, 2, 3, 0,19,21,23,24,26,28,29 }, }, {/* second voice */ {24, 0, 0, 0, 0, 1, 2, 3,24,24,24,24, 0,24,24,21 }, { 0, 0, 0, 0, 0, 1, 2, 3,49,51,49,51, 0, 1, 2, 3 }, {24, 0, 0, 0, 0, 1, 2, 3,24,24,24,24, 5,24, 5,24 }, { 5,23,21, 0, 0, 1, 2, 3,49,51,53,51, 0, 1, 2, 3 }, {26, 0, 0, 0, 0, 1, 2, 3,24,26,24,24, 5, 0,24, 5 }, {24, 5, 0,24, 0, 0, 0, 0,51,51,54,54, 0, 1, 2, 3 }, {26, 0, 0, 0, 0, 1, 2, 3,24,26,24,24, 5, 0,24, 5 }, {24, 5, 0,23, 0, 1, 2, 3, 0, 5, 0,19,21,23,24,26 }, } }; void loop() { uint8_t pos, i, j; for (pos=0; pos<8; pos++) { for (i=0; i<16; i++) { /* melody: voices 0 and 1 */ for (j=0; j<=1; j++) { uint8_t m = melody[j][pos][i]; if (m>10) { /* new note */ if (m > 40) /* hack: new note, keep volume */ set_voice(j, m-30, voice[j].vol, square_50); else /* new note, full volume */ set_voice(j, m, 15, square_50); } else { voice[j].vol--; /* fade existing note */ switch(m) { /* apply effect */ case 1: voice[j].waveform = square_25; break; case 2: voice[j].waveform = square_12; break; case 3: voice[j].waveform = square_6; break; case 4: clear_voice(j); break; /* unused */ case 5: voice[j].vol -= 8; break; } if (voice[j].vol < 0) voice[j].vol = 0; /* just in case */ } } /* bass: voices 2 and 3 */ set_voice(2, bass[pos][i%4], 31, nicebass); set_voice(3, bass[pos][0]-12, 15-i, sawtooth); delay(120); /* time per event */ } } }
It is reproduced with four voices. I only have Arduino Leonardo (well, Pro Micro) to check it, so you may need to change the PIN , depending on which contact is connected to TIMER1A (if I read it correctly, it presses 9 on Uno and outputs 11 on mega). Unfortunately, you cannot choose which contact to use, unfortunately.
I also tested it only with headphones, so I have no idea how this will sound on the piezo buzzer ...
Hope this gives you some insight into the possibilities and potential starting point for your own melody. I am happy to explain everything that is unclear, and also thank you for giving me a reason to write :)