Synthesizer Selbstbau im Xilinx-FPGA mit MIDI-Ansteuerung

Falls es interessiert: anbei der Debug-Print meines Synthi, was er empfängt, wenn ich am Arturia den pitchbender einmal von Null auf Maximum und zurück drehe. Man sieht die Sprünge deutlich. Dann nochmal kurz gedreht (siehe ganz unten, zweiter Log), dort sind die Sprünge anders.

Code:
d1=0x00 d2=0x40 pb=0
d1=0x40 d2=0x40 pb=64
d1=0x40 d2=0x41 pb=192
d1=0x6F d2=0x42 pb=367
d1=0x65 d2=0x43 pb=485
d1=0x4A d2=0x44 pb=586
d1=0x10 d2=0x46 pb=784
d1=0x35 d2=0x47 pb=949
d1=0x1F d2=0x48 pb=1055
d1=0x00 d2=0x49 pb=1152
d1=0x00 d2=0x4A pb=1280
d1=0x25 d2=0x4B pb=1445
d1=0x25 d2=0x4C pb=1573
d1=0x0A d2=0x4E pb=1802
d1=0x2F d2=0x4F pb=1967
d1=0x2F d2=0x50 pb=2095
d1=0x5F d2=0x51 pb=2271
d1=0x6F d2=0x52 pb=2415
d1=0x6F d2=0x53 pb=2543
d1=0x50 d2=0x54 pb=2640
d1=0x5F d2=0x55 pb=2783
d1=0x55 d2=0x56 pb=2901
d1=0x4A d2=0x57 pb=3018
d1=0x2F d2=0x58 pb=3119
d1=0x3A d2=0x59 pb=3258
d1=0x00 d2=0x5B pb=3456
d1=0x7A d2=0x5B pb=3578
d1=0x70 d2=0x5C pb=3696
d1=0x55 d2=0x5D pb=3797
d1=0x40 d2=0x5E pb=3904
d1=0x65 d2=0x5F pb=4069
d1=0x1F d2=0x61 pb=4255
d1=0x00 d2=0x62 pb=4352
d1=0x65 d2=0x62 pb=4453
d1=0x65 d2=0x63 pb=4581
d1=0x00 d2=0x65 pb=4736
d1=0x30 d2=0x66 pb=4912
d1=0x3A d2=0x67 pb=5050
d1=0x40 d2=0x68 pb=5184
d1=0x3A d2=0x69 pb=5306
d1=0x40 d2=0x6A pb=5440
d1=0x3A d2=0x6B pb=5562
d1=0x3A d2=0x6C pb=5690
d1=0x40 d2=0x6D pb=5824
d1=0x30 d2=0x6E pb=5936
d1=0x2A d2=0x6F pb=6058
d1=0x15 d2=0x70 pb=6165
d1=0x1F d2=0x71 pb=6303
d1=0x15 d2=0x72 pb=6421
d1=0x15 d2=0x73 pb=6549
d1=0x2A d2=0x74 pb=6698
d1=0x15 d2=0x75 pb=6805
d1=0x45 d2=0x76 pb=6981
d1=0x4F d2=0x77 pb=7119
d1=0x30 d2=0x78 pb=7216
d1=0x15 d2=0x79 pb=7317
d1=0x20 d2=0x7A pb=7456
d1=0x2A d2=0x7B pb=7594
d1=0x0F d2=0x7C pb=7695
d1=0x6A d2=0x7D pb=7914
d1=0x4F d2=0x7E pb=8015
d1=0x30 d2=0x7F pb=8112
d1=0x7F d2=0x7F pb=8191
d1=0x55 d2=0x7F pb=8149
d1=0x3A d2=0x7E pb=7994
d1=0x45 d2=0x7D pb=7877
d1=0x20 d2=0x7C pb=7712
d1=0x30 d2=0x7B pb=7600
d1=0x6A d2=0x79 pb=7402
d1=0x5F d2=0x78 pb=7263
d1=0x70 d2=0x77 pb=7152
d1=0x05 d2=0x77 pb=7045
d1=0x15 d2=0x76 pb=6933
d1=0x30 d2=0x75 pb=6832
d1=0x30 d2=0x74 pb=6704
d1=0x0F d2=0x73 pb=6543
d1=0x0F d2=0x72 pb=6415
d1=0x6A d2=0x70 pb=6250
d1=0x55 d2=0x6F pb=6101
d1=0x4F d2=0x6E pb=5967
d1=0x4F d2=0x6D pb=5839
d1=0x30 d2=0x6C pb=5680
d1=0x7A d2=0x6A pb=5498
d1=0x4F d2=0x69 pb=5327
d1=0x30 d2=0x68 pb=5168
d1=0x65 d2=0x66 pb=4965
d1=0x4F d2=0x65 pb=4815
d1=0x40 d2=0x64 pb=4672
d1=0x70 d2=0x62 pb=4464
d1=0x70 d2=0x61 pb=4336
d1=0x40 d2=0x60 pb=4160
d1=0x30 d2=0x5F pb=4016
d1=0x55 d2=0x5D pb=3797
d1=0x25 d2=0x5C pb=3621
d1=0x65 d2=0x5A pb=3429
d1=0x3A d2=0x59 pb=3258
d1=0x65 d2=0x57 pb=3045
d1=0x25 d2=0x56 pb=2853
d1=0x6F d2=0x54 pb=2671
d1=0x40 d2=0x53 pb=2496
d1=0x5F d2=0x51 pb=2271
d1=0x5F d2=0x50 pb=2143
d1=0x0A d2=0x4F pb=1930
d1=0x35 d2=0x4D pb=1717
d1=0x65 d2=0x4B pb=1509
d1=0x40 d2=0x4A pb=1344
d1=0x00 d2=0x49 pb=1152
d1=0x4A d2=0x47 pb=970
d1=0x35 d2=0x46 pb=821
d1=0x6F d2=0x44 pb=623
d1=0x35 d2=0x43 pb=437
d1=0x00 d2=0x42 pb=256
d1=0x50 d2=0x40 pb=80
d1=0x00 d2=0x40 pb=0

Code:
d1=0x00 d2=0x40 pb=0
d1=0x5A d2=0x40 pb=90
d1=0x4A d2=0x41 pb=202
d1=0x2F d2=0x42 pb=303
d1=0x1A d2=0x43 pb=410
d1=0x00 d2=0x44 pb=512
d1=0x65 d2=0x44 pb=613
d1=0x50 d2=0x45 pb=720
d1=0x35 d2=0x46 pb=821
d1=0x1F d2=0x47 pb=927
d1=0x35 d2=0x46 pb=821
d1=0x4A d2=0x45 pb=714
d1=0x65 d2=0x44 pb=613
d1=0x75 d2=0x43 pb=501
d1=0x0A d2=0x43 pb=394
d1=0x25 d2=0x42 pb=293
d1=0x35 d2=0x41 pb=181
d1=0x4A d2=0x40 pb=74
d1=0x00 d2=0x40 pb=0
 
Also ne Glaskugel, um in die Zukunft zu schauen, hab ich noch nicht in VHDL auf Github gefunden ;-)

Dann guck in die Vergangenheit und interpoliere zwischen letztem und aktuellen Wert.

Die Sprünge sind normal, auch bei 16384 Auflösungswerten. Denn es wird nicht jeder einzelne Zwischenschritt gesendet, wenn Du im Extremfall von -8192 nach +8191 wanderst. Das macht sich bei schneller Wheelbewegung und / oder hohem pitch amount als Quantisierung bemerkbar.
 
Dann guck in die Vergangenheit und interpoliere zwischen letztem und aktuellen Wert.

Ist mir schon klar wie das geht, Menno. Dir ist schon klar, daß man dann den letzten genauen Wert damit verliert, wenn man nicht einen Zeitschritt künstlich dranzaubern will??



Wie ich schon schrieb, kommen die Sprünge auch, wenn ich gaaanz langsam (also wirklich gaaaaaanz langsam, und nur einen Schritt) den Pitchbender quasi nur "anpuste". Der kleinste von Null verschiedene Wert, den ich je hinbekommen habe, ist 10.
 
Ja, weil das Rad das eben nicht so fein umsetzt. Vielleicht ginge es, wenn das Pitchwheel zehnmal so groß wäre...

Ich kenn das Problem aber auch. Und selbst wenn Du ein Wheel hättest, dass so fein agieren würde: Der nächste hat sowas vielleicht nicht und dann hat der wieder das Problem mit den Steps.

Daher habe ich sowas durch Interpolation geglättet. Ein Lowpass ist da einfach, aber sehr unflexibel. Besser geht es mit einem linearen Interpolator über x Samples (eine halbe Millisekunde oder so sollte schon helfen, da muss man etwas nach Gehör und Feeling feintunen). Und immer wenn ein neuer Wert empfangen wurde:

  1. den letzten Interpolationswert als Start
  2. den empfangen Wert als Ziel und
  3. die Interpolationskoeffizienten wieder auf 0

setzen. So wird man auch unterschiedlicher Geschwindigkeit bei der Wheelbewegung gerecht, ohne dass das hörbar hinterherhinkt oder weiter steppt.
 
Ja, weil das Rad das eben nicht so fein umsetzt. Vielleicht ginge es, wenn das Pitchwheel zehnmal so groß wäre...
Ja genau, kleb doch mal einen Verlängerungsarm ans Rad. ;-) Dann sieht man recht schnell, ob es die zu kutze Weg oder die Auflösung ist.

Übrigens: geiles Projekt!
 
Ich kann mir sehr gut vorstellen das das Arturia Keyboard nur einen 10 oder 12 bit ADC hat um den Pitchbend-Poti auszulesen, das wird dann auf die 14 MIDI-PB bits hochskaliert und dabei entstehen ggf ungenauigkeiten/schwankungen. Dazu kommt ja auch noch normale Fluktiation bei solchen guenstigen/einfachen ADCs.

Zur Range: Als mindestes sollte es mMn die optionen +/-2 und +/-12 geben. Idealerweise bis zu +/-24 in halbtoenen einstellbar. Asymmetrisch halt ich fuer einen sehr speziellen Fall.
 
Ich hab jetzt ein Video hochgeladen, welches die Verwendung des Displays demonstriert, bevor ich den Synthesizer reingebaut habe:

RGB-LED-Matrix Spektrum-Analyzer

Leider geht nicht beides (Spektrum-Analyzer und Synthesizer) gleichzeitig. Dazu sind die Ressourcen im FPGA zu knapp.

BTW @einseinsnull: Da gibts n bissle "Signalprocessing" mit MAC-FIR-Filter, Fensterfunktion ("Von-Hann"), 1024-Taps-FFT, Interpolation ;-)
 
FIR und FFT sind dann nach einem chamberlin dann das zweit- und drittschlimmste, vor allem für synthesizer. ;-)

aber dieser hinweis auf die begrenzte rechenleistung, der gar nicht für mich gedacht war, klärt mich vermutlich gerade darüber auf warum auf deiner seite solche entscheidungen getroffen wurden.

leider ist hardwareprogrammierung so überhaupt nicht mein ding, ich brauch immer was graphisches, sonst verlaufe ich mich. ansonsten wäre mir so eine maschine sehr willkommen, vor allem wenn sie fürs gleiche geld schneller wäre als ein mac oder PC prozessor und mir erlaubt "richtige" hardware "herzustellen".

Der kleinste von Null verschiedene Wert, den ich je hinbekommen habe, ist 10.

wenn die mechanik eines solchen rades tatsächlich 16300 werte erzeugen könnte würde mich das sehr wundern.

und es würde auch kaum was helfen, sobald der user das rad bewegt, weil du sicherlich nicht mehr als 5-10 kbit/s erzeugen willst, vor allem wenn es auch noch ein modrad gibt. :)

aber sind es denn wenigstens immer die gleichen werte?


die midi daten zu interpolieren, das ist übrigens total in ordnung, das macht man eigentlich auf allen plattformen und immer so - also... bei den stellen, bei dem man das für seine signale braucht, damit nix knackst.

dabei kann man dann ja auch wieder kompromisse machen und das erst mal mit einer niedrigeren rate machen, bevor man es an seine zielorte schickt.
 
Zuletzt bearbeitet:
Hallo DISc

In meinem DIY Synth auf Basis eines Teensy Chips habe ich das so gelöst..

C:
//*************************************************************************
// Update PitchBend
//*************************************************************************

float PitchWheelAmt = 1.0;
int pitchBendRange = 12;
const static  float  DIV12 = 1.0f / 12.0f;
const static  float  DIV8192 = 1.0f / 8192.0f;

FLASHMEM void myPitchBend(byte channel, int bend) {   // channel & bend comes from midi controller
    bend = (bend * PitchWheelAmt);
    pitchBend.amplitude(bend * 0.5f * pitchBendRange * DIV12 * DIV8192); //)0.5 to give 1oct max - spread of mod is 2oct
}
 
Zuletzt bearbeitet:
Hallo Rolf,

nur mal ein kleiner Hinweis zu dem Code: Sowohl DIV12 als auch DIV8192, und auch die 0.5f (würde ich so als Magic Number auch nicht stehen lassen wollen) sind Konstanten, die kannst du auch über dem Funktionscode in einem Zwischenschritt zusammenfassen und sparst einige Zyklen.
 
Hallo Rolf,

nur mal ein kleiner Hinweis zu dem Code: Sowohl DIV12 als auch DIV8192, und auch die 0.5f (würde ich so als Magic Number auch nicht stehen lassen wollen) sind Konstanten, die kannst du auch über dem Funktionscode in einem Zwischenschritt zusammenfassen und sparst einige Zyklen.

Ein Compiler macht das selber, wenn Optimierungen aktiv sind. Ich würde das ggf. nur in

C:
bend * pitchBendRange * 0.5f * DIV12 * DIV8192

ändern, damit die Konstanten zusammengefasst sind und es für den Compiler einfacher wird. Das alles ist idR. aber eh nicht der der rechenintensive Teil, sondern wird - je nach Implementation - nur ausgeführt, wenn alle Jubeljahre mal ein Pitchbend kommt (kann man ja anhand der maximalen Übetragungsgeschwindigkeit von Midi abschätzen). Insofern dürfte das jetzt nicht so dramatisch sein. Sag ich mal so als Laie... ;-)
 
Ja klar, es ist ja auch genug Speicher vorhanden, warum also auf Kleinigkeiten achten? So fangen die Hauptübel an, falls du verstehst, was ich meine.

Ein Compiler macht es, vorausgesetzt ... Wenn du es selbst machst, dann gibt es keine Bedingungen. Sage ich mal mit mehreren Jahrzehnten Erfahrung.
 
Ja klar, es ist ja auch genug Speicher vorhanden, warum also auf Kleinigkeiten achten? So fangen die Hauptübel an, falls du verstehst, was ich meine.

In der Ausbildung hab ich das (zu MSDOS Zeiten) in der Tat auch noch gelernt: effizienten Code händisch schreiben. Nach der Ausbildung hat man mir das gleich als erstes abgewöhnt. :D
 
Kauf dir mal ein gutes Buch über Steve Wozniak, dann erfährst du, warum gerade die Kleinigkeiten wichtig sind. ;-)
 
Ach ja, Woz ... dessen Codes oft kaum noch lesbar waren. Aber gut, das driftet hier alles komplett vom Thema ab ... ggf. an anderer Stelle passender.
 
Ja gut, wenn du ne Floatingpoint-Recheneinheit hast, kannst du das sicherlich so machen. Wenn ich in meinem Microblaze C-Code z.B. bei der Frequenzdivision oder beim Antialiasing der Samples "unüberlegte" Divisionen in den Code schreibe, braucht der Microblaze so viele Rechenzyklen, daß es Audio-Unterbrechungen gibt, weil die Sample-Warteschlange zum Audiointerface leerläuft. Die Warteschange hat nur Platz für maximal 16 Samples, und bei einer Samplerate von 48 kHz muß man ein gutes Zeitmanagement haben damit das klappt.

Ich muß Divisionen möglichst mit Bit-Shifts realisieren, das geht super schnell. Außerdem mache ich diese Berechnungen in Hardware, da wären Floatingpoint-Operationen auch "Zyklenfresser".

1. Beispiel:

Frequenzteiler für Transponierung: das geht noch meist gut, da man durch zwei oder durch vier usw. teilen kann, das sind simple Shift-Operationen.
Da ich aber auch Frequenzteiler für Subharmonische und auch krumme Zwischenschritte haben wollte, gibts bei Teilern /3, /5, /6, /7, /9 usw. und sowieso bei allen krummen Teilern Probleme. Lösen kann man das bspw. so:

f(sub) = f(0) * 341 / 1024

Multiplikationen sind kein Problem, und /1024 ist wieder ein Bitshift. Ergebnis ist eine Division /3 in zwei Takten (für maximal 18 Bits * 18 Bits) mit einer m.E. hinreichenden Genauigkeit. Die anderen Teiler bekommt man auf die gleiche Weise und alle mit derselben Geschwindigkeit hin.

2. Beispiel:
Mein Synth rechnet intern mit einer Bitbreite von 20 Bits und einer Samplerate von 96 kHz, das Audiointerface läuft mit 18 Bits und 48 kHz, und ich wollte a) nicht einfach zwei Bits und jeden zweiten Sample wegwerfen und b) Antialiasing machen.
Perfekt wäre z.B. immer jeweils vier aufeinanderfolgende Samples gleitend zu addieren und dann durch 16 zu teilen. Rechnerisch kein Problem (/16 geht mit Shift-Operation). Damit sind bis 24 kHz auflösbar (braucht man nicht). Das Ergebnis ist aber unbefriedigend, man hört und sieht im Ergebnis immer noch Aliasing-Artefakte.
Also dachte ich, nehme ich jeweils 6 aufeinanderfolgende Samples und teile /24 (mit "normaler" Division). Als Ergebnis kommt man bis 16 kHz, aber es ist die Hölle, da der Prozessor zu viel Rechenzeit braucht und somit Samples verliert (s.o.).
Ungeliebte Lösung: ich addiere immer jeweils 8 aufeinanderfolgende Samples und teile dann durch 32, das geht wieder mit Shift-Operationen und rechnet schnell. Jetzt sind jedoch nur noch Frequenzen bis 12 kHz auflösbar, aber empirisch (nicht-audiophile Hörprobe ;-) ) ist das beste von allen: keine Artefakte und die hohen Töne werden kaum beschnitten. In einem Alter hört man so hohe Freuqnzen eh nicht mehr :D

Beim Berechnen der Frequenzen bei Pitchbending geh ich genauso vor und es funktioniert auch hinreichend gut (Pitchbend-Range ist mittlerweile dynamisch konfigurierbar bis maximal +-24 Semitones).


BTW Ich hab auch schon überlegt, mal auf neuere Hardware umzusteigen um die diversen durch Ressourcenknappheiten auferlegten Grenzen zu umgehen. Aber dann müsste ich ja alles neu bauen.... :eek:

Mittlerweile kann mein Synthi auch 12-stimmig, dann jedoch nur ein Oscillator pro Stimme und die Filter (jetzt maximal 4) sind dann hinterm Mixer für das Summensignal.

Nächstes Projekt ist ein MIDI-triggerbarer Sample-Player ("Rompler"?) mit dem zweiten ungenutzt rumliegenden Board (Xiling ML403 mit PowerPC-Core im FPGA).

Grüße,
Dirk
 
Zuletzt bearbeitet:
Mal ein kleiner Bericht zu neusten Entwicklung: da ich mir jetzt einen Sequencer (Arturia KeyStep Pro) gekauft habe, wurden einige kleine Anpassungen an meinem Synthesizer erforderlich. Hauptsächlich um z.B. Parameter, die ich bisher mit relativen CC-Botschaften gesteuert habe, nun (auch) mit absoluten Botschaften zu steuern oder die Chorus- oder Reverb-Stärke mit dem Modulator-Strip zu steuern.
BTW Der neue 12-stimmige Modus macht sich super mit dem KeyStep Pro.

Nun ist auch die vage Idee, noch etwas aus meinem zweiten FPGA-Board (ML403 mit PowerPC-Core) zu machen, aktuell geworden. Ich hab einen "Rompler" gebaut, der Samples (Wave-Dateien auf einer CF-Karte) per Trigger abspielen kann. Manuell kann ich es schon ordentlich krachen lassen :) . Da fehlt jetzt nur noch die MIDI-Anbindung. Viel geht auf dem Board allerdings nicht, ich habe nur wenig Logik und noch weniger Programmspeicher (hier nur 64kB) zur Verfügung. Ich hoffe, ich bekomme 24 Drum-Kanäle hin (genau diese Anzahl kann der KeyStep Pro polyphon triggern). Wie weit ich dann mit Hüllkurven-Forming oder gar Pichting komme, bleibt noch abzuwarten.
 
So, hab in der letzten Nacht noch das MIDI-Hardware-Interface drangebrutzelt und den MIDI-Decoder ins FPGA eingebaut und heute ein paar Steps gedrückt.

Nun dachte ich, so ein PowerPC-Core mit 300 MHz (3x so schnell wie der MicroBlaze auf dem anderen "Synthesizer"-Board) kann mehr, aber wenn er mehr als 3 getriggerte Spuren gleichzeitig abspielen soll, dann reicht die Rechenzeit wiederum nicht und es kommt zu unschönen Sample-Verlusten. :eek:

Aber: im Prinzip funktioniert es und Gate-Länge und Velocity werden auch schon adäquat verarbeitet :)


Edit:

Das erste Video zeigte gar nicht die Hardware selbst, daher wieder gelöscht und ersetzt durch dieses Video.
 
Zuletzt bearbeitet:
Hallo DiSc..

Dein Synth muss ja kein Sequenzer werden. Letztendlich entscheidet der Klang und der ist schon sehr gut 👍 In meiner Jeannie (CPU: Teensy 4.1 600MHz) hab ich auch nur einen einspurigen Stepper eingebaut. Klingt super..

 
Zuletzt bearbeitet:
Einen einfachen Sequencer hab ich ja auch drin, denn der Synth muß ja einen Intro-Jingle spielen können ;-) Der Sequencer ist ganz simpel, kann nur 10 Schritte und auch nur maximal 3 Noten polyphon, dafür kann er aber auch Arpeggiator mit diversen lustigen Modi :frolic:

Und für den Spieltrieb hab ich erstmal den KeyStep Pro angeschafft, um die Zeit zu überbrücken, die ich brauche um zu überlegen ob ich aus einem dritten FPGA-Board noch einen Sequenzer bauen soll. Jedoch hätte ich dann ja das Problem der Bedienung (viele Taster, Schalter, LEDs, siehe MIDIBox Seq 4 usw.) und da hab ich glaub ich keinen Nerv dazu. Der KeyStep Pro ist erstmal gut geeignet um das Geklimper in eine Ordnung zu bringen :D

Den (ersten) Synthesizer (der im ersten FPGA-Board und mit dem Punktmatrix-Display), die Drum-Machine (Rompler im zweiten FPGA-Board), den MIDI-Contoller (Arturia KeyLab MKII) und den Sequencer (KeyStep Pro) hab ich jetzt alle per MIDI-Merger zusammengeschaltet, das gibt ne schöne Spiel-Landschaft.
 
Nunja, wovon genau willst du ein Video sehen? Einiges von dem wenigen was man da sehen könnte ist schon in den vorher geposteten Video(s) / Bildern zu sehen:

Die Hardware (FPGA-Eval-Board) ist mehr oder weniger dieselbe wie in diesem Video vom 2. Projekt ganz am Anfang zu sehen.
Das selbstgebaute MIDI-Interface, welches dort ab ca. 0:25 zu erkennen ist, ist im Prinzip auch das gleiche wie ich vorher auch schon im Synthesizer eingebaut habe, nur ist dort die Form der Platine anders. Die Schaltung ist öffentlich im Internetz (siehe z.B. Beschreibung hier, Schaltung hier) bzw. in den Applikationsblättern der Optokoppler verfügbar.
Das FPGA-Board ist eingebaut in ein RGB-Dotmatrix-Display, wie hier und hier zu sehen (später kam noch ne Frontplatte dazu und hinten auch noch ne Blende, daher sieht man dann vom Board so gut wie gar nichts mehr).

Der Rest ist gekaufte Hardware (MIDI-Controller) und Kabel usw.
 
Mein Synthesizer hat mittlerweile einige interessante Erweiterungen und Verbesserungen erhalten, die ich hiermit ergänzen möchte:

1. Vierter Filter
Dieser wird hauptsächlich als Lowpass-Filter im Feedback-Pfad des Reverb-Effekts eingesetzt, aber auch im Paraphon-Modus zusammen mit Filter 3 als zweites Filter-Paar (in Serie oder parallel zum ersten Paar).

2. Envelope-Kurven werden jetzt berechnet (statt wie vorher aus Tabellen erzeugt zu werden)
Der Wert einer Hüllkurve im Verlauf der Zeit wird schrittweise berechnet, jeder Schritt neu unter Einfluß von Parametern wie Rest-Zeit, aktuell verbleibender Abstand zum Level-Zielwert, "Aggressivität", maximale Steigung (welche ihrerseits z.B. wieder abhängen können von Velocity, Aftertouch...). Hiermit wird ein Hüllkurvenverlauf erreicht, welcher der "analogen" Realität näherkommt. Ein entscheidender Effekt ist, daß die Hüllkurve beim Start einer neuen Phase nicht mit Steigung Null beginnt (wie vorher), sondern die Steigung einer ggf. noch aktiven Phase "mitnimmt" und schrittweise anpasst (z.B. wenn in der Release-Phase neu getriggert wird, sichtbar am Anfang der Kurve in Screenshot 3). Es gibt also keine aprupten Steigungsänderungen mehr.
Die Attack- oder Release-Velocity bestimmt dabei maßgeblich den dynamischen Verlauf der Hüllkurve, bei hoher Velocity sind sogar Überschwinger möglich ;-) (siehe Screenshots aus Excel-Diagramm: Nr1 flacher Verlauf bei Velocity=64, Nr2 steiler Verlauf bei Velocity=120, Nr3 wie Nr1 aber mit Retrigger aus noch aktiver Release-Phase).
Neu ist auch die Option, die Hüllkurve adaptiv früher zu beenden, wenn der Zielwert erreicht wurde z.B. bei hohen Velocity-Werten oder beim Retrigger-Fall. Dies würde, wenn aktiviert, z.B. bei Bild 2 nach ca. 1/3 der Zeit eintreten, ist hier bei der Excel-Berechnung jedoch nicht berücksichtigt (daher der lange statische Verlauf in der Mitte).

3. Sub-Oscillator für jeden Oscillator
Mit diesem wird jeweils phasenstarr zum zugeordneten Oscillator eine Sägezahn- oder Rechteck-Welle mit gleicher Frequenz oder eine oder zwei Oktaven tiefer erzeugt und variabel beigemischt.

4. Weitere Waveforming-Optionen
BitInverter: hiermit lässt sich z.B. eine steigende Sägezahnschwingung effektvoll in eine fallende Sägezahnschwingung überblenden
BitCrusher: experimentell.... wird m.E. überbewertet.
Option "x * abs(x)".... wie soll man es beschreiben.... am Beispiel von Sinus siehe 5. Screenshot. Gibt mehr Dynamik und Nulldurchgänge mit Steigung Null (experimentell für Modulationseffekte).

5. Oscillator-Phasenreset gesteuert durch Envelope-Trigger
Hierbei können die beteiligten Oscillatoren beim Anschlag (Envelope-Attack) bei Phase Null gestartet werden. Bedeutend wird dies z.B. bei langsamlaufenden LFOs als Modulationsquelle, die hiermit immer zur gleichen Phase beim Anschlagen starten (das hat mich bisher immer genervt daß man bei bisher freilaufendem LFO immer irgendwo mittendrin trifft).

6. SuperSaw-Optionen
Ich beschäftige mich ja, wie auch Rolf Degen mit seiner Jeannie, seit einiger Zeit mit den Möglichkeiten zur Erzeugung von SuperSaw-Sounds. Interessant hierbei auch die Eigenheiten bei digitaler Klangerzeugung (hier per DDS = Direct Digital Synthesis), vor allem im Zusammenhang mit Punkt 5:
Bei freilaufenden Oscillatoren "trifft" man beim Anschlag immer an eine zufällige Stelle der Wellenform. Lässt man die Oscillatoren jedoch beim Anschlag alle synchron bei Phase Null starten, bekommt man sehr interessante Sound-Effekte bei aktivem DeTune (für SuperSaw). Hörbeispiel hängt an (zuerst gänzlich ohne Filter, dann mit Filter), in der Waveform sieht man auch den synchronen Start und die fortlaufende Verstimmung. Die Stärke dieses Effekts lässt sich wiederum über kontrolliertes "DePhasing" beinflussen.
@Rolf Degen: solltest du mit deiner Jeannie auch mal versuchen :)

7. Multichannel-Option
Im Unison-SuperSaw-Modus mit DeTune werden die 12 verstimmten Oscillatoren abwechselnd auf die beiden Stereo-Kanäle verteilt.


BTW Es gibt immer noch niemanden der das Ding ernsthaft spielen könnte, also es ist ein reines Bastlerprojekt ;-)

Grüße,
Dirk
 

Anhänge

  • envgen-evo-env-v64.PNG
    envgen-evo-env-v64.PNG
    42,4 KB · Aufrufe: 9
  • envgen-evo-env-v120.PNG
    envgen-evo-env-v120.PNG
    42,8 KB · Aufrufe: 9
  • envgen-evo-env-retrigger.PNG
    envgen-evo-env-retrigger.PNG
    44,2 KB · Aufrufe: 9
  • capture-samples-029-PolySimple-DeTune-v1-20b.mp3
    1,1 MB
  • Poly-Simple-SuperSaw.png
    Poly-Simple-SuperSaw.png
    36,3 KB · Aufrufe: 10
  • sqwave-sinus.PNG
    sqwave-sinus.PNG
    27,4 KB · Aufrufe: 9
Mein Synthi hat wieder mal Erweiterungen erhalten:
Abgesehen von neuen experimentellen FM-Varianten (FM durch exponentielle Phasenmodulation, Ramp-FM und Ringmodulated-FM) werden jetzt die Sinus/Cosinus-Samples aus einem RAM ausgelesen und vom selben Generator (DDS) angesteuert wie die anderen Waveforms (vorher war dies ein vorkonfigurierter IP-Core mit Samples im ROM).
Interessanter Nebeneffekt und BTW die eigentliche Erweiterung:
Da ich nun auch andere Waveforms in diesem RAM ablegen kann, habe ich nun ganz nebenbei einen einfachen Wavetable-Synthesizer. Zur Zeit kann er aber nur 32 Tabellen mit jeweils 1024 Samples.
Tabelle #0 enthält die Standard-Cosinus-Welle (die ich per Default immer drinlasse, da diese benötigt wird für die LFOs im Stringmodus und für die Amplitudenmodulation im Ramp-FM-Modus.
Tabelle #1 bekommt erstmal eine bandbreitenlimitierte Dreieck-Waveform und
Tabelle #2 bekommt eine bandbreitenlimitierte Rechteck-Waveform (50:50).

Frage an die Schwarmintelligenz und vielleicht auch an @rolfdegen im Speziellen:
Habt ihr schonmal bandbreitenlimitierte Waveforms selbst erstellt? Bis zu wieviel Harmonischen Anteilen kann man da gehen? Oder ist das empirisch?
Meine Dreieck-Waveform geht erstmal bis zur 23. und die Rechteckwaveform bis zur 31. Harmonischen (siehe Screenshots vom Excel, mit dem ich die erzeugt habe).
bl-tri-v1.PNG
bl-rect-v1.PNG

Grüße,
Dirk
 


Zurück
Oben