1
0
Fork 0

initial commit

This commit is contained in:
Eve Entropia 2010-03-30 18:55:18 +02:00
commit 617bdc2d29
281 changed files with 5698 additions and 0 deletions

View file

@ -0,0 +1,233 @@
/*
* speaker_pcm
*
* Plays 8-bit PCM audio on pin 11 using pulse-width modulation (PWM).
* For Arduino with Atmega168 at 16 MHz.
*
* Uses two timers. The first changes the sample value 8000 times a second.
* The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle,
* depending on sample value. The second timer repeats 62500 times per second
* (16000000 / 256), much faster than the playback rate (8000 Hz), so
* it almost sounds halfway decent, just really quiet on a PC speaker.
*
* Takes over Timer 1 (16-bit) for the 8000 Hz timer. This breaks PWM
* (analogWrite()) for Arduino pins 9 and 10. Takes Timer 2 (8-bit)
* for the pulse width modulation, breaking PWM for pins 11 & 3.
*
* References:
* http://www.uchobby.com/index.php/2007/11/11/arduino-sound-part-1/
* http://www.atmel.com/dyn/resources/prod_documents/doc2542.pdf
* http://www.evilmadscientist.com/article.php/avrdac
* http://gonium.net/md/2006/12/27/i-will-think-before-i-code/
* http://fly.cc.fer.hr/GDM/articles/sndmus/speaker2.html
* http://www.gamedev.net/reference/articles/article442.asp
*
* Michael Smith <michael@hurts.ca>
*/
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/delay.h>
#define SAMPLE_RATE 8000
/*
* The audio data needs to be unsigned, 8-bit, 8000 Hz, and small enough
* to fit in flash. 10000-13000 samples is about the limit.
*
* sounddata.h should look like this:
* const int sounddata_length=10000;
* const unsigned char sounddata_data[] PROGMEM = { ..... };
*
* You can use wav2c from GBA CSS:
* http://thieumsweb.free.fr/english/gbacss.html
* Then add "PROGMEM" in the right place. I hacked it up to dump the samples
* as unsigned rather than signed, but it shouldn't matter.
*
* http://musicthing.blogspot.com/2005/05/tiny-music-makers-pt-4-mac-startup.html
* mplayer -ao pcm macstartup.mp3
* sox audiodump.wav -v 1.32 -c 1 -r 8000 -u -1 macstartup-8000.wav
* sox macstartup-8000.wav macstartup-cut.wav trim 0 10000s
* wav2c macstartup-cut.wav sounddata.h sounddata
*
* (starfox) nb. under sox 12.18 (distributed in CentOS 5), i needed to run
* the following command to convert my wav file to the appropriate format:
* sox audiodump.wav -c 1 -r 8000 -u -b macstartup-8000.wav
*/
int ledPin = 13;
int speakerPin = 11;
volatile uint16_t sample1;
volatile uint16_t sample2;
byte lastSample;
prog_uint8_t sintab[] = {
0x01,0x01,0x01,0x01,0x02,0x03,0x05,0x07,
0x09,0x0c,0x0f,0x12,0x15,0x19,0x1c,0x21,
0x25,0x29,0x2e,0x33,0x38,0x3d,0x43,0x48,
0x4e,0x54,0x5a,0x60,0x66,0x6c,0x73,0x79,
0x7f,0x85,0x8b,0x92,0x98,0x9e,0xa4,0xaa,
0xb0,0xb6,0xbb,0xc1,0xc6,0xcb,0xd0,0xd5,
0xd9,0xdd,0xe2,0xe5,0xe9,0xec,0xef,0xf2,
0xf5,0xf7,0xf9,0xfb,0xfc,0xfd,0xfe,0xfe,
0xfe,0xfe,0xfe,0xfd,0xfc,0xfb,0xf9,0xf7,
0xf5,0xf2,0xef,0xec,0xe9,0xe5,0xe2,0xdd,
0xd9,0xd5,0xd0,0xcb,0xc6,0xc1,0xbb,0xb6,
0xb0,0xaa,0xa4,0x9e,0x98,0x92,0x8b,0x85,
0x7f,0x79,0x73,0x6c,0x66,0x60,0x5a,0x54,
0x4e,0x48,0x43,0x3d,0x38,0x33,0x2e,0x29,
0x25,0x21,0x1c,0x19,0x15,0x12,0x0f,0x0c,
0x09,0x07,0x05,0x03,0x02,0x01,0x01,0x01
};
volatile uint16_t tone1_h;
volatile uint16_t tone2_h;
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
OCR2A = (pgm_read_byte(&sintab[sample1 / 512]) +
pgm_read_byte(&sintab[sample2 / 512])) / 2;
// OCR2A = pgm_read_byte(&sintab[sample1 / 512]);
sample1 = (sample1 + tone1_h);
sample2 = (sample2 + tone2_h);
}
void startPlayback()
{
pinMode(speakerPin, OUTPUT);
// Set up Timer 2 to do pulse width modulation on the speaker
// pin.
// Use internal clock (datasheet p.160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Set fast PWM mode (p.157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
// Do non-inverting PWM on pin OC2A (p.155)
// On the Arduino this is pin 11.
TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2A = 0;
// Set up Timer 1 to send a sample every interrupt.
cli();
// Set CTC mode (Clear Timer on Compare Match) (p.133)
// Have to set OCR1A *after*, otherwise it gets reset to 0!
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// No prescaler (p.134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set the compare register (OCR1A).
// OCR1A is a 16-bit register, so we have to do this with
// interrupts disabled to be safe.
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Enable interrupt when TCNT1 == OCR1A (p.136)
TIMSK1 |= _BV(OCIE1A);
sei();
}
void stopPlayback()
{
// Disable playback per-sample interrupt.
TIMSK1 &= ~_BV(OCIE1A);
// Disable the per-sample timer completely.
TCCR1B &= ~_BV(CS10);
// Disable the PWM timer.
TCCR2B &= ~_BV(CS10);
digitalWrite(speakerPin, LOW);
}
void setup()
{
pinMode(ledPin, OUTPUT);
tone1_h = 10;
tone2_h = 10;
startPlayback();
}
void arpeggio(int32_t n1, int32_t n2, int32_t n3, int32_t len) {
tone1_h = 16000/n1;
tone2_h = 16000/n2;
_delay_ms(50*len);
}
void loop()
{
for(;;) {
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(261,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(293,246,146,6);
arpeggio(246,196,99,7);
arpeggio(261,220,99,4);
arpeggio(293,246,99,6);
arpeggio(246,196,99,6);
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(262,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(246,196,99,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
_delay_ms(3000);
}
}

View file

@ -0,0 +1,235 @@
/*
* Theremin - Arduino Physical Computing für Bastler, Designer & Geeks
*
* Soundcode von: Michael Smith <michael@hurts.ca> - http://www.arduino.cc/playground/Code/PCMAudio
* CapSense: http://www.arduino.cc/playground/Main/CapSense
*
* Alex Wenger 2009
*/
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/delay.h>
// Audioausgabe
#define SAMPLE_RATE 8000
// Auf welchem PIN soll Audio ausgegeben werden? (nicht Ändern!!!)
int speakerPin = 11;
const unsigned char sintab[] PROGMEM = {
0x01,0x01,0x01,0x01,0x02,0x03,0x05,0x07,
0x09,0x0c,0x0f,0x12,0x15,0x19,0x1c,0x21,
0x25,0x29,0x2e,0x33,0x38,0x3d,0x43,0x48,
0x4e,0x54,0x5a,0x60,0x66,0x6c,0x73,0x79,
0x7f,0x85,0x8b,0x92,0x98,0x9e,0xa4,0xaa,
0xb0,0xb6,0xbb,0xc1,0xc6,0xcb,0xd0,0xd5,
0xd9,0xdd,0xe2,0xe5,0xe9,0xec,0xef,0xf2,
0xf5,0xf7,0xf9,0xfb,0xfc,0xfd,0xfe,0xfe,
0xfe,0xfe,0xfe,0xfd,0xfc,0xfb,0xf9,0xf7,
0xf5,0xf2,0xef,0xec,0xe9,0xe5,0xe2,0xdd,
0xd9,0xd5,0xd0,0xcb,0xc6,0xc1,0xbb,0xb6,
0xb0,0xaa,0xa4,0x9e,0x98,0x92,0x8b,0x85,
0x7f,0x79,0x73,0x6c,0x66,0x60,0x5a,0x54,
0x4e,0x48,0x43,0x3d,0x38,0x33,0x2e,0x29,
0x25,0x21,0x1c,0x19,0x15,0x12,0x0f,0x0c,
0x09,0x07,0x05,0x03,0x02,0x01,0x01,0x01
};
volatile uint16_t sample1; // welches ist das nächste Sample aus der Sinustabelle
// die oberen 7 bit zeigen in die Tabelle, die restlichen
// bits sind kommastellen
volatile uint16_t sample2;
volatile uint16_t sample3;
uint16_t vol; // aktuelle Lautstärke
volatile uint16_t set_vol; // gewuenschte Lautstärke
volatile uint16_t tone1; // Tonhöhe in "Inkrementiereinheiten"
volatile uint16_t tone2; // Tonhöhe in "Inkrementiereinheiten"
volatile uint16_t tone3; // Tonhöhe in "Inkrementiereinheiten"
// Interruptroutine, diese wird 8000 mal pro Sekunde aufgerufen und berechnet den nächsten
// Wert für die Tonausgabe
ISR(TIMER1_COMPA_vect) {
static int timer1counter; // Zähler um Lautstärkeänderung langsamer zu machen
int wert;
// Wert an der Stelle sample1/512 aus der sinus-Tabelle lesen
wert = pgm_read_byte(&sintab[(sample1 >> 9)])+
pgm_read_byte(&sintab[(sample2 >> 9)])+
pgm_read_byte(&sintab[(sample3 >> 9)]);
// Wert mit der aktuellen Lautstärke multiplizieren
wert = (wert * vol) / 256;
// PWM Hardware anweisen ab jetzt diesen Wert auszugeben
OCR2A = wert;
// nächstes Sample in der Sinustabelle abhängig vom gewünschten
// Ton auswählen.
sample1 += tone1;
sample2 += tone2;
sample3 += tone3;
// Lautstärke anpassen wen gewünscht (nur alle 50 Interrupts, damit
// es schön langsam passiert.
timer1counter++;
if (timer1counter > 50)
{
timer1counter = 0;
if (vol < set_vol) vol++;
if (vol > set_vol) vol--;
}
}
void startPlayback()
{
pinMode(speakerPin, OUTPUT);
// Initialisiere den Timer 2 für die schnelle PWM zur
// Soundausgabe auf Pin 11
// Verwende den internen Takt (Datenblatt Seite 160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Fast PWM mode (Seite 157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
// Wähle die nicht invertierende PWM für pin OC2A und OC2B
// Am Arduino ist das Pin 11 und 3
TCCR2A = (TCCR2A | _BV(COM2A1) | _BV(COM2B1));
// Keine Vorteiler / wir wollen es schnell! (Seite 158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Start Wert = 0, sonst gibt es ein hässliches Ploppgeräusch
OCR2A = 0;
OCR2B = 0;
// Initialisiere Timer 1 für 8000 Interrupts/Sekunde
cli();
// Set CTC mode (Clear Timer on Compare Match) (Seite 133)
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// Kein Vorteiler (Seite 134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Gewünschte Frequenz = 8000kHz
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Aktiviere den Interrupt für TCNT1 == OCR1A (Seite 136)
TIMSK1 |= _BV(OCIE1A);
// Startwerte
sample1 = 0;
sample2 = 0;
sample3 = 0;
// Global Interrupts wieder einschalten.
sei();
}
// Aendert Ton und Lautstärke
// ton (50-4000Hz)
// volume (0-256);
void SetFreq(int ton1,int ton2, int ton3, int volume)
{
tone1 = (128ul*512ul*ton1)/8000;
tone2 = (128ul*512ul*ton2)/8000;
tone3 = (128ul*512ul*ton3)/8000;
set_vol = volume;
}
void setup()
{
startPlayback();
}
uint8_t st1_mod = 1;
uint8_t st2_mod = 1;
uint8_t st3_mod = 1;
uint8_t st3b_mod = 1;
void arpeggio(int32_t n1, int32_t n2, int32_t n3, int32_t len) {
#define MAGIC_FAC 2
for (uint16_t i = 0; i < 5*len*len; i++)
{
#define ALEX 1
#if ALEX
SetFreq(st1_mod*n1*(1+(i/128)), // Stimme 1
st2_mod*n2*(1+(i/96)), // Stimme 2
n3 * (1+(i / 32*st3b_mod)), // Basline
80); // Lautstärke
#else
SetFreq(MAGIC_FAC*n1, // Stimme 1
MAGIC_FAC*n2,// Stimme 2
n3, // Basline
80); // Lautstärke
#endif
_delay_us(600*st3_mod);
}
}
void loop()
{
for(;;) {
st1_mod = random(1,3);
st2_mod = random(1,3);
st3_mod = random(1,4);
st3b_mod = random(1,4);
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(261,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(293,246,146,6);
arpeggio(246,196,99,7);
arpeggio(261,220,99,4);
arpeggio(293,246,99,6);
arpeggio(246,196,99,6);
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(262,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(246,196,99,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
}
}

View file

@ -0,0 +1,228 @@
/*
* Theremin - Arduino Physical Computing für Bastler, Designer & Geeks
*
* Soundcode von: Michael Smith <michael@hurts.ca> - http://www.arduino.cc/playground/Code/PCMAudio
* CapSense: http://www.arduino.cc/playground/Main/CapSense
*
* Alex Wenger 2009
*/
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/delay.h>
// Audioausgabe
#define SAMPLE_RATE 8000
// Auf welchem PIN soll Audio ausgegeben werden? (nicht Ändern!!!)
int speakerPin = 11;
const unsigned char sintab[] PROGMEM = {
0x01,0x01,0x01,0x01,0x02,0x03,0x05,0x07,
0x09,0x0c,0x0f,0x12,0x15,0x19,0x1c,0x21,
0x25,0x29,0x2e,0x33,0x38,0x3d,0x43,0x48,
0x4e,0x54,0x5a,0x60,0x66,0x6c,0x73,0x79,
0x7f,0x85,0x8b,0x92,0x98,0x9e,0xa4,0xaa,
0xb0,0xb6,0xbb,0xc1,0xc6,0xcb,0xd0,0xd5,
0xd9,0xdd,0xe2,0xe5,0xe9,0xec,0xef,0xf2,
0xf5,0xf7,0xf9,0xfb,0xfc,0xfd,0xfe,0xfe,
0xfe,0xfe,0xfe,0xfd,0xfc,0xfb,0xf9,0xf7,
0xf5,0xf2,0xef,0xec,0xe9,0xe5,0xe2,0xdd,
0xd9,0xd5,0xd0,0xcb,0xc6,0xc1,0xbb,0xb6,
0xb0,0xaa,0xa4,0x9e,0x98,0x92,0x8b,0x85,
0x7f,0x79,0x73,0x6c,0x66,0x60,0x5a,0x54,
0x4e,0x48,0x43,0x3d,0x38,0x33,0x2e,0x29,
0x25,0x21,0x1c,0x19,0x15,0x12,0x0f,0x0c,
0x09,0x07,0x05,0x03,0x02,0x01,0x01,0x01
};
volatile uint16_t sample1; // welches ist das nächste Sample aus der Sinustabelle
// die oberen 7 bit zeigen in die Tabelle, die restlichen
// bits sind kommastellen
volatile uint16_t sample2;
volatile uint16_t sample3;
uint16_t vol; // aktuelle Lautstärke
volatile uint16_t set_vol; // gewuenschte Lautstärke
volatile uint16_t tone1; // Tonhöhe in "Inkrementiereinheiten"
volatile uint16_t tone2; // Tonhöhe in "Inkrementiereinheiten"
volatile uint16_t tone3; // Tonhöhe in "Inkrementiereinheiten"
// Interruptroutine, diese wird 8000 mal pro Sekunde aufgerufen und berechnet den nächsten
// Wert für die Tonausgabe
ISR(TIMER1_COMPA_vect) {
static int timer1counter; // Zähler um Lautstärkeänderung langsamer zu machen
int wert;
// Wert an der Stelle sample1/512 aus der sinus-Tabelle lesen
/* wert = pgm_read_byte(&sintab[(sample1 >> 9)])+
pgm_read_byte(&sintab[(sample2 >> 9)])+
pgm_read_byte(&sintab[(sample3 >> 9)]); */
wert = pgm_read_byte(&sintab[(sample1 >> 9)])+
pgm_read_byte(&sintab[(sample2 >> 9)])+
(sample3 >> 8);
// Wert mit der aktuellen Lautstärke multiplizieren
wert = (wert * vol) / 256;
// PWM Hardware anweisen ab jetzt diesen Wert auszugeben
OCR2A = wert;
// nächstes Sample in der Sinustabelle abhängig vom gewünschten
// Ton auswählen.
sample1 += tone1;
sample2 += tone2;
sample3 += tone3;
// Lautstärke anpassen wen gewünscht (nur alle 50 Interrupts, damit
// es schön langsam passiert.
timer1counter++;
if (timer1counter > 50)
{
timer1counter = 0;
if (vol < set_vol) vol++;
if (vol > set_vol) vol--;
}
}
void startPlayback()
{
pinMode(speakerPin, OUTPUT);
// Initialisiere den Timer 2 für die schnelle PWM zur
// Soundausgabe auf Pin 11
// Verwende den internen Takt (Datenblatt Seite 160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Fast PWM mode (Seite 157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
// Wähle die nicht invertierende PWM für pin OC2A und OC2B
// Am Arduino ist das Pin 11 und 3
TCCR2A = (TCCR2A | _BV(COM2A1) | _BV(COM2B1));
// Keine Vorteiler / wir wollen es schnell! (Seite 158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Start Wert = 0, sonst gibt es ein hässliches Ploppgeräusch
OCR2A = 0;
OCR2B = 0;
// Initialisiere Timer 1 für 8000 Interrupts/Sekunde
cli();
// Set CTC mode (Clear Timer on Compare Match) (Seite 133)
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// Kein Vorteiler (Seite 134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Gewünschte Frequenz = 8000kHz
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Aktiviere den Interrupt für TCNT1 == OCR1A (Seite 136)
TIMSK1 |= _BV(OCIE1A);
// Startwerte
sample1 = 0;
sample2 = 0;
sample3 = 0;
// Global Interrupts wieder einschalten.
sei();
}
// Aendert Ton und Lautstärke
// ton (50-4000Hz)
// volume (0-256);
void SetFreq(int ton1,int ton2, int ton3, int volume)
{
tone1 = (128ul*512ul*ton1)/8000;
tone2 = (128ul*512ul*ton2)/8000;
tone3 = (128ul*512ul*ton3)/8000;
set_vol = volume;
}
void setup()
{
startPlayback();
}
uint8_t st1_mod = 1;
uint8_t st2_mod = 1;
uint8_t st3_mod = 1;
uint8_t st3b_mod = 1;
void arpeggio(int32_t n1, int32_t n2, int32_t n3, int32_t len) {
#define MAGIC_FAC 2
for (uint16_t i = 0; i < 5*len*len; i++)
{
SetFreq(MAGIC_FAC*n1, // Stimme 1
MAGIC_FAC*n2,// Stimme 2
n3, // Basline
80); // Lautstärke
_delay_us(600*st3_mod);
}
}
void loop()
{
st1_mod = random(1,3);
st2_mod = random(1,3);
//st3_mod = random(1,4);
st3_mod = 2;
st3b_mod = random(1,4);
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(261,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(293,246,146,6);
arpeggio(246,196,99,7);
arpeggio(261,220,99,4);
arpeggio(293,246,99,6);
arpeggio(246,196,99,6);
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(262,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(246,196,99,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
}

View file

@ -0,0 +1,233 @@
/*
* speaker_pcm
*
* Plays 8-bit PCM audio on pin 11 using pulse-width modulation (PWM).
* For Arduino with Atmega168 at 16 MHz.
*
* Uses two timers. The first changes the sample value 8000 times a second.
* The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle,
* depending on sample value. The second timer repeats 62500 times per second
* (16000000 / 256), much faster than the playback rate (8000 Hz), so
* it almost sounds halfway decent, just really quiet on a PC speaker.
*
* Takes over Timer 1 (16-bit) for the 8000 Hz timer. This breaks PWM
* (analogWrite()) for Arduino pins 9 and 10. Takes Timer 2 (8-bit)
* for the pulse width modulation, breaking PWM for pins 11 & 3.
*
* References:
* http://www.uchobby.com/index.php/2007/11/11/arduino-sound-part-1/
* http://www.atmel.com/dyn/resources/prod_documents/doc2542.pdf
* http://www.evilmadscientist.com/article.php/avrdac
* http://gonium.net/md/2006/12/27/i-will-think-before-i-code/
* http://fly.cc.fer.hr/GDM/articles/sndmus/speaker2.html
* http://www.gamedev.net/reference/articles/article442.asp
*
* Michael Smith <michael@hurts.ca>
*/
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/delay.h>
#define SAMPLE_RATE 8000
/*
* The audio data needs to be unsigned, 8-bit, 8000 Hz, and small enough
* to fit in flash. 10000-13000 samples is about the limit.
*
* sounddata.h should look like this:
* const int sounddata_length=10000;
* const unsigned char sounddata_data[] PROGMEM = { ..... };
*
* You can use wav2c from GBA CSS:
* http://thieumsweb.free.fr/english/gbacss.html
* Then add "PROGMEM" in the right place. I hacked it up to dump the samples
* as unsigned rather than signed, but it shouldn't matter.
*
* http://musicthing.blogspot.com/2005/05/tiny-music-makers-pt-4-mac-startup.html
* mplayer -ao pcm macstartup.mp3
* sox audiodump.wav -v 1.32 -c 1 -r 8000 -u -1 macstartup-8000.wav
* sox macstartup-8000.wav macstartup-cut.wav trim 0 10000s
* wav2c macstartup-cut.wav sounddata.h sounddata
*
* (starfox) nb. under sox 12.18 (distributed in CentOS 5), i needed to run
* the following command to convert my wav file to the appropriate format:
* sox audiodump.wav -c 1 -r 8000 -u -b macstartup-8000.wav
*/
int ledPin = 13;
int speakerPin = 11;
volatile uint16_t sample1;
volatile uint16_t sample2;
byte lastSample;
prog_uint8_t sintab[] = {
0x01,0x01,0x01,0x01,0x02,0x03,0x05,0x07,
0x09,0x0c,0x0f,0x12,0x15,0x19,0x1c,0x21,
0x25,0x29,0x2e,0x33,0x38,0x3d,0x43,0x48,
0x4e,0x54,0x5a,0x60,0x66,0x6c,0x73,0x79,
0x7f,0x85,0x8b,0x92,0x98,0x9e,0xa4,0xaa,
0xb0,0xb6,0xbb,0xc1,0xc6,0xcb,0xd0,0xd5,
0xd9,0xdd,0xe2,0xe5,0xe9,0xec,0xef,0xf2,
0xf5,0xf7,0xf9,0xfb,0xfc,0xfd,0xfe,0xfe,
0xfe,0xfe,0xfe,0xfd,0xfc,0xfb,0xf9,0xf7,
0xf5,0xf2,0xef,0xec,0xe9,0xe5,0xe2,0xdd,
0xd9,0xd5,0xd0,0xcb,0xc6,0xc1,0xbb,0xb6,
0xb0,0xaa,0xa4,0x9e,0x98,0x92,0x8b,0x85,
0x7f,0x79,0x73,0x6c,0x66,0x60,0x5a,0x54,
0x4e,0x48,0x43,0x3d,0x38,0x33,0x2e,0x29,
0x25,0x21,0x1c,0x19,0x15,0x12,0x0f,0x0c,
0x09,0x07,0x05,0x03,0x02,0x01,0x01,0x01
};
volatile uint16_t tone1_h;
volatile uint16_t tone2_h;
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
OCR2A = (pgm_read_byte(&sintab[sample1 / 512]) +
pgm_read_byte(&sintab[sample2 / 512])) / 2;
// OCR2A = pgm_read_byte(&sintab[sample1 / 512]);
sample1 = (sample1 + tone1_h);
sample2 = (sample2 + tone2_h);
}
void startPlayback()
{
pinMode(speakerPin, OUTPUT);
// Set up Timer 2 to do pulse width modulation on the speaker
// pin.
// Use internal clock (datasheet p.160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Set fast PWM mode (p.157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
// Do non-inverting PWM on pin OC2A (p.155)
// On the Arduino this is pin 11.
TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2A = 0;
// Set up Timer 1 to send a sample every interrupt.
cli();
// Set CTC mode (Clear Timer on Compare Match) (p.133)
// Have to set OCR1A *after*, otherwise it gets reset to 0!
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// No prescaler (p.134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set the compare register (OCR1A).
// OCR1A is a 16-bit register, so we have to do this with
// interrupts disabled to be safe.
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Enable interrupt when TCNT1 == OCR1A (p.136)
TIMSK1 |= _BV(OCIE1A);
sei();
}
void stopPlayback()
{
// Disable playback per-sample interrupt.
TIMSK1 &= ~_BV(OCIE1A);
// Disable the per-sample timer completely.
TCCR1B &= ~_BV(CS10);
// Disable the PWM timer.
TCCR2B &= ~_BV(CS10);
digitalWrite(speakerPin, LOW);
}
void setup()
{
pinMode(ledPin, OUTPUT);
tone1_h = 10;
tone2_h = 10;
startPlayback();
}
void arpeggio(int32_t n1, int32_t n2, int32_t n3, int32_t len) {
tone1_h = 16000/n1;
tone2_h = 16000/n2;
_delay_ms(50*len);
}
void loop()
{
for(;;) {
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(261,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(293,246,146,6);
arpeggio(246,196,99,7);
arpeggio(261,220,99,4);
arpeggio(293,246,99,6);
arpeggio(246,196,99,6);
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(262,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(246,196,99,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
_delay_ms(3000);
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,134 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
// number of timer0 overflows/sec
#define INT_PER_SEC F_CPU/1/256
// Frequencies (in Hz) of notes
#define F_FSH_4 370
#define F_A_4 440
#define F_B_4 494
#define F_E_4 330
#define F_CSH_5 554
#define F_D_5 587
#define F_FSH_5 740
#define F_CSH_4 277
#define F_GSH_4 415
// number of timer0 overflows for notes
#define REST -1 // special case
#define FSH_4 INT_PER_SEC/F_FSH_4
#define A_4 INT_PER_SEC/F_A_4
#define B_4 INT_PER_SEC/F_B_4
#define E_4 INT_PER_SEC/F_E_4
#define CSH_5 INT_PER_SEC/F_CSH_5
#define D_5 INT_PER_SEC/F_D_5
#define FSH_5 INT_PER_SEC/F_FSH_5
#define CSH_4 INT_PER_SEC/F_CSH_4
#define GSH_4 INT_PER_SEC/F_GSH_4
#define SEMIQUAVER_TIME 60 // ms
#define BREATH_TIME 20 // ms
#include "WProgram.h"
void play(int32_t note, uint32_t len);
void setup();
void loop();
volatile uint32_t intrs = 0;
volatile int32_t curNote = REST;
// TIMER0 overflow
ISR(TIMER0_OVF_vect)
{
if (curNote == REST)
intrs = 0;
else
{
intrs++;
if (intrs >= curNote)
{
PORTD ^= _BV(PD4);
intrs = 0;
}
}
}
void play(int32_t note, uint32_t len)
{
int i;
curNote = note;
for (i = 0; i< len; i++)
_delay_ms(SEMIQUAVER_TIME);
curNote = REST;
_delay_ms(BREATH_TIME);
}
void setup() {
/* setup clock divider. Timer0 overflows on counting to 256.
* 16Mhz / 1 (CS0=1) = 16000000 increments/sec. Overflows every 256.
*/
TCCR0B |= _BV(CS00);
// enable overflow interrupts
TIMSK0 |= _BV(TOIE0);
// PD4 as output
DDRD = _BV(PD4);
TCNT0 = 0;
intrs = 0;
curNote = REST;
// enable interrupts
sei();
}
void loop() {
// Axel F
play(FSH_4, 2);
play(REST, 2);
play(A_4, 3);
play(FSH_4, 2);
play(FSH_4, 1);
play(B_4, 2);
play(FSH_4, 2);
play(E_4, 2);
play(FSH_4, 2);
play(REST, 2);
play(CSH_5, 3);
play(FSH_4, 2);
play(FSH_4, 1);
play(D_5, 2);
play(CSH_5, 2);
play(A_4, 2);
play(FSH_4, 2);
play(CSH_5, 2);
play(FSH_5, 2);
play(FSH_4, 1);
play(E_4, 2);
play(E_4, 1);
play(CSH_4, 2);
play(GSH_4, 2);
play(FSH_4, 6);
play(REST, 12);
delay(3000);
}
int main(void)
{
init();
setup();
for (;;)
loop();
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,184 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#define REST -1
// number of timer0 overflows/sec
#define INT_PER_SEC F_CPU/1/256
volatile uint32_t intrs = 0;
volatile int32_t curNote = REST;
// TIMER0 overflow
ISR(TIMER0_OVF_vect) {
if (curNote == REST) {
intrs = 0;
} else {
intrs++;
if (intrs >= curNote) {
PORTD ^= _BV(PD4);
intrs = 0;
}
}
}
void arpeggio_play(int32_t note, uint32_t len) {
// FIXME: curNote is in interrupts, note is in hertz...
curNote = INT_PER_SEC/note/2;
// len is in PC clock ticks * 10
// clock tick is 1s/18.2 == 54ms
#define MAGIC_CLOCK_TICK 54
#define MAGIC_DELAY_FACTOR 400 // well, should be 1000 us?!
#define MAGIC_BREATH 50
_delay_us(MAGIC_DELAY_FACTOR*(len*MAGIC_CLOCK_TICK/10));
// breath
curNote=REST;
_delay_us(50);
}
void arpeggio(int32_t n1, int32_t n2, int32_t n3, int32_t len) {
for (int32_t i = 0; i < len; i++) {
arpeggio_play(n1, len);
arpeggio_play(n2, len);
arpeggio_play(n3, len);
}
}
int main(void) {
/* setup clock divider. Timer0 overflows on counting to 256.
* 16Mhz / 1 (CS0=1) = 16000000 increments/sec. Overflows every 256.
*/
TCCR0B |= _BV(CS00);
// enable overflow interrupts
TIMSK0 |= _BV(TOIE0);
// PD4 as output
DDRD = _BV(PD4);
TCNT0 = 0;
intrs = 0;
curNote = REST;
// enable interrupts
sei();
for(;;) {
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(261,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(293,246,146,6);
arpeggio(246,196,99,7);
arpeggio(261,220,99,4);
arpeggio(293,246,99,6);
arpeggio(246,196,99,6);
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(262,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(246,196,99,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
}
}
/*
10 REM ARPEGGIO BY JIM LEONARD 5/8/1984
15 WIDTH 80:SCREEN 0,0,0:KEY OFF
20 READ N1,N2,N3,D:ON ERROR GOTO 10000
30 FOR I = 1 TO D
40 SOUND N1,D*.1
50 SOUND N2,D*.1
60 SOUND N3,D*.1
70 NEXT
80 GOTO 20
300 DATA 261,329,130,7
310 DATA 329,392,130,4
320 DATA 329,392,130,6
330 DATA 329,392,123,6
340 DATA 261,329,110,7
350 DATA 329,392,110,4
360 DATA 493,392,110,4
370 DATA 523,440,110,4
375 DATA 440,349,110,6
380 DATA 293,246,146,7
390 DATA 329,261,146,4
400 DATA 349,293,146,6
410 DATA 293,246,146,6
420 DATA 246,196,99,7
430 DATA 261,220,99,4
440 DATA 293,246,99,6
450 DATA 246,196,99,6
500 DATA 261,329,130,7:REM REPEAT (ALMOST)
510 DATA 329,392,130,4
520 DATA 329,392,130,6
530 DATA 329,392,123,6
540 DATA 261,329,110,7
550 DATA 329,392,110,4
560 DATA 493,392,110,4
570 DATA 523,440,110,4
575 DATA 440,349,110,6
580 DATA 293,246,146,7
590 DATA 329,261,146,4
600 DATA 349,293,146,6
620 DATA 246,196,99,6
630 DATA 261,329,110,6
640 DATA 261,329,110,6
645 DATA 261,329,110,6
650 DATA 246,196,99,6
660 DATA 174,220,82,6
670 DATA 174,220,82,6
680 DATA 174,220,82,6
690 DATA 246,196,99,6
700 DATA 261,329,110,6
710 DATA 261,329,110,6
720 DATA 261,329,110,6
730 DATA 261,329,110,6
740 DATA 261,329,110,6
750 DATA 261,329,110,6
760 DATA 261,329,110,6
10000 LOCATE 24,1:END
*/

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,134 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
// number of timer0 overflows/sec
#define INT_PER_SEC F_CPU/1/256
// Frequencies (in Hz) of notes
#define F_FSH_4 370
#define F_A_4 440
#define F_B_4 494
#define F_E_4 330
#define F_CSH_5 554
#define F_D_5 587
#define F_FSH_5 740
#define F_CSH_4 277
#define F_GSH_4 415
// number of timer0 overflows for notes
#define REST -1 // special case
#define FSH_4 INT_PER_SEC/F_FSH_4
#define A_4 INT_PER_SEC/F_A_4
#define B_4 INT_PER_SEC/F_B_4
#define E_4 INT_PER_SEC/F_E_4
#define CSH_5 INT_PER_SEC/F_CSH_5
#define D_5 INT_PER_SEC/F_D_5
#define FSH_5 INT_PER_SEC/F_FSH_5
#define CSH_4 INT_PER_SEC/F_CSH_4
#define GSH_4 INT_PER_SEC/F_GSH_4
#define SEMIQUAVER_TIME 60 // ms
#define BREATH_TIME 20 // ms
#include "WProgram.h"
void play(int32_t note, uint32_t len);
int main(void);
volatile uint32_t intrs = 0;
volatile int32_t curNote = REST;
// TIMER0 overflow
ISR(TIMER0_OVF_vect)
{
if (curNote == REST)
intrs = 0;
else
{
intrs++;
if (intrs >= curNote)
{
PORTD ^= _BV(PD4);
intrs = 0;
}
}
}
void play(int32_t note, uint32_t len)
{
int i;
curNote = note;
for (i = 0; i< len; i++)
_delay_ms(SEMIQUAVER_TIME);
curNote = REST;
_delay_ms(BREATH_TIME);
}
int main(void)
{
/* setup clock divider. Timer0 overflows on counting to 256.
* 16Mhz / 1 (CS0=1) = 16000000 increments/sec. Overflows every 256.
*/
TCCR0B |= _BV(CS00);
// enable overflow interrupts
TIMSK0 |= _BV(TOIE0);
// PD4 as output
DDRD = _BV(PD4);
TCNT0 = 0;
intrs = 0;
curNote = REST;
// enable interrupts
sei();
while (1)
{
// Axel F
play(FSH_4, 2);
play(REST, 2);
play(A_4, 3);
play(FSH_4, 2);
play(FSH_4, 1);
play(B_4, 2);
play(FSH_4, 2);
play(E_4, 2);
play(FSH_4, 2);
play(REST, 2);
play(CSH_5, 3);
play(FSH_4, 2);
play(FSH_4, 1);
play(D_5, 2);
play(CSH_5, 2);
play(A_4, 2);
play(FSH_4, 2);
play(CSH_5, 2);
play(FSH_5, 2);
play(FSH_4, 1);
play(E_4, 2);
play(E_4, 1);
play(CSH_4, 2);
play(GSH_4, 2);
play(FSH_4, 6);
play(REST, 12);
}
delay(3000);
}
int main(void)
{
init();
setup();
for (;;)
loop();
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,119 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
// number of timer0 overflows/sec
#define INT_PER_SEC F_CPU/1/256
// Frequencies (in Hz) of notes
#define F_FSH_4 370
#define F_A_4 440
#define F_B_4 494
#define F_E_4 330
#define F_CSH_5 554
#define F_D_5 587
#define F_FSH_5 740
#define F_CSH_4 277
#define F_GSH_4 415
// number of timer0 overflows for notes
#define REST -1 // special case
#define FSH_4 INT_PER_SEC/F_FSH_4
#define A_4 INT_PER_SEC/F_A_4
#define B_4 INT_PER_SEC/F_B_4
#define E_4 INT_PER_SEC/F_E_4
#define CSH_5 INT_PER_SEC/F_CSH_5
#define D_5 INT_PER_SEC/F_D_5
#define FSH_5 INT_PER_SEC/F_FSH_5
#define CSH_4 INT_PER_SEC/F_CSH_4
#define GSH_4 INT_PER_SEC/F_GSH_4
#define SEMIQUAVER_TIME 60 // ms
#define BREATH_TIME 20 // ms
volatile uint32_t intrs = 0;
volatile int32_t curNote = REST;
// TIMER0 overflow
ISR(TIMER0_OVF_vect)
{
if (curNote == REST)
intrs = 0;
else
{
intrs++;
if (intrs >= curNote)
{
PORTD ^= _BV(PD4);
intrs = 0;
}
}
}
void play(int32_t note, uint32_t len)
{
int i;
curNote = note;
for (i = 0; i< len; i++)
_delay_ms(SEMIQUAVER_TIME);
curNote = REST;
_delay_ms(BREATH_TIME);
}
int main(void)
{
/* setup clock divider. Timer0 overflows on counting to 256.
* 16Mhz / 1 (CS0=1) = 16000000 increments/sec. Overflows every 256.
*/
TCCR0B |= _BV(CS00);
// enable overflow interrupts
TIMSK0 |= _BV(TOIE0);
// PD4 as output
DDRD = _BV(PD4);
TCNT0 = 0;
intrs = 0;
curNote = REST;
// enable interrupts
sei();
while (1)
{
// Axel F
play(FSH_4, 2);
play(REST, 2);
play(A_4, 3);
play(FSH_4, 2);
play(FSH_4, 1);
play(B_4, 2);
play(FSH_4, 2);
play(E_4, 2);
play(FSH_4, 2);
play(REST, 2);
play(CSH_5, 3);
play(FSH_4, 2);
play(FSH_4, 1);
play(D_5, 2);
play(CSH_5, 2);
play(A_4, 2);
play(FSH_4, 2);
play(CSH_5, 2);
play(FSH_5, 2);
play(FSH_4, 1);
play(E_4, 2);
play(E_4, 1);
play(CSH_4, 2);
play(GSH_4, 2);
play(FSH_4, 6);
play(REST, 12);
}
delay(3000);
}

View file

@ -0,0 +1,104 @@
#include "avr/delay.h"
void setup() {
pinMode(11, OUTPUT);
// Set up Timer 2 to do pulse width modulation on the speaker
// pin.
// Use internal clock (datasheet p.160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Set fast PWM mode (p.157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
// Do non-inverting PWM on pin OC2A (p.155)
// On the Arduino this is pin 11.
TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2A = 0;
}
int play (uint16_t f, uint8_t T) {
sendKarplusStrongSound(f, T);
}
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1249193795
int sendKarplusStrongSound(const uint16_t f /*Hz*/, const uint8_t T /*sec*/) {
const uint8_t N = 32;
const uint32_t sr = f * N; // sample rate: 800(25Hz)..47619(1488Hz)
int16_t buf[N];
for (uint8_t i=0; i<N; i++)
buf[i] = (int16_t) random(-32768,32767);
uint8_t bh = 0;
const int Tloop = 60; // or is it more?
const int dt = 16000000/sr - Tloop;
for (uint32_t i=sr*T/2; i>0; i--) {
const int8_t v = (int8_t) (buf[bh] >> 8);
OCR2A = v;
_delay_us(dt); // or do something else for <dt> usecs
uint8_t nbh = bh!=N-1 ? bh+1 : 0;
int32_t avg = buf[bh] + (int32_t)buf[nbh];
//avg = (avg << 10) - avg; // subtract avg more than once to get faster volume decrease
avg = (avg << 10) - avg -avg;
buf[bh] = avg >> 11; // no division, just shift
bh = nbh;
}
}
// Frequencies (in Hz) of notes
#define FSH_4 370
#define A_4 440
#define B_4 494
#define E_4 330
#define CSH_5 554
#define D_5 587
#define FSH_5 740
#define CSH_4 277
#define GSH_4 415
#define REST 0
void loop() {
// Axel F
play(FSH_4, 2);
play(REST, 2);
play(A_4, 3);
play(FSH_4, 2);
play(FSH_4, 1);
play(B_4, 2);
play(FSH_4, 2);
play(E_4, 2);
play(FSH_4, 2);
play(REST, 2);
play(CSH_5, 3);
play(FSH_4, 2);
play(FSH_4, 1);
play(D_5, 2);
play(CSH_5, 2);
play(A_4, 2);
play(FSH_4, 2);
play(CSH_5, 2);
play(FSH_5, 2);
play(FSH_4, 1);
play(E_4, 2);
play(E_4, 1);
play(CSH_4, 2);
play(GSH_4, 2);
play(FSH_4, 6);
play(REST, 12);
delay(100);
}

Binary file not shown.

View file

@ -0,0 +1,210 @@
/*
* Theremin - Arduino Physical Computing für Bastler, Designer & Geeks
*
* Soundcode von: Michael Smith <michael@hurts.ca> - http://www.arduino.cc/playground/Code/PCMAudio
* CapSense: http://www.arduino.cc/playground/Main/CapSense
*
* Alex Wenger 2009
*/
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/delay.h>
// Audioausgabe
#define SAMPLE_RATE 8000
// Auf welchem PIN soll Audio ausgegeben werden? (nicht Ändern!!!)
int speakerPin = 11;
const unsigned char sintab[] PROGMEM = {
0x01,0x01,0x01,0x01,0x02,0x03,0x05,0x07,
0x09,0x0c,0x0f,0x12,0x15,0x19,0x1c,0x21,
0x25,0x29,0x2e,0x33,0x38,0x3d,0x43,0x48,
0x4e,0x54,0x5a,0x60,0x66,0x6c,0x73,0x79,
0x7f,0x85,0x8b,0x92,0x98,0x9e,0xa4,0xaa,
0xb0,0xb6,0xbb,0xc1,0xc6,0xcb,0xd0,0xd5,
0xd9,0xdd,0xe2,0xe5,0xe9,0xec,0xef,0xf2,
0xf5,0xf7,0xf9,0xfb,0xfc,0xfd,0xfe,0xfe,
0xfe,0xfe,0xfe,0xfd,0xfc,0xfb,0xf9,0xf7,
0xf5,0xf2,0xef,0xec,0xe9,0xe5,0xe2,0xdd,
0xd9,0xd5,0xd0,0xcb,0xc6,0xc1,0xbb,0xb6,
0xb0,0xaa,0xa4,0x9e,0x98,0x92,0x8b,0x85,
0x7f,0x79,0x73,0x6c,0x66,0x60,0x5a,0x54,
0x4e,0x48,0x43,0x3d,0x38,0x33,0x2e,0x29,
0x25,0x21,0x1c,0x19,0x15,0x12,0x0f,0x0c,
0x09,0x07,0x05,0x03,0x02,0x01,0x01,0x01
};
volatile uint16_t sample1; // welches ist das nächste Sample aus der Sinustabelle
// die oberen 7 bit zeigen in die Tabelle, die restlichen
// bits sind kommastellen
volatile uint16_t sample2;
volatile uint16_t sample3;
uint16_t vol; // aktuelle Lautstärke
volatile uint16_t set_vol; // gewuenschte Lautstärke
volatile uint16_t tone1; // Tonhöhe in "Inkrementiereinheiten"
volatile uint16_t tone2; // Tonhöhe in "Inkrementiereinheiten"
volatile uint16_t tone3; // Tonhöhe in "Inkrementiereinheiten"
// Interruptroutine, diese wird 8000 mal pro Sekunde aufgerufen und berechnet den nächsten
// Wert für die Tonausgabe
ISR(TIMER1_COMPA_vect) {
static int timer1counter; // Zähler um Lautstärkeänderung langsamer zu machen
int wert;
// Wert an der Stelle sample1/512 aus der sinus-Tabelle lesen
wert = pgm_read_byte(&sintab[(sample1 >> 9)])+
pgm_read_byte(&sintab[(sample2 >> 9)])+
pgm_read_byte(&sintab[(sample3 >> 9)]);
// Wert mit der aktuellen Lautstärke multiplizieren
wert = (wert * vol) / 256;
// PWM Hardware anweisen ab jetzt diesen Wert auszugeben
OCR2A = wert;
// nächstes Sample in der Sinustabelle abhängig vom gewünschten
// Ton auswählen.
sample1 += tone1;
sample2 += tone2;
sample3 += tone3;
// Lautstärke anpassen wen gewünscht (nur alle 50 Interrupts, damit
// es schön langsam passiert.
timer1counter++;
if (timer1counter > 50)
{
timer1counter = 0;
if (vol < set_vol) vol++;
if (vol > set_vol) vol--;
}
}
void startPlayback()
{
pinMode(speakerPin, OUTPUT);
// Initialisiere den Timer 2 für die schnelle PWM zur
// Soundausgabe auf Pin 11
// Verwende den internen Takt (Datenblatt Seite 160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Fast PWM mode (Seite 157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
// Wähle die nicht invertierende PWM für pin OC2A und OC2B
// Am Arduino ist das Pin 11 und 3
TCCR2A = (TCCR2A | _BV(COM2A1) | _BV(COM2B1));
// Keine Vorteiler / wir wollen es schnell! (Seite 158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Start Wert = 0, sonst gibt es ein hässliches Ploppgeräusch
OCR2A = 0;
OCR2B = 0;
// Initialisiere Timer 1 für 8000 Interrupts/Sekunde
cli();
// Set CTC mode (Clear Timer on Compare Match) (Seite 133)
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// Kein Vorteiler (Seite 134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Gewünschte Frequenz = 8000kHz
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Aktiviere den Interrupt für TCNT1 == OCR1A (Seite 136)
TIMSK1 |= _BV(OCIE1A);
// Startwerte
sample1 = 0;
sample2 = 0;
sample3 = 0;
// Global Interrupts wieder einschalten.
sei();
}
// Aendert Ton und Lautstärke
// ton (50-4000Hz)
// volume (0-256);
void SetFreq(int ton1,int ton2, int ton3, int volume)
{
tone1 = (128ul*512ul*ton1)/8000;
tone2 = (128ul*512ul*ton2)/8000;
tone3 = (128ul*512ul*ton3)/8000;
set_vol = volume;
}
void setup()
{
startPlayback();
}
void arpeggio(int32_t n1, int32_t n2, int32_t n3, int32_t len) {
#define MAGIC_FAC 2
SetFreq(MAGIC_FAC*n1,MAGIC_FAC*n2,n3,80);
_delay_ms(5*len*len);
}
void loop()
{
for(;;) {
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(261,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(293,246,146,6);
arpeggio(246,196,99,7);
arpeggio(261,220,99,4);
arpeggio(293,246,99,6);
arpeggio(246,196,99,6);
arpeggio(261,329,130,7);
arpeggio(329,392,130,4);
arpeggio(329,392,130,6);
arpeggio(329,392,123,6);
arpeggio(262,329,110,7);
arpeggio(329,392,110,4);
arpeggio(493,392,110,4);
arpeggio(523,440,110,4);
arpeggio(440,349,110,6);
arpeggio(293,246,146,7);
arpeggio(329,261,146,4);
arpeggio(349,293,146,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(246,196,99,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(174,220,82,6);
arpeggio(246,196,99,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
arpeggio(261,329,110,6);
}
}