In dieser Lektion ersetzt du Teile des Sketchs für das Theremin, damit es nun Töne erzeugt, die auf einer Tonleiter liegen. Du kannst vieles im Sketch weiterverwenden und kannst auch den Aufbau auf deinem Breadboard behalten.
Werfen wir nun also einen Blick auf die Programmteile, die du für die das Spielen auf einer Tonleiter benötigst. Den gesamten Sketch findest du in den Downloads dieser Lektion.
Zunächst benötigst du ein Array, das die Frequenzen der Töne, die du spielen möchtest, beinhaltet.
//A-Moll Pentatonik
int scale[] = {
147, 165, 196, 220, 262, 294, 330, 392, 440,
523, 587, 659, 784, 880, 1047, 1175, 1319, 1568,
1760, 2093, 2349
};
Im obigen Array findest du Töne, die zur A-Moll Pentatonik gehören. Das sind immer wieder die Töne A – C – D – E – G in verschiedenen Oktaven. Noch einmal zur Erinnerung: Auf Github findest du eine mehr oder weniger vollständige Liste aller Töne und ihrer Frequenzen.
___STEADY_PAYWALL___
Statt der A-Moll Pentatonik kannst du natürlich auch z.B. die C-Dur Tonleiter verwenden. Diese sieht dann wie folgt aus.
//C-Dur Tonleiter
int scale[] = {
131, 147, 165, 175, 196, 220, 247, 262, 294,
330, 349, 392, 440, 494, 523, 587, 659, 698,
784, 880, 988, 1047
};
In diesen Arrays stecken je eine feste Anzahl an Tönen: Das erste Array hat eine Länge von 18 und das zweite besitzt 22 Werte. Die Anzahl der Werte benötigst du später in der Funktion map(), die du ja bereits aus dem Vorgänger-Theremin kennst. Was ist jedoch, wenn du weitere Töne hinzufügen möchtest? In diesem Fall müsstest du die Länge des Arrays auch in anderen Teilen des Sketchs anpassen.
Eleganter ist es jedoch, wenn du dein Programm selbst die Länge des Arrays ermitteln lässt. Hierfür benötigst du nur eine Variable und einen For-Loop:
int lengthOfScale = 0;
for (byte i = 0; i < (sizeof(scale) / sizeof(scale[0])); i++) {
lengthOfScale += 1;
}
In der Variablen speicherst du die Länge des Arrays. Im For-Loop erhöhst du den Wert in dieser Variablen in jedem Durchgang um Eins – und zwar so lange bis der Zähler i das Ende des Arrays erreicht hat. Aber wo liegt das Ende? Das ermittelst du mit sizeof(). Dieser Befehl ermittelt die Zahl der Bytes im Array. Geteilt durch die Zahl der Bytes des ersten Werts des Arrays (mit dem Index 0) ergibt das die Gesamtzahl der Werte im Array.
Nun hast du also die Anzahl der Töne in deiner Tonleiter. Diese benötigst du nun in der Furnktion map(). Hier „mappst“ du wieder die Entfernung deiner Hand auf einen Ton bzw. Frequenz. Diesmal ist der Bereich vom ersten Ton im Array scale[0] und dem letzten scale[lengthOfScale – 1] begrenzt. Hinweis: Von der Variablen lengthOfScale ziehst du Eins ab, weil Arrays mit dem Index 0 beginnen.
note = map(distance, 100, distanceHigh, scale[0], scale[lengthOfScale - 1]);
In der Variablen note steckt nun eine Frequenz – die jedoch nicht unbedingt einem korrekten Ton entspricht. Damit dein Theremin aber die richtigen Töne spielt, benötigst du noch eine letzte Abfrage.
for (byte j = 0; j < (lengthOfScale); j++) {
if (note == scale[j]) {
tone(piezo, note);
break;
}
else if (note > scale[j] && note < scale[j + 1]) {
note = scale[j];
tone(piezo, note);
break;
}
}
Dieser For-Loop läuft über jeden Wert in deinem Array, also so lange wie j < (lengthOfScale) gilt. In jeder Iteration prüfst du zunächst, ob der Wert in der Variablen note zufällig genau einer Note im Array entspricht. Ist das der Fall, spielst du diese Note mit der Funktion tone() und verlässt den Loop mit break.
Wenn das aber nicht der Fall ist, liegt deine gespielte note offensichtlich zwischen zwei Tönen im Array: note > scale[j] && note < scale[j + 1]
Hier spielst du dann den Ton, der eins unter dem Wert in der Variablen note steckt – also den nächsttieferen korrekten Ton. Zu kompliziert? Ein Beispiel: Deine Hand hat eine Entfernung zum Sensor, die du mithilfe der Funktion map() auf eine Frequenz von 200 Hertz umgerechnet hast. Das ist aber keine Note der A-Moll Pentatonik, sondern liegt irgendwo zwischen einem G und einem Gis. Der nächsttiefere, richtige Ton ist laut deinem Array ein G mit 196 Hertz. Und den spielt dein Theremin dann. Auf diese Weise wird dein Theremin immer eine Note spielen, die in deinem Array hinterlegt ist.
Und das war es. Lade den Sketch auf deinen Arduino und fang an zu spielen. 🙂