Using a small 8ohm analogue speaker hooked up to pin 11, by strobing the pin, I generate a square wave (a kind of annoying timbre to be honest).
I generate 2 octaves of semitones starting with A-220 and index into it.
The timing is currently inaccurate as the note length for lower notes runs slightly longer (half a pulse width) than higher notes due to how the strobing currently works. It's surprisingly noticeable. I need to work on that to make it more consistent. Probably by using timer interrupts instead of delays.
To do:
Alter the volume by using analogWrite() to set the duty cycle of the pin... 255 = loud 0 = off.
I think I can use that mechanism to generate other waveforms, I'll probably try sawtooth next.
Proper ADSR waveforms.
Multichannel output (haw haw).
const int baseFreq = 220; // A const int numHalfTones = 24; // 2 Octaves long frequencies[numHalfTones]; long halfFreqs[numHalfTones]; /* 12 semi-tones per octave | Bf| | | C#| Ef| | |F# |G# | -+---+ | +---+---+ | +---+---+- | A | B | C | D | E | F | G | A | +---+---+---+---+---+---+---+---+ 2 octaves: 0 1 2 3 4 5 6 7 8 9 10 11 A Bf B C C# D Ef E F F# G G# 12 13 14 15 16 17 18 19 20 21 22 23 */ int seq[] = { 3, 7, 10, 12, 13, 12, 10 , 7, 3, 7, 10, 12, 13, 12, 10 , 7, 8, 12, 15, 17, 18, 17, 15, 12, 3, 7, 10, 12, 13, 12, 10 , 7, 10, 14, 17, -1, 8, 12, 15, -1 }; int notes = 40; long getTimeHigh(int i) { return halfFreqs[i]; }; void ToneGen(void) { float baseMult; int i; int lastTone = baseFreq; baseMult = pow(2.0 , 0.083333); for(i = 0; i < numHalfTones; ++i) { long frequency = baseFreq; if(i) { frequency = (0.5 + (frequencies[i - 1] * baseMult)); } frequencies[i] = frequency; halfFreqs[i] = (0.5 + (1000000.0 / frequency / 2.0)); } }; void setup(void) { pinMode(11, OUTPUT); ToneGen(); Serial.begin(57600); } int rest_count = 100; long duration = (60 * 1000000) / 288; void playNote(int idx) { long tone = 0; if (idx >= 0) { tone = getTimeHigh(idx); } long endTime = micros() + duration ; if (tone > 0) { int val = HIGH; while (micros() < endTime) { digitalWrite(11,val); delayMicroseconds(tone); val = !val; } } else { delay(duration / 1000); } digitalWrite(11, LOW); } void loop(void) { analogWrite(11, 0); for(int i = 0; i < notes; ++i) { playNote(seq[i]); delay(10); } }
No comments:
Post a Comment