Melodiekonverter RTTTL to AVR

Der Melodiekonverter erzeugt aus RTTTL (Ring Tone Text Transfer Language) einen platzsparenden Bytecode, der sich gut mit einem Mikrocontroller verarbeiten lässt. Zudem wird eine passende Frequenztabelle abhängig von CPU-Takt und verwendeter Prescaler Einstellung erzeugt. Der Konverter ist voll kompatibel zu dem originalen RTTTL.

Die Vorteile von RTTTL liegen klar auf der Hand:

Dieses Format wurde bei früheren Nokia Handys für individuelle Klingeltöne verwendet, es gibt also bereits viele Beispiele dafür im Internet. Es ist einigermaßen gut lesbar, intuitiv zu erstellen und zudem nah an der Verarbeitung im Mikrocontroller. Auch gibt es Konverter, die Midi-Dateien in dieses Format umwandeln.

Anmerkung: Dieser Konverter ist nur "halbautomatisch". Er lässt nur einen Prescale-Wert zu und berechnet nicht die Frequenzungenauigkeiten. Es werden auch nicht alle Fehler abgefangen. Das erste lässt sich jedoch mit leichten Anpassungen im C-Code implementieren und Werte aus verschiedenen Frequenztabellen zusammenkopieren. Zweites lässt sich mit dem Frequenzrechner erledigen, der die gleichen Töne berechnet.

Wie beim Frequenzrechner wird davon ausgegangen, dass der verwendete Counter im "CTC" Modus (Clear Timer on Compare match) und der zugehörige OC-Ausgang auf "toggle on compare match" gestellt ist.

Einstellungen für Frequenztabelle

CPU-Takt: MHz
Prescaler: (1, 8, 64, 256)

Melodie

RTTTL:

Transponieren:

generierter Code


Abspielalgorithmus

Hier ist der zugehörige C-Code, der das Format interpretiert:
Ein Beispiel mit kompletten Code ist die Jukebox
/*Beispiel #defines müssen angepasst werden! */
#define TON_AN    TCCR0B=(1<<CS01) //Prescale: 8
#define TON_AUS	  TCCR0B=0
#define TON       OCR0A

      uint16_t index=0;
      uint8_t default_octave=melody[index++]&0x0F;
      uint16_t bpm=60000/melody[index++];
    
      while(melody[index]!=0)
      { 
	//Note laden
	uint8_t note=melody[index++];
	uint16_t duration=bpm>>(note>>5);
	if(note&0x10) duration=(duration*3)/2;
	uint8_t octave=default_octave;
	if((note&0x0F)==0x0E) 
	{
	  note=melody[index++];
	  octave=note>>4;
	}
	if((note&0x0F)!=0x0F) 
	{
	  TON  = frequencies[octave*12+(note&0x0F)-1];
	  TON_AN;
	}
	while(--duration)
	  _delay_ms(4);
	TON_AUS;
	_delay_ms(4);
      }

Das Datenformat

Die Melodie besteht aus 3 Teilen: Eine Note ist folgendermaßen aufgebaut: (MSB first) Wenn die Note nicht in der Standartoktave ist, folgt die komplette Note im nächstem Byte. Dieses hat folgenden Aufbau: (MSB first)

Komprimierung: Die Komprimierung nimmt nur Noten auf, die in der Melodie auch vorkommen. Das Ergebnis ist zwar vollständig kompatibel für den Abspielalgorithmus, weicht aber etwas von der Beschreibung ab, da es keine Oktaven gibt und sich die Notenkodierung an den Häufigkeiten der Noten orientiert. Eine größere Komprimierung halte ich nicht unbedingt für sinnvoll, da der Dekodieraufwand steigen würde.

Achtung: Bei der Komprimierung sind Melodie und Frequenztabelle nicht mehr unabhängig voneinander! So ist ein einfaches tauschen der Frequenztabelle oder ein einfaches hinzufügen von Melodien nicht möglich.