I started implementing a small audio library for Arduino. It uses the PWM to generate different kinds of waves:
The sinus wave sounds quite bad, but the rest is pretty good, especially the saw wav.
Here is the code with a small example: void audioInit(); void playWhiteNoise(int amp, unsigned long t, int pin); void playSine(int amp, int freq, unsigned long t, int pin); void playSaw(boolean up, int amp, int freq, unsigned long t, int pin); void playSquare(int amp, int freq, unsigned long t, int pin);
void setup() {
audioInit(); randomSeed(analogRead(9));}
void loop() {
Serial.println("SAW up");
playSaw(true, 127, currentFrequency, 1000, AUDIO_OUTPUT);
delay(1000);
Serial.println("SAW down");
playSaw(false, 127, currentFrequency, 1000, AUDIO_OUTPUT);
delay(1000);
Serial.println("SINE");
playSine(127, currentFrequency, 1000, AUDIO_OUTPUT);
delay(1000);
Serial.println("SQUARE");
playSquare(127, currentFrequency, 1000, AUDIO_OUTPUT);
delay(1000); }
void audioInit() {
// Make sure the PWM is at its maximum frequency. TCCR1A = 1; TCCR1B = 9;}
void playWhiteNoise(int amp, unsigned long t, int pin) {
unsigned long startTime = millis();
while (startTime + t >= millis()) {
analogWrite(pin, (int)random(255));
} }
unsigned char valueTable[WAVE_RESOLUTION]; void playSine(int amp, int freq, unsigned long t, int pin) {
amp = constrain(amp, 0, 127);
// reuse t -> convert to number of cycles
t = ((long)freq * (long)t) / 1000;
// reuse freq -> convert to period
freq = (1000000 / freq) - 7; // subtract 7 us to make up for digitalWrite overhead - determined empirically
int i;
for (i=0; i<WAVE_RESOLUTION; i++) {
valueTable[i] = (unsigned char) ( ( (sin((2 * PI * i) / (float) (WAVE_RESOLUTION-1))) + 1.0) * amp );
}
while (t--) {
for (i=0; i<WAVE_RESOLUTION; i++) {
analogWrite(pin, (int)valueTable[i]);
delayMicroseconds(freq / WAVE_RESOLUTION);
}
} }
void playSaw(boolean up, int amp, int freq, unsigned long t, int pin) {
amp = constrain(amp, 0, 127);
// reuse t -> convert to number of cycles
t = ((long)freq * (long)t) / 1000;
// reuse freq -> convert to period
freq = (1000000 / freq) - 7; // subtract 7 us to make up for digitalWrite overhead - determined empirically
int i;
for (i=0; i<WAVE_RESOLUTION; i++) {
valueTable[i] = (unsigned char) ( (up ? i : WAVE_RESOLUTION - i - 1) * 2 * amp / (WAVE_RESOLUTION-1)); // Serial.println((int)valueTable[i]); }
while (t--) {
for (i=0; i<WAVE_RESOLUTION; i++) {
analogWrite(pin, (int)valueTable[i]);
delayMicroseconds(freq / WAVE_RESOLUTION);
}
} }
void playSquare(int amp, int freq, unsigned long t, int pin) { amp = constrain(amp, 0, 127);
// reuse t -> convert to number of cycles
t = ((long)freq * (long)t) / 1000;
// reuse freq -> convert to period
freq = (500000 / freq) - 7; // subtract 7 us to make up for digitalWrite overhead - determined empirically
while (t--) {
analogWrite(pin, 127 + amp);
delayMicroseconds(freq);
analogWrite(pin, 127 - amp);
delayMicroseconds(freq - 1); // - 1 to make up for fractional microsecond in digitaWrite overhead
} }