![]() |
Hardware-ProjekteProf. Jürgen Plate |
Um einen Ton zu erzeugen, muß zunächst der zuständige Timer mit der gewünschten Frequenz programmiert werden. Dieser Timer wird über die Ports 43H und 42H angesprochen. Die Frequenz wird durch einen 16-Bit-Teilfaktor bestimmt, der die Taktfrequenz des Timers entsprechend herunterteilt:
Teilfaktor = 133100/FrequenzZum Ein-und Ausschalten des Lautsprechers dürfen nur die beiden Bits 0 und 1 des PPI gesetzt oder gelöscht werden, die anderen Bits müssen erhalten bleiben.
Glücklicherweise ist der interne Lautsprecher Teil der Linux Console und daher ein character device. So bleibt einem der direkte Portzugriff erspart. Es genügt die Funktion ioctl(). Für den internen Lautsprecher gibt es zwei Requests, die sich auf den Kernel stützen:
ioctl (fd, KDMKTONE,(long) argument)
ioctl(fd,KIOCSOUND,(int) tone).
Tonhoehe = 1190000/FrequenzDie Dauer wird in Timer Ticks gemessen. Beie Aufrufe kehren sofort zurück, das Programm wird also durch das Piepsen nicht blockiert. KDMKTONE eignet sich gut für Warnsignale, weil der Ton von selbst endet. KIOCSOUND kann verwendet werden, um Melodien zu spielen. Um hier wieder Stille zu erhalten, muß die Tonhöhe 0 angegeben werden.
In der westlichen Welt hat sich durchgesetzt, die Oktave in 12 Halbtonschritte aufzuteilen (chromatische Tonleiter). Dabei ist es möglich, die Oktave mit 12 gleichen Halbtonschritten (gleichstufige Stimmung) oder mit 12 ungleich grossen Halbtonschritten (ungleichstufige Stimmung) zu durchlaufen.
Die wichtigste ungleichstufige Stimmung ist die reine Stimmung. Wie die nachfolgende Tabelle zeigt, stehen die 12 Halbtöne einer Oktave in einem festen Frequenzverhältnis zum Grundton (f0). Die Frequenz des n-ten Halbtons wird mit fn bezeichnet.
Frequenz des Halbtons | Tonschritt |
f0 = 1 * f0 | Prim |
f1 = 16/15 * f0 | |
f2 = 9/8 * f0 | Grosse Sekund |
f3 = 6/5 * f0 | Kleine Terz |
f4 = 5/4 * f0 | Grosse Terz |
f5 = 4/3 * f0 | Quarte |
f6 = 45/32 * f0 | |
f7 = 3/2 * f0 | Quinte |
f8 = 8/5 * f0 | |
f9 = 5/3 * f0 | Sext |
f10 = 9/5 * f0 | |
f11 = 15/8 * f0 | Sept |
f12 = 2 * f0 | Oktave |
Bei Verwendung von Noten lassen sich folgende Frequenzen berechnen:
262 C - "middle C" 277 C# 294 D 311 D# 330 E 349 F 370 F# 392 G 415 G# 440 A 466 A# 494 HUm andere Oktaven zu bilden, einfach immer die höchste Noten-Freqenz mit 1.0595 multiplizieren und runden. Zum Beispiel ergibt sich aus den H oben: 494 * 1.0595 = 523.393, gerundet 523 Hz für das "C", das eine Oktave höher liegt als das "middle C".
Das folgende Programm erzeugt auf dem internen Lautsprecher einen Ton der Frequenz freq [Hz] und der Dauer duration [ms]. Es kehrt nicht sofort zurück, sondern wartet, bis der Ton fertig gespielt wurde.
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Spielen mit dem internen PC-Lautsprecher unter Linux * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Das Programm erzeugt auf dem internen Lautsprecher einen * Ton der Frequenz freq [Hz] und der Dauer duration [ms] * * Aufruf: beep [freq duration] * * Beim Aufruf ohne Parameter wird ein 880-Hz-Ton 100 ms lang erzeugt. * * Wegen des Zugriffs auf /dev/console (wahlweise /dev/tty0) * und der ioctl-Aufrufe kann das Programm nur von root * aufgerufen werden (ggf. mit 'chmod 4711 beep' SUD-root setzen) * Für eine Produktiv-Version sollte noch eine Fehlerbehandlung * hinzugefügt werden. * * JPL 10.11.04 */ #include <sys/types.h> #include <sys/ioctl.h> #include <fcntl.h> #include <linux/kd.h> #include <unistd.h> #include <stdlib.h> int main (int argc, char *argv[]) { int fd; long duration, freq, res; fd = open("/dev/console",O_RDONLY); if (argc > 2) { freq = atoi(argv[1]); duration = atoi(argv[2]); } else { freq = 880; duration = 100; } if (freq > 0) { res = (duration << 16) + (1193180/freq); ioctl(fd,KDMKTONE,res); } usleep(duration*1000); close(fd); return(0); }Nun kann man z.B. ein Shell-Script schreiben, das den Anfang von Beethovens "Für Elise" spielt:
#!/bin/bash beep 659 120 # Treble E beep 0 120 beep 622 120 # Treble D# beep 0 120 beep 659 120 # Treble E beep 0 120 beep 622 120 # Treble D# beep 0 120 beep 659 120 # Treble E beep 0 120 beep 494 120 # Treble B beep 0 120 beep 587 120 # Treble D beep 0 120 beep 523 120 # Treble C beep 0 120 beep 440 120 # Treble A beep 0 140 beep 262 120 # Middle C beep 0 120 beep 330 120 # Treble E beep 0 120 beep 440 120 # Treble A beep 0 120 beep 494 120 # Treble B beep 0 140 beep 330 120 # Treble E beep 0 120 beep 415 120 # Treble G# beep 0 120 beep 494 120 # Treble B beep 0 120 beep 523 120 # Treble C beep 0 140 beep 330 120 # Treble E beep 0 120 beep 659 120 # Treble E beep 0 120 beep 622 120 # Treble D# beep 0 120 beep 659 120 # Treble E beep 0 120 beep 622 120 # Treble D# beep 0 120 beep 659 120 # Treble E beep 0 120 beep 494 120 # Treble B beep 0 120 beep 587 120 # Treble D beep 0 120 beep 523 120 # Treble C beep 0 120 beep 440 120 # Treble A beep 0 140 beep 262 120 # Middle C beep 0 120 beep 330 120 # Treble E beep 0 120 beep 440 120 # Treble A beep 0 120 beep 494 120 # Treble B beep 0 140 beep 330 120 # Treble E beep 0 120 beep 523 120 # Treble C beep 0 120 beep 494 120 # Treble B beep 0 140 beep 440 120 # Treble A"beep" läßt sich sinnvoll beim Betrieb von Servern einsetzen, die normalerweise keine Soundkarte haben - und oft auch keinen Monitor und keine Tastatur.
Falls Sie wirklich Musik machen wollen, dann hilft vielleicht die folgende Frequenztabelle für 7 Oktaven:
C C# D D# E F F# G G# A A# B ------------------------------------------------------------------------ 65, 69, 73, 78, 82, 87, 92, 98, 104, 110, 116, 123, 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 262, 278, 294, 312, 330, 350, 370, 392, 416, 440, 466, 494, 524, 556, 588, 624, 660, 700, 740, 784, 832, 880, 932, 988, 1048, 1112, 1176, 1248, 1320, 1400, 1480, 1568, 1664, 1760, 1864, 1976, 2096, 2224, 2352, 2496, 2640, 2800, 2960, 3136, 3328, 3520, 3728, 3952, 4192, 4448, 4704, 4992, 5280, 5600, 5920, 6272, 6656, 7040, 7456, 7904