Arduino-Synthesizer mit FM: 3 Schritte - 2020 - How ToDo Well

Arduino-Synthesizer mit FM: 3 Schritte - 2020 - How ToDo Well

Inhaltsverzeichnis:

Anonim

Benötigtes Material

  • ein Arduino Uno oder Klon
  • ein 830-Loch-Steckbrett
  • 19 4-polige Mikrotaster
  • ein 100muF Elektrolytkondensator
  • ein 10 kOhm Potentiometer
  • eine 3,5-mm-Kopfhörerbuchse
  • ~ 50 cm einadriges Anschlusskabel
  • 21 Überbrückungsdrähte (14 lang und 7 kurz)

Verdrahten Sie alle Komponenten gemäß dem angegebenen Schaltplan. Es ist ein ziemlicher Aufwand, die gesamte Verkabelung in Betrieb zu nehmen. Es ist daher sinnvoll, zunächst nur den Audiokreis und eine Taste anzuschließen und die Software hochzuladen. Wenn das funktioniert, können Sie nach und nach alle anderen Schaltflächen hinzufügen. Stellen Sie für den Elektrolytkondensator sicher, dass der positive Anschluss mit der Arduino-Seite und der negative Anschluss mit dem Potentiometer verbunden sind. Die kurzen Verbindungen innerhalb des Steckbretts werden am besten mit kurzen Stücken eines massiven Anschlusskabels hergestellt, die längeren Verbindungen zum Arduino besser mit flexiblen Überbrückungskabeln.

Beachten Sie, dass die Tasten an jeden Pin angeschlossen werden können. Mit der Software ist es möglich, jeder Note eine beliebige Taste zuzuweisen. Die einzige Ausnahme ist Pin D9, an dem das Audiosignal erzeugt wird. Es darf nicht als Tasteneingang verwendet werden.

Laden Sie die Arduino-Skizze vom nächsten Schritt an und Sie können mit dem Spielen beginnen.

Die Tasten spielen die Noten C4-F5 und die Taste ganz rechts ändert das Instrument. Die Zeit, zu der eine Taste gedrückt wird, ändert die Länge einer Note. Da es sich jedoch um einfache digitale Drucktasten handelt, kann die Lautstärke des Tons nicht durch die Geschwindigkeit oder Kraft beeinflusst werden, mit der die Tasten gedrückt werden.

Schließen Sie einen Stereo-Kopfhörer an die 3,5-mm-Buchse an und mit dem Potentiometer kann die Lautstärke reguliert werden.

Um den Ton über einen Lautsprecher zu hören, muss er verstärkt werden. Jeder Verstärker, der für die Aufnahme von Kopfhörern ausgelegt ist, funktioniert. Alternativ sollte eine billige Verstärkermodulbasis auf dem LM386 oder PAM8403 ausreichen, um die Lautstärke zu erhöhen.

Schritt 2: Code

Laden Sie den Anhang mit der Arduino IDE hoch. Ich habe Version 1.8.7 verwendet, aber es wurde nichts Besonderes verwendet, sodass ich davon ausgehe, dass es mit den meisten früheren und zukünftigen IDEs gut funktioniert. Darüber hinaus werden keine externen Bibliotheken verwendet.

Nach dem Schritt "Bestätigen" wird Folgendes angezeigt:

Sketch belegt 11630 Bytes (36%) des Programmspeicherplatzes. Maximal sind 32256 Bytes möglich. Globale Variablen belegen 757 Byte (36%) des dynamischen Speichers, während lokale Variablen 1291 Byte belassen. Maximal sind 2048 Bytes möglich.

Es ist also weit davon entfernt, den 2kB RAM, 32kB Flash des Arduino Uno, zu erschöpfen.

Gerätedefinitionen

Jedes Instrument wird durch 10 Parameter definiert. Um neue Sounds zu entdecken, ist es wichtig, deren Bedeutung zu verstehen und die Grundlagen der ADSR-Hüllkurven und der FM-Klangsynthese zu verstehen.

ldness: lautheit

Wenn Sie diesen Wert bei 64 oder darunter halten, wird sichergestellt, dass der Ausgang nicht überläuft und schreckliche Verzerrungen erzeugt. Aber für Klänge, die nur sehr kurz mit maximaler Amplitude bleiben, ist es in Ordnung, höher zu gehen, da es unwahrscheinlich ist, dass alle 4 Stimmen mit maximaler Amplitude vorliegen.

pitch0: Tonhöhenversatz

Wenn Sie diesen Wert auf 12 einstellen, wird eine normale Konfiguration angezeigt, bei der die Tonhöhe der Taste ganz links der Tonhöhe des C4 entspricht. Das Setzen auf 0 führt zu einer Verschiebung um eine volle Oktave nach unten, während der Wert 24 zu einer vollen Oktave nach oben führt.

ADSR_a: Angriffsparameter

Geschwindigkeit, mit der der Ton von 0 auf max. Eine kleine Zahl hier bedeutet, dass der Ton sehr langsam beginnt. Beispiel: ADSR_a = 8192 benötigt 4ms, um auf max. ADSR_a = 256 benötigt 128 ms, um auf max

ADSR_d: Decay-Parameter

Geschwindigkeit, mit der der Ton von max auf Sustain abfällt. Eine kleine Zahl bedeutet hier, dass der Ton sehr langsam abfällt. Beispiel: ADSR_d = 8192 benötigt 4 ms, um von max auf 0 abzuklingen. ADSR_d = 256 benötigt 128 ms, um von max auf 0 abzuklingen. Wenn Sustain von 0 abweicht, dauert es tatsächlich weniger, um den Sustain-Wert zu erreichen.

ADSR_s: Sustain-Parameter

Relative Lautstärke des Tons, wenn die Taste gedrückt bleibt. ADSR_s = 255 bedeutet, dass die maximale Lautstärke erreicht wird. ADSR_s = 192 bedeutet, dass es bei 80% des maximalen Volumens bleibt. ADSR_s = 0 bedeutet, dass der Ton ausfällt, auch wenn die Taste gedrückt bleibt.

ADSR_r: Freigabeparameter

Geschwindigkeit, mit der der Ton nach dem Loslassen nachlässt. Eine kleine Zahl bedeutet, dass der Ton nach dem Loslassen der Taste noch lange anhält. Beispiel: Es dauert 4 ms, bis ADSR_r = 8192 von max auf 0 abfällt. ADSR_r = 256 benötigt 128 ms, um von max auf 0 abzuklingen. Wenn der Ton zum Zeitpunkt der Freigabe bereits unter dem Maximum war, dauert es weniger Zeit, um zu sterben.

FM_inc: FM Frequenz bezüglich Tonhöhe

Das Verhältnis der Modulationsfrequenz zur Tonhöhe FM_inc = 256 entspricht einer Modulationsfrequenz, die der Tonhöhe entspricht, was zu reinen Harmonischen führt, die ein Vielfaches der Tonhöhenfrequenz sind. FM_inc = 512, 768 oder 1024 entspricht einer Modulationsfrequenz, die das 2,3- oder 4-fache der Tonhöhe beträgt, was zu reinen Harmonischen führt, die ein Vielfaches der Tonhöhenfrequenz sind, jedoch bei höheren Frequenzen eine stärkere Betonung aufweisen. FM_inc = 128 entspricht einer Modulationsfrequenz, die der Tonhälfte entspricht, was zu halbreinen Harmonischen führt, die ein Vielfaches der halben Tonhöhenfrequenz sind, wodurch auch Untertöne erzeugt werden. FM_inc = 384,640,896 entspricht einer Modulationsfrequenz von 1,5, 2,5 oder 3,5 mal der Tonhöhe, was zu halbreinen Harmonischen führt, die ein Vielfaches der halben Tonhöhenfrequenz sind, wodurch auch Untertöne erzeugt werden, jedoch mit größerer Betonung bei den höheren Frequenzen. Jede Zahl für FM_inc, die kein Vielfaches von 64 ist, führt zu einem harmonischen Ton, der typisch für zylindrische Schwingungen ist. Ein Wert von FM-inc, der sich geringfügig von einem Vielfachen von 256 unterscheidet, führt zu Frequenzbändern in unmittelbarer Nähe, die dann zu einem Vibrato-Effekt führen.

FM_a1: FM-Amplitudenstart

Frequenzmodulationsamplitude am Anfang einer Note. FM_a1 = 256 bedeutet, dass am Anfang einer Note Beta = 1 ist, was zu einem reichen Spektrum führt. Eine geringere Anzahl führt zu weniger Seitenbändern und damit zu einer reineren Note. Sehr große Werte wie FM_a1 = 2048 entsprechen Beta = 8 und ergeben ziemlich verrückte Wellenformen, was zu sehr interessanten Klängen führen kann.

FM_a2: FM-Amplitudenende

Frequenzmodulationsamplitude am Ende einer Note. In den meisten Instrumenten dämpfen die hohen Frequenzen schneller als die tiefen Frequenzen, was durch einen abnehmenden Wert der FM-Amplitude oder FM_a2FM_a1 emuliert werden kann.

FM_dec: FM-Zerfall

Die Geschwindigkeit, mit der sich die FM-Amplitude von ihrem Startwert zu ihrem Endwert ändert, wird durch Fm_dec bestimmt. Beachten Sie, dass diese Änderung einem exponentiellen Abfall folgt, so dass der Übergang viel glatter ist als bei der ADSR-Hüllkurve, bei der der Übergang linear ist. FM_dec = 256 bedeutet, dass die Zeitkonstante der Exponentialänderung 128 ms beträgt. Ein niedriger Wert von FM_dec bedeutet, dass sich der Klang ständig ändert. Ein hoher Wert von FM_dec führt zu einer kurzen anfänglichen Änderung, gefolgt von einem schnellen Übergang zu einem stabileren endgültigen Klang.

Schlüssel

Das Arduino uno verfügt über 20 io-Ports. Pin 9 wird für den Audioausgang und ein weiterer Pin für die Instrumentenauswahl benötigt. Ansonsten kann jeder Schlüssel mit jedem I / O-Pin verbunden und die entsprechende Note in der Software definiert werden. Aus Geschwindigkeitsgründen erfolgt der Zugriff auf die Tasten durch direkte Portmanipulation. Innerhalb des Codes werden sie daher als PORTD, PORTB und PORTC aufgerufen. Im Block 'Pin-zu-Schlüssel-Zuordnung' geben die Kommentare im Code jedoch an, welches Bit von welchem ​​Port welchem ​​Arduino-Pin entspricht. Wenn Sie eine Version mit weniger Tasten erstellen, können Sie die nicht instrumentierten Pins hier als "nokey" definieren: Dies führt zu einem kleineren und schnelleren Code und vermeidet unerwünschte Tongenerationen, wenn eine dieser Tasten versehentlich kurzgeschlossen wird. Alle Tasten verwenden die internen Pull-Up-Widerstände, sodass keine zusätzlichen 19 externen Pull-Up-Widerstände erforderlich sind. Die Schlüssel werden nur einmal in jeder Schleife gelesen (einmal alle 0,48 ms), so dass die Auswirkungen des Entprellens ebenfalls sehr begrenzt sind und ich keinen Bedarf an Hard- oder Software-Entprellschutz fand.

Schritt 3: Technische Details

PWM

Die Pulsweitenmodulation ist ein bekanntes Verfahren zur Erzeugung von halbanalogen Signalen. Zum Erstellen von Audiodaten muss die Frequenz deutlich über unserer Hörgrenze liegen. Der Timer ist so eingestellt, dass alle 512 Taktzyklen ein Impuls ausgegeben wird. Da der Arduino mit 16 MHz arbeitet, entspricht dies einer Abtastfrequenz von 31250 Hz, die weit über unserer Hörgrenze liegt. Diese Abtastfrequenz erlaubt es, Töne mit bis zu der Hälfte dieser Frequenz zu erzeugen (gemäß dem Nyquist-Theorem).

Timing ohne Unterbrechungen

Eine Methode, um die Zeit zu verfolgen und die Impulsbreite im richtigen Moment zu aktualisieren, ist die Verwendung von Interrupts. Interrupts haben jedoch einen erheblichen Overhead, weshalb ich mich entschied, das Timing auf die Überprüfung des Timer-Überlaufbits zu stützen. Auf diese Weise wird die verfügbare CPU-Zeit mehr oder weniger gleichmäßig auf die "schnelle Schleife" und die "langsame Schleife" aufgeteilt.

In der schnellen Schleife (setPWM) wird die augenblickliche Pulsbreite für die 4 Stimmen bei jedem Tick des Timers berechnet. Dies darf ~ 250 Zyklen dauern, und es scheint ausreichend zu sein, die 4 Phasen zu aktualisieren, die Frequenzmodulation durchzuführen, die Intensität zu berechnen und die 4 Signale zu addieren. Um dies schnell zu halten, werden nur 8- und 16-Bit-Ganzzahlen verwendet, und die Sinuswerte wurden tabellarisch aufgeführt.

Der Aufruf der schnellen Schleife muss eine Inline-Funktion sein, wobei das Attribut __attribute __ ((always_inline)) verwendet wird. Dies bedeutet, dass der vom Compiler generierte Assemblycode diesen Code bei jedem Aufruf wiederholt. Es nimmt mehr Platz in Anspruch, ist aber schneller.

Der Sinus wird als 8-Bit-Zahl angegeben, aber alle voreingestellten Instrumente verwenden nur ein Viertel des Sinus

In 512 Taktzyklen ist keine Zeit mehr, um alle anderen Funktionen auszuführen, z. B. das Überprüfen der Tasten, das Ändern des Instruments, das Auswählen der Stimme und das Ändern der zeitlichen Entwicklung der Noten, sodass diese Funktionalität in 15 Teile aufgeteilt wird die schnellen Schleifen. Dies ermöglicht einige Zwischenberechnungen mit einer 32-Bit-Genauigkeit, die für die Multiplikation von zwei 16-Bit-Zahlen erforderlich sind. Die vollständige Schleife benötigt 0,48 ms, was für diese Funktionen schnell genug ist.

FM-Synthese

Eine einfache Sinuswelle klingt langweilig, da sie keine höheren Harmonischen hat. Ein rechnerisch effizienter Weg zur Erzeugung komplexer Klänge ist die Frequenzmodulation. Aus praktischen Gründen wird es hier als Phasenmodulation implementiert, aber für sinusförmige Signale sind Phasenmodulation und Frequenzmodulation äquivalent. FM kann neben der Haupttonhöhe ein reiches Spektrum an Seitenbändern erzeugen. Die Modulationsfrequenz bestimmt die Position dieser Seitenbänder und die Amplitude bestimmt deren Intensität. Wenn die Modulationsfrequenz kein einfaches Verhältnis der Tonhöhe ist, ist der resultierende Klang anharmonisch und entspricht dem typischen Klang vibrierender zylindrischer Objekte wie einer Glocke. Echte Musikinstrumente haben ein reiches Spektrum, das sich mit der Zeit ändert, da einige Vibrationen schneller dämpfen als andere.