AVR-Synthesizer

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

von sam1994

Features

  • 4 Instrumente
  • Bassdrum, Snare, Hihat
  • mehr als 20 gleichzeitig spielende Kanäle @20Mhz
  • einstellbare Samplerate
  • spielt konvertierte Midi-Dateien ab
  • benötigt 7KB Flash, 500-900B Ram

Hardware

Pwm-wandler.svg

Standardmäßig wird der OCR1A-Pin zur Ausgabe verwendet. Ein externer Quarz ist nötig, wenn die Töne auf der richtigen Frequenz liegen sollen.

Software

Der Synthesizer besteht aus einem Synthesizer und einem Sequenzer. Beide müssen am Anfang initialisiert werden. Dem Sequenzer wird beim Laden einer Datei ein Zeiger auf eine Funktion übergeben, die immer das nächste Byte der Datei ausliest. Dadurch ist es ohne großen Aufwand möglich die Datei aus dem Flash oder von einer SD-Karte zu lesen.

Flash

Die Datei wird als Array im Flash gespeichert.

const uint8_t datei[] PROGMEM = {...vom Konverter...};

Dem Sequenzer wird die vordefinierte Funktion ReadFlash übergeben, als Zeiger die Datei:

sei();
//Synthesizer init
synth_init();
//Datei vom Sequenzer laden
seq_load(ReadFlash, (uint8_t*)datei);
//Synthesizer und Sequenzer starten
synth_start();
seq_start();
for(;;)
    synth_update();

SD-Karte

Für die SD-Karte braucht man einen Puffer. Mit 256 Byte ist man auf der sicheren Seite, bei wenigen Kanälen kann man auch 128 oder 64 Byte nehmen. Außerdem muss man eine Funktion definieren, die aus dem Puffer liest und dem Sequenzer übergeben wird. Der übergebene Zeiger wird hier als Index missbraucht.

#define MIDI_BUF_LEN 256
uint8_t midi[MIDI_BUF_LEN];	

uint8_t ReadBuffer(uint8_t* pos)
{
    uint8_t index = (uint16_t)pos;
    return midi[index & (MIDI_BUF_LEN-1)];
}

Am Anfang muss der Puffer gefüllt und der Synthesizer initialisiert werden. In der Hauptschleife wird nur der Puffer nachgefüllt.

//Lesepuffer füllen
uint8_t i = 0;
do
    midi[i] = ffread();
while(++i != (MIDI_BUF_LEN & 0xFF));
//Leseindex auf 0 setzen
uint8_t write = 0;

//Synthesizer init
synth_init();
//Datei vom Sequenzer laden
seq_load(ReadBuffer, 0);
//Synthesizer und Sequenzer starten
synth_start();
seq_start();

for(;;)
{
    //Synthesizerupdate; Diese Funktion muss mindestens im 1ms Intervall aufgerufen werden
    synth_update();
    //Leseindex mit Schreibindex vergleichen
    uint8_t read = (uint8_t)(uint16_t)Seq.file;
    while(read != write)  //Buffer wieder auffüllen
        midi[write++ & (MIDI_BUF_LEN-1)] = ffread();
}

Downloads

Synthesizer

Hinweis: Die Beispiele nutzen den OC1A-Pin zur PWM-Erzeugung.

Konverter

Beispiele

Siehe auch