Datum:
Angehängte Dateien:Hallo Ihr Lieben.. Ich entwickel zur Zeit einen Synthesizer auf Basis eines ATxmega128A1 Prozessors. Falls euch mein Projekt interessiert schaut mal unter http://www.cczwei-forum.de/cc2/thread.php?threadid=5878 vorbei. Da gibts jede Menge an Informationen Rund um die Musikelektronik und auch Programmier-Tips in C, um einen eigenen Synthesizer zu bauen. Viel Spaß beim stöbern wünscht euch Rolf
Datum:
Hallo Rolf, erstmal möchte ich bekunden das du sehr schöne Erklärungen auf der CC2 Seite zu dem Thema gemacht hast. Die anderen Links sind auch sehr schick. Find das immer wieder erstaunlich was man klangtechnisch aus nem AVR holen kann. Dafür das das "nur" nen popeliger 8-bitter ist :-) Werd deinen Beitrag weiterhin verfolgen und bin mal gespannt was du aus dem Xmega rauskitzeln kannst. Ich selbst bin bei meinem Synthesizer (schau mal hier im Forum unter Audio-DSP mit Spartan 3) einen anderen weg gegangen. Da mache ich die Klangerzeugung/Bearbeitung/Filterung in einem FPGA, und gesteuert wird das ganze von einem AVR. In dem Artikel sind auch noch Links zu You-Tube Videos. Das ganze ist allerdings schon was länger existent und liegt momentan auch was rum. Aber evtl überarbeite ich den Synth mal mit einem neueren Spartan. Insgesamt hat man mit der Platform (wenn sie mal fertig bzw dokumentiert wäre) recht viele Möglichkeiten, da ich von vornherein auf der Verarbeitungsebene modular bin. Weiterhin viel Spaß beim Synth-DIYing :-)
Datum:
Hallo Rene Ich habe jetzt die ersten Sounds von meinem Synthi ins Netz gestellt. Kann man sich auf SoundCload unter http://soundcloud.com/rolfdegen/sets/testsounds-av... anhören. Die Sound sind zwar nix Besonderes, weil der Synthi zur Zeit nur ein Oszillator und ein Hüllkurvengenerator besitzt. Aber ich bin gerade dabei, das ganze auf drei Oszilatoren und 3 Hüllkurvengeneratoren auszubauen. In Bezug auf dein Audio-Projekt: Ich habe mir schon vor längerer Zeit dein "Audio-DSP mit Spartan 3" hier auf mikrocontroller.net angesehen bzw angehört und bin von der Soundqualität einfach begeistert. Ist schon eine ganz andere Liga :) Ich habe mir jetzt bei Watterott ein STM32F4 Discovery Board bestellt und bin schon gespannt was das Bord im Audiobereich so alles kann. Die Eckdaten sind vielversprechend zB. 168MHz CPU-Takt, 1 MB Flash, 192 KB RAM, FPU und 24Bit DA-Wandler Chip onBoard. Werde das Board ausführlich testen und vielleicht wird ja ein Wave-2 daraus werden. Schaun wir mal.. Gruß Rolf
Datum:
Hallo Synthbastler :) Ich habe mir auch schon einen Synth mit einem AVR gebastelt, allerdings habe ich dann sehr bald aufgegeben weil mir der Sound nicht gefallen hat. Ich bin halt besseres gewohnt, da ich aus der VST-DSP Ecke komme. Habe mir dann mal ein paar Dev-Boards für schnellere Controller gesucht (PIC32, dsPIC, AVR32...), allerdings bin ich da nicht sonderlich weit gekommen. Der dsPIC ist recht simpel und billig, und man kommt schnell zum DSP-Teil des Projekts, allerings ist er nicht sonderlich schnell. AVR32 ist irgendwie sehr kompliziert, dafür ist er einigermaßen schnell. Gleiches gilt für den PIC32. Rene´s Projekt find ich recht interessant, und ich hatte schon lange vor mal mit FPGAs zu arbeiten, weil damit geht man den Großteil der Geschwindigkeits-Probleme aus dem Weg. Jetzt habe ich wieder etwas mehr Zeit, und wollte das mal angehen. Habe mich schon etwas informiert, und nach Dev-Boards umgesehen. Evtl. werde ich mir ein CycloneII-Board holen, ist zwar nicht mehr der aktuellste, aber das Board hat alles drauf was ich brauche, und eine Synthesizer-Demo wird gleich mitgeliefert. Das einzige was mir da noch etwas Sorgen macht ist: bei der freien Version von Quartus steht "Windows 32bit only", und meine 32-bit Kisten habe ich alle ausgemustert :)
Datum:
@Rolf Also die Sounds klingen schon recht witzig. Old-School-8-Bit-Style :-) Bin mal gespannt auf weitere Demos. Wie willst das denn mit den Filtern machen ? Analoge Filter die digital gesteuert werden ? Oder direkt digitale Filter ? Und danke noch für das Lob :-)) @Maik was würde denn gegen Xilinx sprechen ? Also den Spartan 6 zu routen war sehr angenehm. Mein (noch nicht phsyisch vorhandenes, aber schon teilgeroutetes Test-Board) schaut schon ganz gut aus und hat neben nem Codec, nem AVR noch 16MB SDRAM an dem FPGA angeklebt bekommen. Aus dem Teil ne Platform zu machen ist mittlerweile nen Klacks. Würde das Audio-Projekt ja gerne nochmal reaktiveren (fürs Forum) aber bei der "alten" Version war die Resonanz schon nicht so groß. Wobei das Board als solches vllt noch für den einen oder anderen Interessant sein könnte. Ist auch "relativ" einfach zu Löten (144'er QFP und 0603 SMD auf ner doppelseitigen Platine). Na ja .. mal schauen. Vllt starte ich das Projekt erneut.
Datum:
Rene B. schrieb: > Also die Sounds klingen schon recht witzig. Old-School-8-Bit-Style :-) Hallo Rene. Wenn schon.. denn schon. Es sind 12Bit Sounds :) Gerechnet wird intern mit 16Bit und das Ergebnis wird dann für den Xmega-DAC auf 12Bit reduziert. Eine Filtertechnik habe ich im Moment noch nicht integriert. Es läuft aber mit Sicherheit auf analoge Filter-Bausteine hinaus, weil der Xmega einfach zu wenig Rechengeschwindigkeit besitzt. Der ist schon voll mit der Soundausgabe, Hüllkurve, Midi und Grafischen Touch-Display beschäftigt, da bleibt keine Zeit mehr für eine Filterberechnungen. Allerdings weis ich noch nicht, was ich für Filter-Chips nehmen soll. Hatte Anfang der 90er Jahre mit dem Bau meines 1.Synthesizers von der Firma Doepfer (http://www.doepfer.de/home_d.htm) begonnen und dafür ein paar Curtis IC bestellt. Aber ich war "jung" und habe den Synthi nie fertig gebaut. Und nach den vielen Umzügen sind die Bauteile einfach verschwunden. Hallo Maik. Ich habe mir die Beschreibung des Cyclone II Board mal angesehen. Kann man sich hier herunterladen: http://www.altera.com/products/devkits/altera/kit-... Das Board ist ja ganz schön groß und teuer im Verhältnis zum STM32F4 Discovery Board, hat aber alles was man so brauch für einen Synthi. Für den Anfang bleibe ich erst einmal bei einem kleinen und preisgünstigen Board um damit Erfahrungen zu sammeln. Später trau ich mich dann an die größeren Boards wzB das EVK1104 evaluation Board von Atmel: http://www.atmel.com/tools/EVK1104.aspx und als Entwicklungs-Tool AVR Studio das ich jetzt schon für den Xmega benutze. Gruß Rolf
Datum:
@Rolf und Maik was vllt auch noch als Platform sehr interessant wäre ist der Raspberry PI. Der hat ja nen 700MHz ARM am werkeln. Das sollte für digitale Synthies dicke reichen. Jedenfalls werd ich mich mit der Platform auchmal auseinandersetzen, selbst wenns eben nichts zum nachbauen ist. @Rolf Die Curtis-Chips hätte ich gerne mal in den Fingern. Aber die sind so schwer zu bekommen. Ich glaube da würd ich eher ein diskretes Design (State-variable-Filter, oder den klassischen Moog-Filter) nehmen. Hab damals auch mal nen "klassischen" Filter analog aufgebaut. Aber das ganze ist dann irgendwann liegen geblieben. Würde gerne aber bei meinem Audio-Projekt noch analoge Filter integrieren und mit jeweils nem eigenen Codec versehen. Dann hätte ich die Möglichkeit Signale zu mischen und beliebig zu routen (und eben auch durch den Filter). Wäre für nen Mischpult mit Effektgerät ganz nützlich, oder eben für nen Synthie (selbst wenn der dann nur max x-stimmig werden kann wobei x dann die Anzahl analoger Filter ist). Aber reizvoll sind analoge Synthies allemale. Egal ob mit oder ohne digitale Komponenten.
Datum:
Das "RasPi"-Board hat leider keinen eigenen DA-Wandler onBoard. Der Sound wird per PWM im Prozessor erzeugt und über einen einfachen RC-Filter nach außen geführt. Hier ist der Schaltplan: http://www.raspberrypi.org/wp-content/uploads/2012... Gruß Rolf
Datum:
Na und ? Der hat doch USB-Schnittstellen. Und ne Soundkarte ist doch schnell da dran gekorkt :-) Wobei es mich mal interessieren würde wie schwer bzw unmöglich es ist bzw wäre das Board ohne Linux zu betreiben. Also quasi die gesamte Rechenleistung mit allem drum und dran für sich ganz alleine zu haben :-) Und ich denke von den Schnittstellen her ist es bestimmt möglich auch nen guten Wandler noch dranzuflanschen. Notfalls per FPGA-Daughter Board :-)
Datum:
Hinweis zum "Raspberry Pi". Der Erik Bartmann ist gerade dabei, ein Buch über den RasPi mit dem Titel "Raspberry Pi für Frühaufsteher" zu schreiben. CC2-Link: http://www.cczwei-forum.de/cc2/thread.php?postid=7... Gruß Rolf
Datum:
@Rolf: Ja das Board ist recht teuer im Vergleich zu den Controller-Dev-Boards. Das relativiert sich aber in dem Moment, wo man es mit anderen FPGA-Dev-Boards vergleicht. Auch kostet der FPGA auf dem Board alleine schon mehr als 50 Euro :) Ich habe das EVK1105, ansich ist das nicht schlecht, nur hat das einen PCB-Fehler, was es extrem schwer macht das Teil zu programmieren. Und DFU wird in Atmel Studio 6 nicht mehr unterstützt, deswegen benötigt man ab da auch noch einen JTAG-Programmer. @Rene: Ich habe mir ein paar Xilinx-Boards angeschaut, das günstigste mit Codec was ich gefunden habe ist das Digilent Atlys, was aber schon doppelt soviel kostet wie das CycloneII Dein eigenes Layout ware natürlich optimal, weil das quasi das nötigste enthält. Ich würde gern eins nehmen, allerdings benötige ich es fertig aufgebaut. Da ich am Anfang meine "Lötfehler" als "mögliche Fehlerquelle" ausschließen möchte. Das Pi kommt für mich nicht in Frage. Mein Ziel ist es ein Synthesizer/Effektgerät zu bauen, dh. später möchte ich eine eigene Platine fertigen können.
Datum:
Auf einem AVR ist schon einiges möglich - C, viele Kanäle und komplexe Sounds passen da aber nicht mehr zusammen. Das größte Problem ist die Rechenleistung für die vielen Kanäle. Wenn man 8 Kanäle realisieren möchte hat man bei 44100 Hz @32Mhz 32Mhz : 44100 : 8 = 90 Takte pro Kanal Zeit. In meinem Synthesizerprojekt konnte ich die Takte/Kanal auf ~15 reduzieren, dafür waren keine komplexen Sounds mehr möglich.
Datum:
@Samuel Hast du mal nen Link zu deinem Projekt ? Würd mich mal interessieren. Im Prinzip ist mit den AVRs ja soundtechnisch schon einiges machbar wenn man Kompromisse bei der Samplingrate macht. Aber Filter-Operationen sind halt bei der begrenzten Rechenleistung schwierig. Oder sehr Tricky :-)
Datum:
http://www.mikrocontroller.net/articles/AVR-Synthesizer
add freqcnt1, hrfreq1 ;16-bit Zähler adc freqcnt2, hrfreq2 brcs 1f 4: ;Tonerzeugung ;Im Register ueber freqcnt2 liegt der Index zur richtigen Soundtabelle movw ZL, freqcnt2 lpm temp, Z ;Lautstärke mulsu temp, volsum1 ;mischen add sample, 0 adc sample2, 1 |
Ich habe die Hauptroutine nochmal herausgekramt: Für einen Kanal sind es hier 11 Takte, allerdings kommt noch ein bisschen dazu für Register laden etc. Wenn man so viel optimiert wird irgendwann der Ram zum Flaschenhals mit 2 Zyklen pro Zugriff. Also werden alle Daten von bis zu drei Kanälen geladen und die nächsten 64 Samples werden berechnet.
Datum:
Hallo zusammen Zufällig habe ich auf einer japanischen Website ein interessante FM Sound Programm für das ST32F4 Discovery Board entdeckt. So wie es verstanden habe (mein Japanisch ist nicht besonders gut :), ist das Soundmodul 16stimmig polyphon, Samplingrate 48KHz und Midi fähig. Ich habe die Firmware über ST-Link Utility direkt mal ins Discovery geflasht . Nach dem Reset läuft sofort eine Sounddemo ab. Klingt nicht schlecht wenn ihr mich fragt.. Link: http://d.hatena.ne.jp/pcm1723/20120418/1334746384 Download: http://www.geocities.jp/pcm1723/html2/download.htm MfG Rolf
Datum:
@Rolf Hast du vllt mal das Sound-Demo als MP3 oder nen Link wo man sich dieses Demo anhören kann ? Ich hab leider keinen STM zur Hand um das mal ausprobieren zu können. Würde mich aber dennoch mal interessieren wie das klingt. FM-Synthese ist ja klanglich schon recht mächtig bzw bietet viele Möglichkeiten. Vor allem wenn man FM-Synthese als Klangquelle nutzt und mit einem nachgeschalteten analogen oder digitalen Filter "verfeinert" :-) Das ist auch eins der Dinge die ich meinem Audio-Projekt gerne noch beibringen würde. Aber bisher hab ich mich mit der FM noch nicht weiter beschäftigt (also das ich das aufm PC mal "durchrechne" und einfach mal was rumspielen kann). Von daher danke schonmal für die Links. Vllt kann ich mir da was für aufn PC mal selbststricken.
Datum:
Hallo Rene Ich werde die Demo Heute in soundcloud.com bereitstellen und dich hier informieren. Ferner versuch ich Heute einen Optokopler an das Discovery Board "anzukleben", um die Demosounds anzuspielen. Mal schaun obs funktioniert.. Hab noch eine interessante Projekt-Seite im INet gefunden. Nennt sich "Jo-Midi-FM". Ist eine japanische Website. Mit Google-Translate in Deutsch kann man es uebersetzen lassen. Link: http://www.geocities.jp/pcm1723/ MfG Rolf
Datum:
Angehängte Dateien:Hallo Rene Im Anhang findest du eine c.File aus dem FM Sound Projekt fuer das Discovery Board. Vielleicht hilft es dir. Gruss Rolf
Datum:
Hallo zusammen.. Ich habe an das Discovery-Board jetzt einen Midi-Anschluss gelötet, damit ich die Demo Sound des FM Sound Generator über ein Midi-Keyboard abspielen kann. Schaltplan gibts hier: http://www.cczwei-forum.de/cc2/thread.php?postid=7... Gruß Rolf
Datum:
Hallo Rene Ich habe den Demo-Sound des STM32F4 Discovery Boards mal ins Netz gestellt. Kann man sich als MP3 hier auf soundcloud.com anhören oder downloaden: http://soundcloud.com/rolfdegen/st32mf4-demo-02 Gruß Rolf
Datum:
Hallo Rolf, erstmal danke für das Demo. Hört sich ja recht schnuckelig an. (Hatte mir schon irgendwie gedacht das das so sanft und soft klingt, irgendwie haben die Japaner glaub ich einen Faible dafür :-)) Aber klingt sehr sauber das ganze. Ich glaub ich werd mich auch mal mit FM Synthese beschäftigen. Vllt bringe ich meinem FPGA sowas auch noch bei :-)
Datum:
Hallo Rene Naja.. Im Vergleich zu den Demo-Sound von deinem Spartan3 Board klingen die Sounds das Discovery sehr bescheiden. Ich habe noch ein MP3-File mit einzelnen Klängen vom Discovery Board erzeugt und auf soundcloud.com hochgeladen. Hier der Link: http://soundcloud.com/rolfdegen/st32mf4-demo-03 Gruß Rolf
Datum:
Na ja ... aber im Endeffekt ist es nur ne Frage der Software. Das was in meinem Audio-Projekt abläuft lässt sich mit recht wenig aufwand sicherlich auch auf nem Discovery Board laufen lassen. Die Filter die ich verwende sind ganz normale IIR-Biquads. Und die Berechnung der Koeffizienten erfolgt in einem AVR :-) Also alles im Prinzip kein Hexenwerk. Daher fänd ich das ja so interessant die FM mal so aufzuschnibbeln das ich das mit in meinem Synth reinbekäme :-)
Datum:
Hab mir gerade mal die Sounds angehört. Sehr schöne Demos. Ideal als Oszillator. Dahinter noch nen schönen Resonanzfilter mit Hüllkurve und LFOs ... Yammy :-)
Datum:
Der Hall bzw. die Echos in den Sounds kommen auch vom Discovery. Ich habe die Sounds über den Line-Out vom Discovery übers Mischpult und ohne Effekte aufgenommen. Gruß Rolf
Datum:
Ach ja ... der Hall in dem Demo. Wäre auch mal ein Interessanter "Opcode" für mein Audio-Projekt. Hab dir übrigens ne PN geschickt. Die Demos waren vom TGFM oder von dem Jo-MIDI FM ?
Datum:
Hab jetzt mein Altera-Board, leider wurde da nur ein Ami-Netzteil mitgeliefert, was mir hier natürlich nicht hilft. Hab es mal an mein Labornetzteil gehangen, und es scheint zu gehen. Mehr kann ich da aber nicht machen, weil ich in meiner Bastelecke keine Anschlussmöglichkeiten habe. Der Code der mitgeliefert wird, ist in Verilog, was ein herber Rückschlag ist, da ich mich auf VHDL eingerichtet habe. Dennoch ist er recht überschaubar, und ich begreif wenigstens wie sie zum Ziel kommen. Es sind einige Audio-Demos dabei. Die Synthesizer-Demo nutzt Wavetable-Synthese (vom FPGA Ram), was auch keine Überraschung ist, da man damit schnell zum Ziel kommt. Zum Thema FM: Ich habe nie verstanden, weshalb das immernoch so gefragt ist. Mit den Sounds kann ich irgendwie nichts anfangen. Vom techn. her, ist es auch nichts anderes als dass man den Ausgang eines Osc an den Frequenzeingang eines anderen Osc hängt. Beim Hall wird es schon interessanter, ab einer gewissen Dichte wird dann auch einem M4 die Luft ausgehen. Bei meinem letzten Reverb den ich gebaut habe, brauchte ich alleine 74 Filter: 1 Lowpass 1 Highpass 8 Allpass 64 Comb
Datum:
@Maik FM als alleiniger Sound ist auch recht langweilig. Aber FM als Oszillator mit schönen "dicken" Resonanz-Filtern dahinter macht schon was her. Wenn ich mir den FM7 von NI z.b. anhöre. Ok, da ist die FM-Synthese ein büüschen aufgebohrt, aber gerade das zeigt ja eigentlich das man mit ein bissl Spielerei doch noch recht brauchbare Sounds rausholen kann. Und es ist ja auch immer eine Frage wie komplex die Anordnung ist. Mit zwei/drei Sinusoszillatoren gewinnt man auch keinen Blumentopf. Aber bei 6-8 Operatoren, entsprechenden Wellenformen, Filtern und Effekten klingt das durchaus mehr als brauchbar. Zum Thema selbstgebautes FPGA-Board. Falls ich mein Redesign für mein Board mache und Interesse besteht kann ich dir (und auch dir Rolf) auch gerne eins zusammenlöten und testen.
Datum:
Rolf Degen schrieb: > Welches Altera-Board hast du genau ? Der komplette Name lautet: DK-DE2-2C35N/UNIV Es ist dieses: http://www.altera.com/education/univ/materials/boa... Im Prinzip tut es auch das DE1, aber ich wollte ein Board, wo ich ohne zu basteln alles drauf habe (LCD fehlt beim DE1). Und der Vorteil bei Dev-Boards ist ja, dass für alles was darauf ist, auch Demos vorhanden sind, und ich lerne am funktionierenden Code einfach schneller :) Rene B. schrieb: > Zum Thema selbstgebautes FPGA-Board. Falls ich mein Redesign für mein > Board mache und Interesse besteht kann ich dir (und auch dir Rolf) auch > gerne eins zusammenlöten und testen. Ja, Interesse ist immernoch da. Ein simples FPGA-Audio Modul wäre eine feine Sache, sowas findet man leider nirgends (--> Marktlücke :))
Datum:
Dem kann ich nur zustimmen. Hätte auch Interesse an einem Sound-Board von Rene. Zumal man dann auch ein Ansprechpartner bei Problemen und Ideen hat. Gruß Rolf
Datum:
Na ja. Ich hab damals schon nach "mitstreitern" gesucht und auch vereinzelt gefunden. Aber das Problem ist eben immer der Preis. Der hängt eben stark davon ab wieviele Leute sich finden. Zumal der "Löwenanteil" des Preises in erster Linie durch die Platine bestimmt wird. Ein Einzelstück (nur die Platine) kostet dann gerne 60-70 Euro. Bei 10 Leuten sinds dann nur noch ca 15 Euro (oder so). Die restlichen Bauteile liegen dann so im Bereich 50-60 Euro. Also ich geb mal die Eckdaten was ich mir Vorstelle an Hardware bzw was ich Schaltplan und Layoutmäßig schon fertig habe : - Spartan 6 FPGA (LX9) nebst SPI-Flash - 8/16/32MB SDRAM (je nach Beschaffbarkeit) - Audio-Codec (TLV320AIC23B) mit Line In/Out, Kopfhöreranschluß, Mikrofoneingang (aber nur der Kopfhörerausgang hat ne Klinkenbuchse) - µSD-Karten-Slot - AVR ATMega644P/1284P - FTDI FT232 um mit dem AVR quatschen zu können und gleichzeitig die 5V für die Platine - 8 Analogeingänge (über einen Multiplexer) - Stiftleisten für den FPGA - Stfitleisten für den AVR Was ich noch am überlegen bin da drauf zu flanschen ist : - MIDI-Interface (je nach Platz) - einfaches R-Netzwerk um VGA-Signale auf eine Stiftleiste zu geben Ich schau mal das ich heute Abend den Schaltplan so wie er momentan ist hier mal reinstelle. Vllt schaffe ich es beim dritten Anlauf ja mal genug Leute für so ein Projekt zusammenzutrommeln. @Maik Wenn das wirklich so ne Marktlücke ist würde ich diese gerne Ausfüllen. Aber alleine bekomm ich das nicht hin (Vertrieb, Gewerbe, WEEE oder wie das heißt usw). Tät mir gerne damit was dazuverdienen :-)
Datum:
Ich helfe, soweit es mir möglich ist. Mit FPGAs fang ich "praktisch" gerade erst an, "theoretisch" bin ich schon weiter. Auf das Board würde ich nur das nötigste packen, alles das womit ein einfacher µC-User bisher nichts zu tun hatte. Also im groben: - das Board hat nur eine einzige Eingangsspannung (5V oder 3,3V) - daraus folgt: alle Spannungsregler onboard - FPGA + Config-Rom/Flash - RAM - Codec (ggf. mit Amp) Mehr müsste da nicht drauf sein. Aber es gibt noch ein paar Dinge wo ich mir nicht sicher bin. zB. man könnte die Klinkenbuchsen draufbauen, aber was ist wenn man das Board nur als "Kern" einsetzt, und das Trägerboard die eigentlichen externen Anschlüsse trägt? Weiß nicht, wie es beim Programmieren vom Spartan ist, beim Cyclone braucht man JTAG+AS und natürlich den passenden Programmieradapter (Original: 200 Euro). Den µC würde ich keinesfalls mit auf das Board nehmen, weil jeder bevorzugt ja einen anderen. Auch kann man den zur Not auf ein Breadboard setzen. Gleiches gilt für Midi. Man könnte den Midi-Anschluss ja an den FPGA hängen oder halt an den µC. Das sollte dem User überlassen werden.
Datum:
Angehängte Dateien:Ich werde das Soundmodul später in mein kleines Midi-Keyboard einbauen und über ein Grafisches Display mit Touch-Panal-Funktion ansteuern. Ich hab mal eine Fotomotage im Anhang gemacht. So solls später aussehen. Im Midi-Keyboard ist Platz genug für zwei Eurokarten voll Elektronik. @Rene. Hab auf der CC2-Website mal ein wenig Werbung für dein Projekt gemacht. Vielleicht meldet sich ja noch der Eine oder Andere bei dir. LG Rolf
Datum:
@Maik Die Platine wird mit 5V versorgt (über USB) und hat die LDOs für 3.3V und 1.2V drauf. Den uC möchte ich mir nur ungern "klemmen" da mich schon bei den früheren Platinen genervt hat das ich immer nen uC separat drankorken musste. Und der AVR kann ja auch anfangs die Programmierung des SPI-Datenflashs übernehmen. Ist ja nicht zwingend erforderlich das du den nutzt um den FPGA zu "bespaßen" :-) Und außerdem kann man ja über die Stiftleisten noch nen anderen uC an den FPGA drankorken. @Rolf Vielen dank für die Werbung :-) Und dein "Preview" zum AVR WAVE 1 im Keyboard sieht recht schnuckelig aus :-) Wollte das mit meiner Platform auch machen. Bin aber noch nicht dazu gekommen.
Datum:
Angehängte Dateien:So ... hier mal Schaltplan und die Bauteilplatzierung von dem neuen Board so wie es ist.
Datum:
Schaut recht kompakt aus. Wieviel Layer sind das? Wie gesagt, würde ich das unnötige weglassen. Wenn das Board so klein ist, könnte man das sogar als Arduino-Shield auslegen... damit hätte man eine wesentlich größere Reichweite. In diesem Fall könnte man den restlichen Platz für die 2 freien Audio-I/O nutzen und sogar Midi noch mit draufbauen.
Datum:
@Maik Es sind genau 2 Layer :-) Die Idee das Teil zu nem Arduino Shield umzubauen wäre evtl noch ne Idee. Nur sollte man dann die großen Arduino nehmen. Mit 32K kommt man u.u. nicht so weit. Und es müssten noch einige Levelshifter platziert werden, um die 5V Signale des Arduinos kompatibel mit den 3.3V Signalen des FPGAs zu machen. Und man müsste sich überlegen wie man das macht wenn das Board an einen 3.3V uC statt eines 5V uCs angekorkt wird (obwohl es da u.u. reicht die Spgsversorgung für die Levelshifter Jumperbar zu machen.
Datum:
Hallo Ich habe diese Tage ein wenig an der Soundquallität meines Synthis gefeilt und die Auflösung von 8Bit auf 12Bit geändert. Zusätzlich habe ich die 12Bit Sinustabelle von 256 Tabellenwerten auf 4096 Werte erhöht. Die Soundausgabe klingt jetzt rauschärmer und erzeugt bei der Wiedergabe von hohen Tönen weniger Verzerrungen. Sinuston (12Bit und 8Bit) auf einem ATxmega128A1 mit internem 12Bit DAC http://soundcloud.com/rolfdegen/sinus_12bit_8bit Gruß Rolf
Datum:
Angehängte Dateien:Hallo Ich möchte die benötigte Zeit für die Soundaugabe von zwei Sinus-Oszillatoren in meinem C-Code verringern (siehe Anhang), um einen dritten Oszillator zu implementieren . Die Interrupt-Routine benötigt für die Ausgabe von zwei Sinustönen auf einen DAC-Kanal schon über 17µsec. Für einen dritter Oszillator reicht die Zeit nicht mehr aus. Hat jemand von euch vielleicht eine Idee, was ich an meinem Code verbessern könnte ? Jeder Ratschlag ist willkommen. Ich dachte auch schon daran, die DAC-Ausgabe in Assembler zu schreiben und in den C-Code mit einzubinden. Aber ich habe keine Ahnung, wie ich das in Atmel Studio 6.0 machen könnte. Ich bedanke mich schon im Voraus für eure Tips. LG Rolf
Datum:
schrittweite_temp kannst du weglassen, und direkt mit schrittweite1/schrittweite2 rechnen. Spart Ram und mind. 4 Zyklen. Die Accus kannst du Global auch als Register definieren, dann dürftest du einiges an Zyklen sparen. Kannst auch mal hier schauen: http://www.mikrocontroller.net/articles/AVR-GCC-Co... Aber so etwas Zyklenkritisches würde ich eh komplett in Assembler angehen. Dann hat man eine genaue Kontrolle.
Datum:
Angehängte Dateien:Hallo Maik Danke für deinen Tip. Das Ändern des Phasenaccus auf eine globale Register-Variable mit "register32_t" hat leider nicht viel gebracht. Ich habe testweise die Bit-Breite des Phasenaccus von 32Bit auf 16Bit reduziert und komme jetzt auf eine Berechnungszeit von 2µsec pro Oszillator. Ingesammt benötigt die Interrupt-Routine jetzt etwas weniger als 9µsec (vorher 17µsec). Durch die Änderung des Phasenaccus von 32Bit auf 16Bit reduziert leider auch die Frequenzauflösung auf ca. 1,34 Hz pro Schritt. Als nächstes werde ich versuchen, die Interrupt-Routine in Assembler zu schreiben und in meinen C-Code mit einzubinden. Mal schaun obs funktioniert.. Gruß Rolf
Datum:
Hallo, wie berechnest Du die Hüllkurve bzw. die Variable adsr_1? Kannst Du den C code mal einstellen? Gruß
Datum:
Angehängte Dateien:Hallo Klaus Ja gerne, ist kein Geheimnis. Die Routine läuft über einen Timer-Interrupt und wird alle 1msec aufgerufen. Der berechnete Hüllkurvenwert für den DAC hat eine Auflösung von 12Bit. Die Routine ist alledings noch nicht ganz fertig, funktioniert aber in groben Zügen schon. Gruß Rolf
Datum:
@Maik Hallo Ich konnte die Ausführungszeit meiner Sound-Routine nochmals von 9µsec auf 6.5µsec reduzieren, indem ich die Compiler-Optimierung in Atmel Studio 6 von "Os" auf "O2" geändert habe. Mehr Infos zum Thema gibts hier: http://www.cczwei-forum.de/cc2/thread.php?postid=7... Gruß Rolf
Datum:
Hallo ihr Musikbegeisterten, habe selbst mit einem 80MHz-16Bit-DSP Musik in C erzeugt, dort geht alles eleganter: z.B. 16x16-Mul in 25ns. Finde es jedoch umso beachtlicher, dass es auch mit 8Bit und 20 MHz akzeptabel klingt. Wenn man den Asm-Code anschaut, merkt man, wo noch gespart werden kann: Die häufigst verwendeten Variablen sollen in festen Registern stehen. Ich weiß nicht aus dem Stegreif, wie man das dem GCC beibringt. Die im oberen Link genannte Anote AVR200 ist völlig ungeeignet, da sie für kleine AVRs ohne MUL-Befehl gedacht ist. Auf jeden Fall lesenswert sind folgende Beiträge: Beitrag "DDS normal ?" Beitrag "DDS Sinus erzeugung" Beitrag "Rechnen mit AVR"
Datum:
Hallo Ich versuch mich gerade mal mit Assembler. Ich möchte die komplette Soundausgabe über eine Assembler-Routine in meinem C-Programm machen. Sie dazu den Beitrag im CC2-Forum: http://www.cczwei-forum.de/cc2/thread.php?postid=7... Gruß Rolf
Datum:
Hallo an alle, Wenn es von Ihrem Interesse ist, schauen Sie bitte auf Youtube-Video "STM32F4 Discovery Soft Synth" und geben Sie mir Ihre Meinung. Jeder Vorschlag wird zu schätzen wissen !!
Datum:
Hallo. My name is Rolf Degen from germany. It is a very good project. I'm I also currently developing a synthesizer on an AVR 8-bit processor basis. My Link: http://www.cczwei-forum.de/cc2/thread.php?threadid=5878 I'm German and all information on this site is in german. Sorry Greetings from germany I can't writen a link on your youtube-site. Why ??? Greetings Rolf
Datum:
Hello Rolf, This is a YouTube restriction. I see that you have avoided the obstacle ! I suggest you to open a parallel english page (for example on EmbDev.net ) to give more visibility at your project. I also have developed some project in my native language, but due to the poor quality of the various translator utility, I get only local audience. Best regards, Alessandro.
Beitrag #2754343 wurde vom Autor gelöscht.
Beitrag #2754352 wurde vom Autor gelöscht.
Datum:
Angehängte Dateien:Hallo Rolf Degen schrieb: > Ich versuch mich gerade mal mit Assembler. Ich möchte die komplette > Soundausgabe über eine Assembler-Routine in meinem C-Programm machen. Zum Programm: Der Assembler-Code beinhaltet jetzt die komplette Timer1 Interrupt-Routine für die Soundausgabe der zwei DCO's inklusive der Hüllkurve. Die Laufzeit beträgt insgesammt 5,53 µsec. Der Aufruf der Interrupt Routine erfolgt alle 25 µsec durch die Interrupt-Freigabe im Hauptprogramm (C-Code). Mehr Info gibts hier: http://www.cczwei-forum.de/cc2/thread.php?postid=7... Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen Dank großartiger Unterstützung von Wolfgang aus dem CC2-Forum (http://www.cczwei-forum.de/cc2/), konnte ich die Assembler-Routine für meinen AVR-Synthi noch etwas verbessern. Hinzugekommen ist die Möglichkeit, außer einer Sinus-Wellenform auch eine Sägezahn-Wellenform auszuwählen. Der Parameter dafür wird als 8Bit Volatile Variable aus dem C-Programm (Main-Programm) übergeben. Wolfgangs Website: http://www.wiesolator.de/ Gruß Rolf
Datum:
Hallöchen.. Gibt noch ein paar neue Sounds vom AVR-Synthi. SAW-Sounds mit zwei Oszillatoren: http://soundcloud.com/rolfdegen/saw-oszillator FM-Sounds (1 Operator): http://soundcloud.com/rolfdegen/fm-01 Gruß Rolf
Datum:
Angehängte Dateien:Hallo In meinem Code ist noch eine einfache FM-Sound Erweiterung hinzugekommen. LG Rolf
Datum:
Angehängte Dateien:Hallo Ich bin gerade dabei, die Hüllkurvenansteuerung in meinem AVR-Synthi zu verbessern. Problematisch war die Release-Phase, da sie nur einen geraden Verlauf hatte. Aber was wäre ich ohne die Unterstützung von Wolfgang (ein Genie wenn ihr mich fragt). Er hatte mich auf die Idee gebracht, die Release-Phase mit Hilfe einer kleinen Umrechnung in eine angeglichene e-Funktion umzusetzen (siehe Bild). Hier die Berechnung für die Release-Phase: ADSR_Hoehe = 65535 Release_Time = 2- 65535 if (ADSR_Hoehe > 0) { ADSR_Hoehe = ADSR_Hoehe - ((ADSR_Hoehe / Release_Time)+1); } Der Übergabewert für ADSR-Steuerung in meiner Assembler-Routine muss auf 12Bit reduziert werden: adsr_1 = ADSR_Hoehe >>4 Bild-Anhang: Neue Release-Phase im AVR-Synthi Mehr zum Thema hier: http://www.cczwei-forum.de/cc2/thread.php?postid=7... Gruß Rolf
Datum:
Ich würde mir überlegen, ob du das ganze wirklich so genau brauchst. In meinem Synthesizer ist der Akkumulator 16bit groß (In meinem Quelltext steht davon nichts, da ich beim Programmieren nicht mal DDS kannte, sondern selbst überlegt habe wie ich verschiedene Frequenzen erzeuge). Die Hüllkurve ist nur 8bit groß, zusätzlich gibt es eine Lautstärkeregelung für jeden Kanal (8bit). Ich würde in die Tonerzeugung nicht einfach mal so eine 16bit Division reinhauen. Bei mir hat es quadratisch schon ziemlich gut funktioniert. Pseudo-Code:
counter = 255;
...
if(counter < release_time)
Relase_volume = 0;
else
{
counter -= release_time;
Release_volume = counter * counter >> 8;
}
|
Das lässt sich in Assembler in wenigen Takten schreiben. Eine Optimierung, die ich dir dringend empfehle ist einen Puffer anzulegen, in den du die Samples berechnest. Das kannst du dann in der Hauptschleife machen, während DMA die Daten ausgibt. Wichtig ist, dass die Erzeugung immernoch in Assembler geschrieben wird. Allerdings werden immer zuerst die Register mit den Werten geladen, dann z.B 64 Samples am Stück berechnet und schließlich die Register zurückgeschrieben. Dadurch fallen alle Schreibzugriffe auf das SRAM während der Tonerzeugung weg. In meinem Synth werden alle Register während der Tonerzeugung genutzt: Dadurch ist es möglich 3 Kanäle gleichzeitig zu berechnen und zu mischen. PS: Die Ideen zur Sounderzeugung in deinem Forum sind wirklich gut. Mein Synthesizer spielt zurzeit zwischen um die 35 Kanäle gleichzeitig bei 25Mhz (44,1kHz). Allerdings sind die Sound relativ einfach, da sie nur aus 512Byte-Tabellen geladen werden. Vielleicht werde ich versuchen auf Kosten der Kanäle die Sounds zu verbessern.
Datum:
Hallo Samuel Erst einmal Danke für dein Interesse an meinem Synthi-Projekt. Die Idee mit einem Sample-Buffer ist schon interessant. Ich frag mich nur, wie ich andere Dinge wzB den Midi-Buffer, Touch-Panel und Grafik-Display noch ansteuern bzw auswerten kann, wenn der Prozessor im Main-Programm mit der Berechnung von Sample-Daten beschäftigt ist. Meine Konstruktion sieht so aus, das ich die komplette Berechnung und Ausgabe der 12Bit-Sounds in einer Timer Interrupt-Routine alle 25µsec durchführe (Samplerate: 40Khz). Die Laufzeit der Interrupt-Routine beträgt insgesamt je nach Syntheseart (SUB,FM) und Wellenform (Sinus, Sägezahn) zwischen 5.4µsec und 5.9µsec für zwei Oszillatoren gleichzeitig. Dadurch bleibt noch genügend Reserve übrig, um Grafik-Display, Touch-Panel und Midi-Daten zu verarbeiten. Später soll am DAC-Ausgang auch noch ein Analoger Filterbaustein wzB. SSM2044 oder FM10 hinzu kommen. Dieser wird dann über die Hüllkuvendaten in der Assembler-Routine gesteuert. Gruß Rolf
Datum:
Wenn ich das richtig verstanden habe macht die Blockweise berechnung nur dann wirklich Sinn wenn man DMA nutzt. Einzig der Overhead der durch das Wegspeichern und Wiederherstellen der Prozessor-Register pro Sample ansteht wird minimiert. Die Berechnung selbst wird ja nicht unbedingt kürzer. Ok, es hängt noch vom Algorithmus ab, ob man beispielsweise vorher noch was "größeres" berechnen muss bevor die eigentliche Audio-Verarbeitung losgeht. Aber im Prinzip spielt das bei den "kleinen" Prozessoren keine Rolle. Gravierender wird das wenn (wie beim PC) Cache ins Spiel kommt. Dann macht das u.u. erheblich was aus einen Buffer vorzuberechnen, da dann der "Kontext-Wechel" nicht bei jedem Sample neu gemacht werden muß, bzw benötigte Variablen nicht erst mühsam bzw u.u. zeitaufwendig aus einem anderen Speicherbereich geholt werden müssen. Aber im Prinzip spricht nichts dagegen direkt Blockweise zu arbeiten. Man muß sich nur je nach Blockgröße klarmachen das dadurch eben auch eine Latenz entsteht (ok das Problem hat man eher auf einem PC), bzw bei Blöcken die größer als 10ms sind die zeitliche Zuordnung der MIDI-Signale auch nicht ganz unproblematisch ist. Aber wer berechnet denn schon 480 Samples im voraus :-) Ich hätte vllt auch noch einen Ansatz für die Hüllkurvengeschichte. Ist aber auch was aufwendiger. Ich habe die einzelnen Phasen anders definiert. Und zwar wird auf ein Register immer der jeweilige Attack/Decay/Release Wert aufaddiert. Der Akku ist quasi eine Skalierung für eine Tabelle (beispielsweise 0-255). In dieser Tabelle steht dann linear/exponentiell/umgekehrt exponentiell der Lautstärke Verlauf (von 0-1). Die nächste Phase beginnt dann wenn der Akku überläuft. In der Sustain Phase wird der Akku immer genullt. Man kann dann somit für jede steigende/fallende Phase unterschiedliche Charakteristika definieren. Bei der Lautstärke macht sich das vllt nicht so bemerkbar, aber wenn die Hüllkurve z.b. einen Filter langsam steuert hört sich das dann schon unterschiedlich an. Außerdem kann man mit dieser Phasen/Zeit-Unterteilung auch andere Hüllkurven leichter realisieren. z.b. eine AHDSR, HADSHR oder die mehrphasigen Hüllkurven von z.b. Roland Synthies recht einfach implementieren, ohne jedesmal den Code umzuschreiben. Mal so als Anregung für deinen FM-Synthie :-)
Datum:
Hallo Rene Ich werde erst einmal bei meinem Konzept bleiben und langsam mein Touch-Panel und Grafik-Display für Benutzereingaben programmieren. Dadurch spare ich mir die ständige Neuprogrammierung des Xmega-Prozessors für diverse Sound- und Hüllkurven-Test. Deine Idee für die Hüllkurvensteuerung finde ich sehr interessant und werde es Später mal ausprobieren. Hab gerade mal nach dem Filter IC "SSM2044P" gegooglet. Bei http://darisusgmbh.de/shop/index.php gibts das IC für nur 14,28 Euro. Lieferzeit zwei Wochen. Gruß Rolf
Datum:
Der Puffer bringt schon ziemlich viel: Ich hab dein Asm-Programm mal überflogen, da sind > 50 Ramzugriffe drin -> mehr als 100 Takte werden für das Laden/Speichern/Sichern verbraucht. Wenn man 64 Samples am Stück rechnet ist es nur noch 1/64 der Zeit. Wenn du noch etwas optimieren willst, dann ist der Puffer wahrscheinlich die beste Variante. @Rene Selbst ohne DMA macht es Sinn. Bei mir hat diese Optimierung das Programm mehr als doppelt so schnell gemacht (Atmega328 hat leider kein DMA).
Datum:
Angehängte Dateien:Hallo zusammen Ich habe die Hüllkurvensteuerung für den AVR-Synthi noch einmal überarbeitet (siehe C-Code im Anhang). Die Parameter habe ich auf 16Bit Breite belassen, weil dadurch auch außergewöhnlich lange Attack- und Release-Phasen für spezielle Soundeffekte möglich sind. Im Anhang ein Bild vom neuen Hüllkurvenverlauf im AVR-Synthi. @Samuel Ich werde auf jeden Fall deine Idee mit dem Sample-Buffer im Sinn behalten und es Später versuchen umzusetzen. Zur Zeit arbeite ich noch an vielen Baustellen im Synthi und die Optimierungen stehn da noch ganz hinten an. Gruß Rolf
Datum:
Fortsetzung: Ich glaube das Wolfgang aus dem CC2-Forum ein ähnliche Buffer-Funktion in seinem Synthi-Projekt realisiert hat (Link: http://www.wiesolator.de/index.php?area=Musik&topi...). Gruß Rolf
Datum:
Hallo, kannst Du bitte mal den kompletten code posten? Ich möchte das auf einem AVR32 testen. Viele Grüße
Datum:
Angehängte Dateien:Hallo Klaus Im Anhang findes du meinen gepackten Quellcode. Es sind zwei Dateien. Das Main-Programm in C und die Assembler-Routine, die per Timer-Interrupt im Main-Programm aufgerufen wird. Ich arbeite unter Atmel Studio 6 mit GCC 4.7.1. LG Rolf
Datum:
Hallo Rolf, vielen Dank, ich versuche mich jetzt daran den code auf dem AVR32 zum laufen zu kriegen. Viele Grüße
Datum:
Hallo liebe Musikliebhaber auf mikrocontroller.net Es gibt mal wieder was auf die Ohren von meinem Synthi. Aus purer Freude an den Klängen aus meinem Synthi und weil es irren Spass macht, damit rum zuspielen, habe ich im Synthi einen kleinen Live-Sequenzer programmiert. Das Ergebnis könnt ihr euch auf SoundCloud anhören. Allerdings hege ich keinen Anspruch auf kompositorische Fähigkeiten :-) Link SoundCloud: http://soundcloud.com/rolfdegen Aber Vorsicht, die Demo-Sequenzen sind von mir live gespielt und nur für Ohren gedacht, die Elektronischen Musik wzB von Klaus Schulze, Kraftwerk, Stockhausen und Co lieben :) Wünsch euch viel Spass beim hören. Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen Ich habe die Attack-Phase in der Hüllkurvensteuerung meines AVR-Synthis etwas verbessert. Die neue Hüllkurve kommt einem analogen Synthesizer schon sehr nahe. Mehr Infos gibts hier: http://www.cczwei-forum.de/cc2/thread.php?postid=7... LG Rolf
Datum:
Hallo liebe Synthi-Fans Es gibt mal wieder was auf die Ohren. Dieses mal habe ich ein paar Demo-Sounds durch den spannungsgesteuerten LowPass-Filter (CEM3320) im AVR-Synthi gejagt. Die Filterfrequenz wird durch einen eigenen ADSR-Generator gesteuert. Die Filterresonanz manuell über einen Regler am Keyboard. Was leider noch fehlt, ist die Modulation durch einen LFO (LowFrequenzOszillator). AVR-Synthi Demo-Sounds mit LP-Filter: http://soundcloud.com/rolfdegen/filter-wave-01 Die Steuerung der Filterfrequenz- und Resonaz erfolgt über zwei PWM-Ausgänge am Xmega-Prozessor. Gruß Rolf
Datum:
Hallo Es gibt wieder etwas neues im AVR-Synthi. Ich habe jetzt drei LFO's für die Modulation des Oszilators, Filter und DAC implementiert. Mehr Infos gibts hier: http://www.cczwei-forum.de/cc2/thread.php?postid=7... Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen Ich habe einen Digitalen Noise-Generator (nach einer Idee von Wolfgang aus dem CC2-Forum) in den AVR-Synthi implementiert (siehe Klangbeispiel). Zusätzlich habe ich ein aktuelles Prinzipschaltbild mit den Funktionsblöcken gezeichnet. Klangbeispiel "Noise": http://soundcloud.com/rolfdegen/avr-synthi-noise Im Anhang das Prinzipschaltbild und mein Programm. Das ganze ist leider noch eine Baustelle und soll euch nur eine Stütze für eigene Ideen für euer Projekt sein. Gruß Rolf
Datum:
Hallo Rolf, ich möchte Deinen Thread nicht hijacken, aber gestatte eine kurze OT-Frage: Das scheint ein (Xplain?) Experimentierboard mit einem ATxmega128A1 + S(D)RAM zu sein - genau das könnte ich für ein eigenes Projekt zur Zeit gut gebrauchen... Könntest Du mir sagen wie sich das Board nennt und ggf. woher man es bekommen kann? Grüße Sascha
Datum:
Sascha W. schrieb: > Das scheint ein (Xplain?) Experimentierboard mit einem ATxmega128A1 + > S(D)RAM zu sein - genau das könnte ich für ein eigenes Projekt zur Zeit > gut gebrauchen... > Könntest Du mir sagen wie sich das Board nennt und ggf. woher man es > bekommen kann? http://www.cczwei-forum.de/cc2/thread.php?postid=7...
Datum:
Hallo Sascha Es handelt sich um das Atmel XMEGA-A1 Xplained Evaluation-Kit. Ich habe es bei Reichelt gekauft (siehe Link). Link Reichelt: http://www.reichelt.de/Programmer-Entwicklungstool... Gruß Rolf
Datum:
Super - Danke Euch für die Hinweise! Ist zur Abwechslung ja auch mal einfach zu bekommen, nicht nur direkt aus Hongkong ;) Grüße Sascha
Datum:
Hallo Es gibt wieder was neues über die Stromversorgung des AVR-Synthis. Näheres auf: http://www.cczwei-forum.de/cc2/thread.php?postid=7... Gruß Rolf
Datum:
Hallo und guten Morgen Ich habe einen Schaltplan für den AVR-Synthi gezeichnet. Auf http://www.cczwei-forum.de/cc2/thread.php?postid=7... kann man sich jetzt den Schaltplan ansehen. Gruß Rolf
Datum:
Angehängte Dateien:Hallo Ich habe jetzt das Bedienschema fuer das Touch Panal Display fertig gestellt. Die Systemeinstellungen fuer den Synthesizer werden ueber mehrere Menue-Seiten aufgerufen und koennen dort veraendert und abgespeichert werden. Das Aufrufen der einzelnen Menue-Seiten erfolgt ueber die Tabreiter (siehe Youtube-Video). Bild: Touch Panal Menue AVR-Synthi Youtube-Video: Youtube-Video "AVR Synth Menue" Im Moment sind die Menue-Seiten noch leer. Ich werde mir jetzt Gedanken darueber machen muessen, wie ich die Synthesizer-Funktionen in den Menue-Seiten sinnvoll gestalte. Gruß Rolf
Datum:
Angehängte Dateien:Hallo Habe Heute das 1.Menü für den Audio-Filter im Synthesizer entwickelt (siehe Bild). Die Fader sind groß genug und lassen sich auch leicht mit einem Finger bedienen. Leichter und feinfühliger gehts natürlich auch mit einem Tabstift. Ich benutze zum Beispiel einen alten Kugelschreiber mit einer Kunststoffspitze. Funktioniert damit prima und hat nix gekostet. Bild: VCF1-Menü auf dem Touch Panel des AVR-Synthis Durch die Anregung von verschiedenen Usern, habe ich mich dazu entschieden, für die Parameter-Eingaben zusätzlich einen Drehencoder mit Rast- und Tasterfunktion zu verwenden. Damit werden die Parametereingabe noch leichter und komfortabler. Gruß Rolf
Beitrag #2859870 wurde vom Autor gelöscht.
Datum:
Angehängte Dateien:Hallo zusammen Ich habe Probleme mit Phasen-Jitter in meinem Synthi-Projekt. Der Phasen-Jitter entsteht, wenn der Wert des Phasenaccus mit dem Wert für die Schrittweite nicht gerade teilbar ist. In meinem Fall beträgt der Jitterwert max 25µsec = 40KHz und das ist genau die Sample-Frequenz für die Tonausgabe (siehe Bild 1+2). Wenn ich für die Schrittweite eine Wert nehme, mit dem der Phasenaccu (24Bit) gerade teilbar ist, sind keine Störungen warnehmbar und auf dem Oszilloskop ist eine saubere Saw-Wellenform zu sehen (Bild 3+4). Phasenaccu 24Bit Schrittweite 24Bit Samplerate 25usec (40KHz) Bild 1: SAW-Wellenform ca. 2031Hz mit Phasen-Jitter (max. 25usec / Div. 100µsec) Bild 2: SAW-Wellenform ca. 2031Hz mit Phasen-Jitter (max. 25usec / Div. 2msec) Bild 3: Saw-Wellenform ca. 2038Hz ohne Phasen-Jitter (Div. 100µsec) Bild 4: Saw-Wellenform ca. 2038Hz ohne Phasen-Jitter (Div. 2msec) Das Problem lässt sich nach meiner Meinung nur durch ein Zurücksetzen des Phasenaccus auf 0 beheben, wenn die Wellenform neu beginnt . Dadurch wird der Phasenaccu mit der Wellenformerzeugung synchronisiert und es ensteht kein Jitter mehr. Allerdings ist dann keine genau Frequenzeinstellung mehr möglich. Versuche mit Erhöhung der Bitbreite des Phasenaccus waren nicht erfolgreich. Der Phasen-Jitter reduzierte sich dadurch nicht.. Zur Information habe ich noch eine Infoseite gefunden, die das Phasen-Jitter Problem bei der DDS Synthese sehr anschaulich beschreibt: http://www.elektronik-labor.de/AVR/DDSGenerator.htm Gruß Rolf
Datum:
Hallo Stundenlagens Grübeln und die Notizen beim Schalfen unters Kopfkissen haben leider nicht geholfen Ich finde einfach keinen Lösungsansatz für mein Jitter-Problem. Würde man die Soundausgabe über einen Timer steuern, könnte man die DDS-Problematik vielleicht vergessen. Einen Lösungsweg wie es Olivier Gillet bei seinem Shruthi-Synth macht (Soundausgabe über PWM und ext. VCF+VCA) will ich nicht nachbauen. Ich möchte mein eigenes Hardware Konzept beibehalten. Link Shruthi Synth: http://mutable-instruments.net/shruthi1
Datum:
Hallo Ich habe hier einmal den relevanten Programmteil der für die Erzeugung der Sinus und Saw-Wellenform verantwortlich ist dargestellt. Die gesammte Sound-Routine (hier nicht abgebildet) wird in einem Timer-Interrupt alle 25µsec im Main-Programm (C-Code) aufgerufen. Wellenformspeicher für Sinus (4096 Werte 12Bit) 12Bit DAC-Wandlung im Xmega-Prozessor 1MHz-Wandlerate
//=============================================================== // SUBTRAKTIVE KLANGSYSYNTHESE //=============================================================== SubSynthese: //--------------------------------------------------------------- // DCO-1 // * 24-Bit Akku-Breite // * 24-Bit Phasen-Delta (2,384185mHz/Unit) // * 12-Bit Sample // ( 38 Takte = 1,188 µsec) //--------------------------------------------------------------- // Phasen-Akku 1 incrementieren // ---------------------------- DCO1Calc: LDS delta0, schrittweite1+0 ; 2 Phasen-Delta aus SRAM laden LDS delta1, schrittweite1+1 ; 2 LDS delta2, schrittweite1+2 ; 2 LDS phakku0, phaccu1+0 ; 2 Phasen-Akku aus SRAM laden LDS phakku1, phaccu1+1 ; 2 LDS phakku2, phaccu1+2 ; 2 SUB phakku0, delta0 ; 1 Phasen-Akku + Phasen-Delta SBC phakku1, delta1 ; 1 SBC phakku2, delta2 ; 1 STS phaccu1+0, phakku0 ; 2 Phasen-Akku in SRAM zurückschreiben STS phaccu1+1, phakku1 ; 2 STS phaccu1+2, phakku2 ; 2 // Die oberen 12Bit des Phasen-Akkus extrahieren // --------------------------------------------- ANDI phakku1, 0xF0 ; 1 Lower Nibble in Byte 0 abnullen LSR phakku2 ; 1 Division durch 8 (16-Bit) ROR phakku1 ; 1 LSR phakku2 ; 1 ROR phakku1 ; 1 LSR phakku2 ; 1 ROR phakku1 ; 1 // Waveform-Selektion // ------------------ LDS dcowave, DcoWaveForm ; 2 Wellenform-Selektion laden SBRS dcowave, 0 ; 1/2 RJMP DCO1Sine ; 2 Sinus bestimmen // Saw über 1:1 Phase ausgeben // --------------------------- DCO1Saw: LSR phakku2 ; 1 Phasen-Akku / 2 ROR phakku1 ; 1 MOV dcomix0, phakku1 ; 1 Phase umladen MOV dcomix1, phakku2 ; 1 RJMP DCO1End ; 2 Fertig // Sample über aktive Phase aus Wavetable laden // -------------------------------------------- DCO1Sine: LDI R30, 0xFC ; 1 Basis-Adresse Sinus-Tabelle (Low-Byte) LDI R31, 0x03 ; 1 (High-Byte) ADD R30, phakku1 ; 1 Phasen-Pointer addieren ADC R31, phakku2 ; 1 LPM dcomix0, Z+ ; 3 Sample aus Wavetable laden (16-Bit) LPM dcomix1, Z ; 3 => in MixerSumme als Initialwert DCO1End: |
Die Zwischentöne, die der Phasen-Jitter verursacht, kann man sehr deutlich ab einer Frequenz von 1KHz warnehmen. Hier ein Soundbeispiel mit einer SAW-Wellenform. Start 100Hz, Ende 5000Hz: http://soundcloud.com/rolfdegen/saw-sweeb Gruß Rolf
Datum:
// Die oberen 12Bit des Phasen-Akkus extrahieren // --------------------------------------------- ANDI phakku1, 0xF0 ; 1 Lower Nibble in Byte 0 abnullen LSR phakku2 ; 1 Division durch 8 (16-Bit) ROR phakku1 ; 1 LSR phakku2 ; 1 ROR phakku1 ; 1 LSR phakku2 ; 1 ROR phakku1 ; 1 |
Der KOMMENTAR ist falsch... extrahiert werden die 13Bit, wobei das unterste Bit immer 0 ist. Ich betone KOMMENTAR, weil der Code ansich richtig ist, aber auf den ersten Blick schwer zu durchschauen, weil der Kommentar falsch ist. Du brauchst sicher die 13Bit-Adressierung für den Sinus, wegen der 16Bit Wortlänge im Programmspeicher. Den Jitter kann man vermeiden durch Reduzierung der Akkumulator-Breite (nicht beim Akkumulieren, sondern beim Ausgeben der Saw, bzw. beim Adressieren des Wavetables) ab bestimmten Frequenzen. Also im Prinzip kann man es so machen, dass man zB. ab 500Hz immer das LSB nullt, ab 1000Hz nullt man dann das LSB und das nächst höhere, usw. Diese Grenz-Frequenzen kann man anhand des Phasen-Deltas setzen. Diese Methode ist im Prinzip immer ein Abrunden, was dazu führt, das der geringfügige Jitter wegbleibt, weil er weggerundet wird. Das hat aber auch Nachteile: 1. Man verliert bei höheren Frequenzen die Auflösung 2. Höhere Frequenzen werden leiser 3. Man erzeugt automatisch ein DC-Offset, was man berücksichtigen sollte, oder besser noch, gleich im Oscillator kompensiert. Software-Instrumente nutzen, um diese Problem generell zu umgehen größere Wavetable, so hat man zB. für niedrigere Frequenzen ein besser aufgelöste Wave als bei höheren. Im Schnitt teilt man diesen Wavetable in 8 Frequenzbereiche. Für so einen kleinen µC ist das aber undenkbar.
Datum:
Maik M. schrieb: > Den Jitter kann man vermeiden durch Reduzierung der Akkumulator-Breite > (nicht beim Akkumulieren, sondern beim Ausgeben der Saw, bzw. beim > Adressieren des Wavetables) ab bestimmten Frequenzen. Hallo Maik, das ist ein guter Tip. Werde ich Morgen gleich mal testen. Besten Dank. In Bezug auf den Kommentar: Der Phasenaccu hat eine Auflösung von 24Bit und ich benötige die oberen 12Bit für den Zugriff auf die 4KByte große Sinus-Tabelle im Speicher des Xmegas. Gruß Rolf
Datum:
Hallo Maik Hat leider nicht funktioniert. Der Phasen-Jitter bleibt unverändert. Aber vielleicht mach ich was falsch ??? Meinen Programmcode habe ich wegen der Übersicht etwas vereinfacht. Die markierte Zeile "ANDI phakku1,0b11111110" soll das Phasen-Jitter eliminieren indem sie das LSB im Low-Byte der Tabellenadresse löscht. Leider ohne Erfolg. Ich habe es auch mit anderen Werten versucht, aber ohne Erfolg. Der Phasen-Jitter bleibt.
//************************************************************** // ATMEL Studio 6 Inline Assembler-Routine // Soudausgabe auf DACA Chanal 0 // TimeR1 Interruptroutine: alle 25usec = 40.0 KHz Samplerate // // (Laufzeit: ?,??? µsec = ??? Takte bei 32MHz) // // // (c) 06.10.2012 Version 1.0 //************************************************************** #include "avr/io.h" .extern sound_out // Name der Assembler-Funktion .global TCC1_OVF_vect // Timer1 Interrupt-Vektor //--------------------------------------------------------------- // Benutzte Prozessor-Register (Definition als Namen) //--------------------------------------------------------------- dcoout0 = 16 ; R16 DCO-Out Byte 0 dcoout1 = 17 ; R17 Byte 1 phakku0 = 18 ; R18 Phasen-Akku Byte 0 phakku1 = 19 ; R19 Byte 1 phakku2 = 20 ; R20 Byte 2 delta0 = 21 ; R21 Phasen-Delta Byte 0 delta1 = 22 ; R22 Byte 1 delta2 = 23 ; R23 Byte 2 //--------------------------------------------------------------- // Prozessor-Register inkl. Status-Register sichern // Interrupt-Routine Timer1-Overflow (40.000Hz) //--------------------------------------------------------------- TCC1_OVF_vect: PUSH R0 ; 2 R0 auf Stack schieben IN R0, SREG ; 1 Status-Register über bereits gesichertes PUSH R0 ; 2 R0 auf Stack schieben PUSH R1 ; 2 R1 auf Stack schieben PUSH R16 ; 2 R16 auf Stack schieben PUSH R17 ; 2 R17 auf Stack schieben PUSH R18 ; 2 R18 auf Stack schieben PUSH R19 ; 2 R19 auf Stack schieben PUSH R20 ; 2 R20 auf Stack schieben PUSH R21 ; 2 R21 auf Stack schieben PUSH R22 ; 2 R22 auf Stack schieben PUSH R23 ; 2 R23 auf Stack schieben PUSH R30 ; 2 R30 auf Stack schieben (ZL) PUSH R31 ; 2 R31 auf Stack schieben (ZH) //=============================================================== // SUBTRAKTIVE KLANGSYSYNTHESE //=============================================================== SubSynthese: //--------------------------------------------------------------- // DCO-1 // * 24-Bit Akku-Breite // * 24-Bit Phasen-Delta (2,384185mHz/Unit) // * 12-Bit Sample //--------------------------------------------------------------- // Phasen-Akku 1 incrementieren // ---------------------------- LDS delta0, schrittweite1+0 ; 2 Phasen-Delta aus SRAM laden LDS delta1, schrittweite1+1 ; 2 LDS delta2, schrittweite1+2 ; 2 LDS phakku0, phaccu1+0 ; 2 Phasen-Akku aus SRAM laden LDS phakku1, phaccu1+1 ; 2 LDS phakku2, phaccu1+2 ; 2 ADD phakku0, delta0 ; 1 Phasen-Akku + Phasen-Delta ADC phakku1, delta1 ; 1 ADC phakku2, delta2 ; 1 STS phaccu1+0, phakku0 ; 2 Phasen-Akku in SRAM zurückschreiben STS phaccu1+1, phakku1 ; 2 STS phaccu1+2, phakku2 ; 2 // Die oberen 12Bit des Phasen-Akkus extrahieren // --------------------------------------------- ANDI phakku1, 0xF0 ; 1 Lower Nibble in Byte 0 abnullen LSR phakku2 ; 1 Division durch 8 (16-Bit) ROR phakku1 ; 1 LSR phakku2 ; 1 ROR phakku1 ; 1 LSR phakku2 ; 1 ROR phakku1 ; 1 // SAW-Sample über aktive Phase aus Wavetable laden // ------------------------------------------------- LDI R30, 0xFC ; 1 Basis-Adresse Saw-Tabelle (Low-Byte) LDI R31, 0x03 ; 1 (High-Byte) //******************************************************************************** ANDI phakku1,0b11111110 ; Phasen-Jitter eliminieren //******************************************************************************** ADD R30, phakku1 ; 1 Phasen-Pointer addieren ADC R31, phakku2 ; 1 LPM dcoout0, Z+ ; 3 Sample aus Wavetable laden (12-Bit) LPM dcoout1, Z ; 3 // -------------------------------------------------------------- // Ausgabe am DAC-Converter (DACA Chanal 0) // -------------------------------------------------------------- STS 0x0318, dcoout0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) STS 0x0319, dcoout1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) // -------------------------------------------------------------- // Prozessor-Register inkl. Status-Register wiederherstellen // -------------------------------------------------------------- POP R31 ; 2 R31 von Stack wiederherstellen (ZH) POP R30 ; 2 R30 von Stack wiederherstellen (ZL) POP R23 ; 2 R23 von Stack wiederherstellen POP R22 ; 2 R22 von Stack wiederherstellen POP R21 ; 2 R21 von Stack wiederherstellen POP R20 ; 2 R20 von Stack wiederherstellen POP R19 ; 2 R19 von Stack wiederherstellen POP R18 ; 2 R18 von Stack wiederherstellen POP R17 ; 2 R17 von Stack wiederherstellen POP R16 ; 2 R16 von Stack wiederherstellen POP R1 ; 2 R1 von Stack wiederherstellen POP R0 ; 2 Status-Register über R0 wieder OUT SREG, R0 ; 1 herstellen POP R0 ; 2 R0 von Stack wiederherstellen RETI ; 4 Return Interrupt und I-Flag quittieren // -------------------------------------------------------------- .end // |
Datum:
ANDI phakku1,0b11111110 ; Phasen-Jitter eliminieren |
Das bringt nichts, das unterste Bit ist bei deiner Addressierung immer
0, da du mit 13 Bit adressierst, nicht mit 12Bit. Jetzt bist du genau
auf den falschen Kommentar("Die oberen 12Bit des Phasen-Akkus
extrahieren") reingefallen, den ich dir mit dem letzen Post zeigen
wollte ;)
Diese Andrundungs-Maske ist etwas schwer zu bestimmen, aber evtl. gibt's
eine andere Lösung. Probier mal das:
//************************************************************** // ATMEL Studio 6 Inline Assembler-Routine // Soudausgabe auf DACA Chanal 0 // TimeR1 Interruptroutine: alle 25usec = 40.0 KHz Samplerate // // (Laufzeit: ?,??? µsec = ??? Takte bei 32MHz) // // // (c) 06.10.2012 Version 1.0 //************************************************************** #include "avr/io.h" .extern sound_out // Name der Assembler-Funktion .global TCC1_OVF_vect // Timer1 Interrupt-Vektor //--------------------------------------------------------------- // Benutzte Prozessor-Register (Definition als Namen) //--------------------------------------------------------------- dcoout0 = 16 ; R16 DCO-Out Byte 0 dcoout1 = 17 ; R17 Byte 1 phakku0 = 18 ; R18 Phasen-Akku Byte 0 phakku1 = 19 ; R19 Byte 1 phakku2 = 20 ; R20 Byte 2 delta0 = 21 ; R21 Phasen-Delta Byte 0 delta1 = 22 ; R22 Byte 1 delta2 = 23 ; R23 Byte 2 //--------------------------------------------------------------- // Prozessor-Register inkl. Status-Register sichern // Interrupt-Routine Timer1-Overflow (40.000Hz) //--------------------------------------------------------------- TCC1_OVF_vect: PUSH R0 ; 2 R0 auf Stack schieben IN R0, SREG ; 1 Status-Register über bereits gesichertes PUSH R0 ; 2 R0 auf Stack schieben PUSH R1 ; 2 R1 auf Stack schieben PUSH R16 ; 2 R16 auf Stack schieben PUSH R17 ; 2 R17 auf Stack schieben PUSH R18 ; 2 R18 auf Stack schieben PUSH R19 ; 2 R19 auf Stack schieben PUSH R20 ; 2 R20 auf Stack schieben PUSH R21 ; 2 R21 auf Stack schieben PUSH R22 ; 2 R22 auf Stack schieben PUSH R23 ; 2 R23 auf Stack schieben PUSH R30 ; 2 R30 auf Stack schieben (ZL) PUSH R31 ; 2 R31 auf Stack schieben (ZH) //=============================================================== // SUBTRAKTIVE KLANGSYSYNTHESE //=============================================================== SubSynthese: //--------------------------------------------------------------- // DCO-1 // * 24-Bit Akku-Breite // * 24-Bit Phasen-Delta (2,384185mHz/Unit) // * 12-Bit Sample //--------------------------------------------------------------- // Phasen-Akku 1 incrementieren // ---------------------------- LDS delta0, schrittweite1+0 ; 2 Phasen-Delta aus SRAM laden LDS delta1, schrittweite1+1 ; 2 LDS delta2, schrittweite1+2 ; 2 LDS phakku0, phaccu1+0 ; 2 Phasen-Akku aus SRAM laden LDS phakku1, phaccu1+1 ; 2 LDS phakku2, phaccu1+2 ; 2 ADD phakku0, delta0 ; 1 Phasen-Akku + Phasen-Delta ADC phakku1, delta1 ; 1 ADC phakku2, delta2 ; 1 STS phaccu1+0, phakku0 ; 2 Phasen-Akku in SRAM zurückschreiben STS phaccu1+1, phakku1 ; 2 STS phaccu1+2, phakku2 ; 2 // MyCo // hohes Delta-Wort durch 2 teilen LSR delta2 ; 1 ROR delta1 ; 1 // MyCo // 1/2 Delta von der Adressierung abziehen SUB phakku1, delta1 ; 1 SBC phakku2, delta2 ; 1 // Die oberen 12Bit des Phasen-Akkus extrahieren // --------------------------------------------- ANDI phakku1, 0xF0 ; 1 Lower Nibble in Byte 0 abnullen LSR phakku2 ; 1 Division durch 8 (16-Bit) ROR phakku1 ; 1 LSR phakku2 ; 1 ROR phakku1 ; 1 LSR phakku2 ; 1 ROR phakku1 ; 1 // SAW-Sample über aktive Phase aus Wavetable laden // ------------------------------------------------- LDI R30, 0xFC ; 1 Basis-Adresse Saw-Tabelle (Low-Byte) LDI R31, 0x03 ; 1 (High-Byte) ADD R30, phakku1 ; 1 Phasen-Pointer addieren ADC R31, phakku2 ; 1 LPM dcoout0, Z+ ; 3 Sample aus Wavetable laden (12-Bit) LPM dcoout1, Z ; 3 // -------------------------------------------------------------- // Ausgabe am DAC-Converter (DACA Chanal 0) // -------------------------------------------------------------- STS 0x0318, dcoout0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) STS 0x0319, dcoout1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) // -------------------------------------------------------------- // Prozessor-Register inkl. Status-Register wiederherstellen // -------------------------------------------------------------- POP R31 ; 2 R31 von Stack wiederherstellen (ZH) POP R30 ; 2 R30 von Stack wiederherstellen (ZL) POP R23 ; 2 R23 von Stack wiederherstellen POP R22 ; 2 R22 von Stack wiederherstellen POP R21 ; 2 R21 von Stack wiederherstellen POP R20 ; 2 R20 von Stack wiederherstellen POP R19 ; 2 R19 von Stack wiederherstellen POP R18 ; 2 R18 von Stack wiederherstellen POP R17 ; 2 R17 von Stack wiederherstellen POP R16 ; 2 R16 von Stack wiederherstellen POP R1 ; 2 R1 von Stack wiederherstellen POP R0 ; 2 Status-Register über R0 wieder OUT SREG, R0 ; 1 herstellen POP R0 ; 2 R0 von Stack wiederherstellen RETI ; 4 Return Interrupt und I-Flag quittieren // -------------------------------------------------------------- .end // |
Ist halt nur eine Idee, keine Ahnung ob das genau das macht, was ich meine.
Datum:
Mein Fazit: Das Jitter von 25µsec (Taktzyklus für den Zähler des Phasenaccus) werde ich prinzipiell nicht los. Beim Sinus ist das auch kein großes Problem. Dieser wird sauber und störungsfrei wiedergegeben . Aber für die anderen Wellenformen wzB. Sägezahn, Puls oder Rechteck ist die Softwaregenerierte DDS-Synthese bei einer Taktrate von 25µsec nicht zu gebrauchen. Muss mir also was anderes überlegen. Gruß Rolf
Datum:
Der Ansatz den Rolf meinte von wegen den Phasenakku zu nullen nach einem Wellenformdurchgang ist doch im Prinzip richtig. Man darf den Akku an sich aber nicht nullen. Man muß, sobald ein Neustart der Wellenform erfolgt sich den aktuellen Phasenakku sichern und ihn als Offset zum eigentlichen Phasenakku betrachten. Wenn der Phasenakku (gerade bei höheren Frequenzen) eben nicht mit dem Index 0 auf den Wavetable bzw Saw-Erzeugung liegt verschiebt man diesen für den Durchlauf der Wellenform. Man hat dann aber dennoch das Problem das die Wellenform eben nicht voll "ausgefahren" wird. Die einzige Lösung die mir vllt einfallen würde wäre die Samplefrequenz soweit zu erhöhen das der Jitter nicht mehr auftritt und dann per Down-Sampling auf die Ausgabefrequenz zu shiften, aber das heißt dann auch den Wavetable entsprechend aufzubohren.
Datum:
Ich habe gerade nochmal gestöbert. http://musicdsp.org/archive.php?classid=1#90 Vllt hilft das weiter. Ist zwar eher für Software-Synthies und DSP, aber ich denke das ein oder andere könnte evtl nützlich sein.
Datum:
Dieser Jitter wird immer auftreten, sobald
Wiedergabefrequenz > Samplerate/Wavetable_Länge |
Bei ihm ist's 40.000 / 4096, also ab ca. 10Hz wird der Jitter auftauchen. Der ist zwar ab dieser Frequenz noch sehr gering, wird aber größer, je höher die Frequenz ist. Das kann man aber umgehen, indem man bei höheren Frequenzen einen kleinere Wavetable verwendet. Oder man adressiert bei höheren Frequenzen einfach mit geringerer Auflösung (nullen der niedrigen Bits). Den Drift/Jitter kann man sich in etwa errechnen:
Drift in Prozent = (Wiedergabefrequenz*Wavetable_Länge)/(Samplerate*DAC_Auflösung)*100 |
Datum:
Hallo Danke an alle. Zum Vorschlag von Maik:
// MyCo // hohes Delta-Wort durch 2 teilen LSR delta2 ; 1 ROR delta1 ; 1 // MyCo // 1/2 Delta von der Adressierung abziehen SUB phakku1, delta1 ; 1 SBC phakku2, delta2 ; 1 |
Die Code-Änderungen hat leider nichts gebracht. Der Phasen-Jitter bleibt. Ich werde es wohl mit der Idee von Maik, bei höheren Frequenzen kleinere Wavetables zu verwenden, versuchen. Zum Hinweis von Rene "Bandlimited sawtooth synthesis": Ich hab Gestern mit Oliver Gillert, dem Entwickler des genialen Shruthi Synth (http://mutable-instruments.net/shruthi1) gemailt. Ich habe ih gefragt, wie er das so mit der Sounderzeugung im Shruthi macht und eine Antwort erhalten, die ich hier mit Hilfe von Google übersetzt habe: "Für die klassischer analoger Wellenformen auf dem Shruthi (Saw, Rechteck, Dreieck), verwende ich bandbegrenzten Wavetables . (Anmerkung von mir: Wolfgang hat es oben in einen der letzten Beiträge schon vorhergesagt hat). Die Wavetables werden durch integrierte bandbegrenzte Impulse (sinc-Funktionen) für verschiedene f0 / fs-Verhältnis Abstand mit 2 ** (16 / 12,0) Verhältnisse. Als Ergebnis gibt es ein Wavetable für jede Gruppe von 16 Noten. Um zu vermeiden, grobe Übergänge I Interpolieren zwischen jeder Wavetable. Für die höheren Töne, die Wellenform nähert sich einer sinusförmigen - von der erwartet wird, weil einer quadratischen Welle bei 8 kHz auf 44 kHz abgetastet ist in der Tat eine Sinuswelle (die dritte Oberwelle bei 24kHz oberhalb Nyquist-Frequenz). Hier ist eine Kurve der Wellenformen aus der Shruthi bei unterschiedlichen Frequenzen (50, 125, 320, 800, 2k, 5k, 12k): http://i.imgur.com/nZmMx.png Die quadratischen und Sägezahnwellen gefärbt sind - ich denke, diese Wellenformen sind viel interessanter als die "reinen" Sägezahn und "pure" eckig Welle. Die PWM-Wellenform wird durch Summieren von zwei bandbegrenzten Sägezahn erhalten mit einer Phasendifferenz - die Phasendifferenz steuert die PWM-Verhältnis. Ich habe versucht mit minBLEP und es verwendet, 70% der CPU. Auf der Shruthi-1 ist war keine Option, aber in Ihrem Projekt, das Sie mit einem XMega bei 32 MHz, so dass es machbar sein, um minBLEP verwenden. Ich würde empfehlen, diese Option wählen, da es klingt sehr gut und kann tun hardsync! minBLEP nicht tun können Dreiecke, aber Sie können bandbegrenzte Wavetables für diese Verwendung. Die Shruthi-1-Code ist Open Source und finden Sie Antworten auf Ihre zu finden Fragen Sie sich den Code: https://github.com/pichenettes/shruthi-1/" Auf http://www.experimentalscene.com/articles/minbleps.php habe ich eine kleine Anleitung (C++ Quellcode) für einen "minBLEP"-Oszilator gefunden. Mal schaun wie ich das für einen Xmega nutzen kann. Gruß Rolf
Datum:
Angehängte Dateien:Hallo Ich wollte mal wissen wie sich so ein Square-Sound mit Bandbegrenzung (eng. band-limited square) auf meinem Synthi so anhört und habe mir die Mühe gemacht zwei Hörbeispiele aufzunehmen. Die Aufnahmen wurden am LowPass-Filterausgang bei offenem Filter gemacht. Die 8Bit Square-Sounds werden aus einer 256 Byte großen Waveform-Tabelle mit 40KHz Sampling-Frequenz an den DAC Ausgang gesendet. Bild 1: 1KHz Square-Sound 8Bit (Rechteck) ohne Bandbegrenzung auf dem AVR-Synthi Link soundcloud.com: http://soundcloud.com/rolfdegen/square-0 Bild 2: 1KHz Square-Sound (aus dem Shruthi-Synth gestohlen ) mit Bandbegrenzung auf dem AVR-Synthi. Link soundcloud.com: http://soundcloud.com/rolfdegen/bandlimited-square-0 Wie man hört, ist der Square-Sound mit Bandbegrenzung viel sauberer und ohne Nebengeräusche. Mal schaun wie ich als "Nicht Studierter" so einen minBlep-Oszillator auf meinen Xmega implementieren kann. Gruß Rolf
Datum:
Hallo Ich habe mich dazu entschieden, fertige Bandbegrenzte Wavefiles zu benutzen und diese in den Flash-Speicher des Xmegas zu schreiben. Dadurch spar ich mir das ganze Rumrechnen mit Sinus und Cosinus und haste nicht gesehen zur Laufzeit. Die Bandbegrenzten Wavefiles liegen mir als bin.Datei vor und ich möchte diese als ext. Datei in meinen Quellcode mit einbinden. Leider weis ich nicht wie das in Atmel Studio funktioniert. Ich habe mir ersteinmal damit geholfen, das ich die Wave-Datei über einen Hexeditor als Hexadezimal-Tabelle exportiere und in meinen C-Quellcode kopiere. Das funktioniert problemlos. Dadurch wird aber der Quellcode sehr lang und unübersichtlich. Ein Tip wär nicht schlecht. Danke euch. Gruß Rolf
Datum:
Angehängte Dateien:@Rolf Ich hab gestern mal mit bandlimited waveforms auf dem PC rumexperimentiert. Ich habe dabei einen Oszillator programmiert der 64 einzelne Sinüsse zusammenrechnet und deren Frequenz-Anteile (also 64 Koeffizienten) vorgegeben werden können. Den Sinus selbst hole ich über eine Tabelle. Ich habe mal deine Erkenntnis darin verwurstet das der Sinus auch bei "ungenauen" Frequenzen keine "Sprünge" macht und somit eine "ganz normale" DDS genutzt. Also das Ergebnis klingt doch schon ganz gut, selbst wenn man bei tiefen Frequenzen eine Art Tiefpass mit raushört, das aber eben daran liegt das ich "nur" 64 Anteile berechne, die Wellenform aber noch hörere Frequenzen beinhalten würde. (wenn meine Grundfrequenz beispielsweise 100Hz ist, wäre der letzte Frequenzanteil bei 6,4kHz). Das Ergebnis klingt aber recht brauchbar, und ich werd da auch mal was weiter probieren. Das ganze ist somit quasi eine einfache Additive Synthese. Das was für mich son bissl den Reiz dabei ausmacht ist das ich die Frequenzanteile zur Laufzeit ändern kann, und somit die ausgangswellenform schon dynamisch gestalten kann (z.b. zwischen Sägezahn und Rechteck "morphen") oder einer Wellenform einfach Oberwellen hinzufügen kann, die z.b. von einer Hüllkurve gesteuert werden. Anbei mal die zusammengehackte Datei (ist noch viel Float drin, lässt sich aber problemlos durch integer ersetzen), in der allerdings der Sinus noch nicht drin ist (der ist bei mir in einer separaten Datei und hat den Sinus-Kurvenzug von 0 bis pi/2).
Datum:
@Rene: Füge mal vor der Zeile:
rT = fOscGetSine (ulPhi); |
diese eine:
if (ulPhi & 80000000)break; |
Damit wird verhindert, das Frequenzen über der Nyquisit generiert werden. Diese Zeile:
if (rFrq > 23000.0f) { rFrq = 20000.0f; } |
ist wohl nur ein Provisorium, oder? Besser wäre es, bei einer hohen Basis-Frequenz, den Osc komplett zu umgehen.
Datum:
@Maik >if (rFrq > 23000.0f) { rFrq = 20000.0f; } Da war noch ein Fehler drin. Hatte das ganze ursprünglich für 48kHz ausgelegt, bis mir dann bei der Durchsicht eingefallen ist das meine Soundkarte auf 44,1kHz läuft :-S >if (ulPhi & 0x80000000) break; Stimmt. Gute Idee. Vor allem hätte ich dann auch einen anhaltspunkt wieviele Sinüsse ich bei hohen Frequenzen effektiv durchrechnen muß, damit die 64. Oberwelle noch unterhalb meiner Nyquist Frequenz liegt. >ist wohl nur ein Provisorium, oder? Besser wäre es, bei einer hohen >Basis-Frequenz, den Osc komplett zu umgehen. Wie meinst das "komplett umgehen" ?
Datum:
Angehängte Dateien:Hallo Rene Hab ein einfaches Programm namens "WinFilter" für die Filterberechnung gefunden. Vielleicht hilfts es dir :) Bild: WinFilter Download Link: http://www.winfilter.20m.com/ Gruß Rolf
Datum:
@Rolf Danke für den Link. Das Problem bei solchen Filter Tools ist das sie zwar Koeffizienten ausspucken, aber den Weg wie man diese dann selbst berechnen kann eben nicht. Und das wäre gerade für Synthesizer/Mischpulte/Effektgeräte wo sich die Filter ja in Frequenz/Güte/Typ/Charakteristik dynamisch ändern können interessant.
Datum:
@Rolf Die musicdsp-Seite hab ich vor einiger Zeit schon entdeckt. Daher kam ich ja auf die bandlimited-Geschichte. Ich glaub das ich da auch die Neuüberarbeitung meiner Filter-klamotten her hab (Koeffizientenseitig). Ist schon recht lesenswert die Seite. Daher dachte ich das dir das vllt bei deinem Problemchen evtl hilfreich sein könnte.
Datum:
Ich habe bei diesen Problemen wieder viel interessantes gelernt aber ich bin nicht so der Mathetyp und mich schreckt der ganze Berechnungskram eher ein wenig ab. Zumal der Xmega in meinem Projekt noch andere Aufgaben nebenbei erledigen soll wz. Midi-Daten empfangen, Daten zum Touch-Display senden und empfangen, Analoge Filter steuern uvm. Später soll es auch eine Möglichkeit geben, die Soundbank von einer SD-Karte in den 8MB SDRAM Speicher des Xplained Board zu laden. Zur Zeit arbeite ich an der Soundbank für meinen Synthi. Ich habe im Internet einige Bandlimited Wavetables gefunden, die ich in meine Soundbank integriert habe. Somit bleibt meinem Xmega-Prozessor die Berechnung wärend der Laufzeit erst einmal erspart. Hier ein Code-Ausschnitt vom Shruthi Synth:
// ------- Band-limited PWM -------------------------------------------------- void Oscillator::RenderBandlimitedPwm(uint8_t* buffer) { uint8_t balance_index = U8Swap4(note_ - 12); uint8_t gain_2 = balance_index & 0xf0; uint8_t gain_1 = ~gain_2; uint8_t wave_index = balance_index & 0xf; const prog_uint8_t* wave_1 = waveform_table[ WAV_RES_BANDLIMITED_SAW_1 + wave_index]; wave_index = U8AddClip(wave_index, 1, kNumZonesHalfSampleRate); const prog_uint8_t* wave_2 = waveform_table[ WAV_RES_BANDLIMITED_SAW_1 + wave_index]; uint16_t shift = static_cast<uint16_t>(parameter_ + 128) << 8; // For higher pitched notes, simply use 128 uint8_t scale = 192 - (parameter_ >> 1); if (note_ > 64) { scale = U8Mix(scale, 102, (note_ - 64) << 2); scale = U8Mix(scale, 102, (note_ - 64) << 2); } phase_increment_ = U24ShiftLeft(phase_increment_); BEGIN_SAMPLE_LOOP phase = U24AddC(phase, phase_increment_int); *sync_output_++ = phase.carry; *sync_output_++ = 0; if (sync_input_[0] || sync_input_[1]) { phase.integral = 0; phase.fractional = 0; } sync_input_ += 2; uint8_t a = InterpolateTwoTables( wave_1, wave_2, phase.integral, gain_1, gain_2); a = U8U8MulShift8(a, scale); uint8_t b = InterpolateTwoTables( wave_1, wave_2, phase.integral + shift, gain_1, gain_2); b = U8U8MulShift8(b, scale); a = a - b + 128; *buffer++ = a; *buffer++ = a; size--; END_SAMPLE_LOOP } |
Viele Ideen kann man sich auch auf der Website des Shruthi Synth abkucken. Olivier Gillert der Macher des Shruthi Synths hat seine Entwicklungsarbeit für jederman frei zugänglich gemacht. Das Ding ist einfach genial. Er arbeitet z.Zt. an einer mehrstimmigen Version des Shruthis. Link zur Shruthi Website: http://mutable-instruments.net/ Gruß Rolf
Datum:
Rene B. schrieb: >>ist wohl nur ein Provisorium, oder? Besser wäre es, bei einer hohen >>Basis-Frequenz, den Osc komplett zu umgehen. > > Wie meinst das "komplett umgehen" ? Das bezog sich auf diese Zeile:
if (rFrq > 23000.0f) { rFrq = 20000.0f; } |
Die ja soviel macht wie: Bei einer zu hohen Frequenz, generiere eine völlig andere. Das ist ungünstig, weil der Osc. dann evtl. sinnlos eine disharmonie spielt. Mit "Osc. umgehen" meine ich, das man ihn bei einer zu hohen Frequenz garnicht erst berechnet, sondern 0 (Stille) ausgibt.
Datum:
@Maik Achso meintest das. Ja, so gesehen ist das nen Proviorium. Und Frequenzanteile oberhalb von fS/2 zu Nullen wird noch eingebaut ...
Datum:
Hallo Bezüglich der Wave-Files habe von Humfrey aus dem CC2-Forum einen guten Vorschlag erhalten. Die Deklaration der Wave-Daten als Hexadezimal Werte in eine extra Quelltext-Datei schreiben und diese dann per #include in den normalen C-Quelltext mit einbinden. Funktioniert bestens. Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen Ich war mal wieder fleißig und habe die letzten Wochen am AVR-Synthi gebastelt bzw programmiert. Herausgekommen ist eine neu gestaltete Menü-Seite für die DCO Einstellung. Was eigentlich sehr einfach klingt, hat mir doch etwas Kopfzerbrechen bereitet. Die Einstellung der DCO's sollte übersichtlich und einfach zu bedienen sein. Bild 1: DCO-Menü Herausgekommen ist eine Wellenform Auswahl-Matrix für beide DCO's um ver- schiedene Wellenformen zu kombinieren. Mit der internen Wellenform-Tabelle (ca. 22KByte) bestehend aus den Bandlimited Waves (Square, Saw, Triangle) und Synthezizer-Waves sind zur Zeit etwas mehr als 500 Wellenform Kombi- nationen möglich. Soundbeispiele wirds hier später geben. Ferne besteht die direkte Möglichkeit, mit dem Detune-Regler die DCO's gegeneinander zu verstimmen um einen Schwebungeffekt im Sound zu erreichen. Mit den Schaltern "Soft" und "Hard" kann man die Stärke des Reglers einstellen. Der "Sync"-Button synchronisiert beide DCO's wieder und stellt den Detune-Wert wieder auf null. Bild 2: Auswahl der Synthesizer-Waves Eine etwas schwierige Aufgabe war die Wellenform Auswahl für die Synthesizer- Waves. Das habe ich durch ein Untermenü bewerkstelligt. Klickt man auf den "WAV"-Button öffnet sich eine neue Menüseite für die Auswahl der Waves und der grafischen Ansicht der Wellenform. Bild 3: Wellenform-Kombination einer Saw-Waveform und Synthesizer-Waveform Gruß Rolf
Datum:
Angehängte Dateien:Hier noch ein paar Bilder von speziellen Wellenform-Kombinationen. Gruß Rolf
Datum:
@Rolf Sieht ja recht schick aus. Bin mal gespannt auf die Sound-Beispiele. Aber ich hab mal ne Frage zum Sync. Heißt Sync nicht das ein Oszillator beim Nulldurchgang den anderen Synchronisiert, also diesen dann ebenfalls neustartet ? Das macht im Falle das beide Detune = 0 haben in dem Sinne keinen Sinn, da beide dann ja exakt diesselbe Frequenz haben. Aber interessant wird das meine ich dann sobald der zu Synchronisierende Oszillator höher schwingt (egal ob mit einem Detune im Halbton bzw Cent-Halbton) Hauptsache höher als der erste Oszillator, denn sonst würde die Wellenform ja nicht voll ausschwingen können. Aber ich meine das gerade das Synchronisieren den Sound was fetter bzw charakteristischer macht. Was vllt auch noch ne schöne Variante für deinen Oszillator wäre (wenn du ohnehin schon 2 davon hast ;-)) wäre Ringmodulation. Also einfach die beiden Oszillator-Ausgänge miteinander multiplizieren. Das würde die 500 möglichen Kombinationen noch ein bissl aufstocken :-) Und wäre ne prima Klangquelle für nen analogen Filter. Ich weiß ja nicht wie es in deine Programmierung passt. Aber mal so als Vorschlag.
Datum:
Ich hab gerade mal in meinen AVR-Synth code geschaut, wie ich das so aufgebaut habe. Die Klangerzeugung lief bei mir über einen "morphable wavetable". Der Wavetable selbst hatte 8 Wellenformen, wobei man immer von einer Wellenform zur nächsten morphen kann. Das ging im Prinzip so:
Ausgang = (Wellenform[index][sample] * (255-morph) + Wellenform[(index+1)&0b111][sample] * morph) morph = Byte (0..255) index = Byte (0..7) sample = Wavetable Akku |
Multiplikation war bei mir eine spezielle Funktion, die Word mit Byte Multipliziert hat, und als Ergebnis kam Word raus (die untersten 8Bit des 24Bit Ergebnisses werden ignoriert) Ich habe auch mit einem Filter experimentiert, der so auschaute:
v0 = R*C*v0 + C*in - C*v1; v1 = R*C*v1 + C*v0; output = v1; C = Cutoff (0..255) R = Resonance(255..0) |
Hierbei habe ich die Multiplikation R*C in einem nebenherlaufenden, sehr langsamen Timer erledigt, weil es nicht so kritisch war. Soweit ich mich erinnern kann, war der Filter sehr gut, und dank dem Hardware-Multiplikator auch von den Zyklen her recht vertretbar.
Datum:
Rene B. schrieb: > Heißt Sync nicht das ein Oszillator > beim Nulldurchgang den anderen Synchronisiert, also diesen dann > ebenfalls neustartet ? Hallo Rene. Ja das ist richtig. Ich sollte meine Sync Funktion wohl besser umbenennen, denn sie setzt lediglich beide Oszillator auf die gleiche Frequenz und den gleichen Phasenwinkel zurueck. Ich bin mir allerdings nicht im klaren darueber, ob das musikalisch gesehen ueberhaupt sinnvoll ist. Nemen wir mal an, das mit dem Einschalten des Synthis beide Oszillatoren mit gleicher Frequenz und Phase starten. Nun verstelle ich im DCO Menue den Detune Regler und dadurch schwingen beide Oszillatoren mit unterschiedlicher Frequenz und als Ergebnis ensteht am Ausgang eine gewollte Amplitdenmodulation. Mit dem alleinigen Zuruecksetzen des Detune Reglers auf null, schwingen zwar beide Oszillatoren wieder mit gleicher Frequenz aber nicht unbedingt synchron zueinander, was ebenfalls zu einer Amplitudenmodulaton am Ausgang fuehrt. Aus diesem Grund stelle ich mit dem Sync-Button auch die Phasen beider Oszillatoren zurueck. Danke fuer den Tip mit der Ringmodulation. Werde ich Morgen gleich umsetzen :)
Datum:
Hab die Preview von damals wiedergefunden und raufgeladen: http://soundcloud.com/maikmenz/avr-8bit-filter Der Reverb stammt nicht vom Synth, den hab ich nachträglich draufgepackt. Der Filter in der Demo ist der den ich erwähnt habe. In der Demo hört mach auch das Wavetable morphing von Sägezahn zu Rechteck und zurück.
Datum:
Angehängte Dateien:Hallo Irgendwie sieht bei mir die Ringmodulation auf dem Oszi (Bild 1) etwas merkwürdig aus. Hier mein Code:
//------------------------------------------------------------------- // Ringmodulation Sample1 (dco1out0 8Bit) * Sample2 (dco2out0 8Bit) // Multiplikationsergebnis durch 16 teilen für 12Bit Ausgabe auf DAC //------------------------------------------------------------------- Ringmod: MUL dco1out0, dco2out0 ; DCO1_out * DCO2_out MOVW dco1out0, R0 LSR dco1out1 ; Ausgabewert auf 12Bit (div 4) ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 STS 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) STS 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Der Sound klingt aber wie eine Ringmodulation. Ich wunder mich halt über das Aussehen der Wellenform. Diese entspricht nicht der üblichen aus dem Lehrbuch wie zB in Bild 2. Mach ich was flasch in meiner Berechnung oder ist das so korrekt. Mir scheint es so, als ob der Nullpunkt der Sinuskurve nach unten verschoben ist. Die Frequenz von Oszillator 1 (dco1) beträgt 200Hz und von Oszillator 2 (dco2) 6000Hz. Die beiden Sinuswerte stammen direkt aus einer 8Bit Sinus-Tabelle im Flash des ATxmegas. Gruß Rolf
Datum:
Dein Code operiert nur im positivem Bereich, das ist generell schlecht für DSP.
Datum:
du müsstest deinen Wavetable als Signed speichern, und von da an alle Unsigned-Operationen durch Signed-Operationen ersetzen. Dann am Ende, vor der Ausgabe konvertierst du dann erst wieder zurück auf Unsigned
Datum:
Mach deine Wellenformen und die Multiplikation signed. Wie Maik schon meinte : Nur unsigned (also positiv) ist eher schlecht, selbst wenns sich nach dem gewünschten Ergebnis anhört. Du wirst dann tlw Probleme bekommen mit nem DC-Offset. Dadurch das der Nullpunkt dann ja eben irgendwo liegt, in Abhängigkeit von der Beschaffenheit deines Ausgangssignals.
Datum:
Die Tabellen kann ich nicht ändern. Besteht nicht die Möglichkeit den ausgelesenen Tabellenwert als signed Byte zu konvertieren. Die Auflösung würde dadurch auf 7Bit reduziert.
Datum:
das kannst du machen, aber hast dann halt wieder einen Zyklus weniger. Konvertieren von Signed nach Unsigned und umgekehrt geht relativ einfach:
subi register,0x80 |
Allerdings musst du bei Signed-Operationen bedenken, dass das höchstwertige Bit immer das Vorzeichen-Flag ist. Operationen wie lsl, lsr, ror, rol, usw. darfst du auf das höchstwertige Byte eines Signed nicht anwenden, weil sich sonst evtl. das Vorzeichen ändert. Für LSR gibt es allerdings schon ersatz: ASR. Für LSL hingegen gibt es keinen, aber da kannst du sowas machen:
bst reg,7 bld reg,6 lsl reg |
Dabei bleibt das Vorzeichen erhalten. Auch musst du bei der Multiplikation aufpassen, schau dir dazu die Operationen MULS und MULSU an.
Datum:
Angehängte Dateien:Hallo Ich habe es wie folgt gelöst:
//------------------------------------------------------------------- // Ringmodulation Sample1 (dco1out0 8Bit) * Sample2 (dco2out0 8Bit) // Multiplikationsergebnis durch 16 teilen für 12Bit Ausgabe auf DAC //------------------------------------------------------------------- Ringmod: subi dco1out0,0x80 ; make signed Wave subi dco2out0,0x80 MULS dco1out0, dco2out0 ; Multipl signed DCO1_out * DCO2_out MOVW dco1out0, R0 ; save Result ldi dco2out0,0x80 ; make unsigned Wave add dco1out1,dco2out0 LSR dco1out1 ; DCO_out reduction to 12Bit (div 4) ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 STS 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) STS 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Das Ergebnis sieht jetzt richtig aus (Bild). Allerdings ist die Ausgangsspannung nur noch halb so groß wie vorher. Eine Division durch drei vor der DAC-Ausgabe funktioniert nicht. Dadurch entstehen wilde Bit-Muster. Gruß Rolf Gruß Rolf
Datum:
Das die Ausgangsspannug nur noch halb so groß ist, liegt daran das du 2 Vorzeichenbits hast. Da aber durch die Multiplikation ja nur noch 1 VZ-Bit übrigbleibt geht dir in der Dynamik ja ein Bit flöten. Du müsstest quasi eienn Shift nach links machen um die Ausgangsspannung wieder auf de vollen Bereich zu bringen.
Datum:
Das funktioniert eben nicht. Egal wo ich es mache. Es ensteht am Ausgang ein Wildes Bit-Chaos.
... ldi dco2out0,0x80 ; make unsigned Wave add dco1out1,dco2out0 LSR dco1out1 ; DCO_out reduction to 12Bit (div 4) ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 LSL dco1out0 ; Ausgabewert multi 2 ROL dco1out1 STS 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) STS 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Datum:
Vorzeichenbehaftetes Multiplizieren ist etwas tricky, wie Rene schon schrieb, verliert man 1 Bit. Genauer: S XXX XXXX * S XXX XXXX = SS YY YYYY YYYY YYYY Wobei S das Vorzeichenbit ist, X und Y sind Wertebits. Probier mal folgendes (bisher ungetestet):
//------------------------------------------------------------------- // Ringmodulation Sample1 (dco1out0 8Bit) * Sample2 (dco2out0 8Bit) // Multiplikationsergebnis durch 16 teilen für 12Bit Ausgabe auf DAC //------------------------------------------------------------------- Ringmod: subi dco1out0,0x80 ; make signed Wave subi dco2out0,0x80 MULS dco1out0, dco2out0 ; Multipl signed DCO1_out * DCO2_out ; Multiply signed word with 2 bst r1,7 bld r1,6 lsl r0 rol r1 ; Make unsigned word subi r1,0x80 ; save Result movw dco1out1:dco1out0, r1:R0 LSR dco1out1 ; DCO_out reduction to 12Bit (div 4) ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 STS 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) STS 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
wenn das überhaupt funktionieren sollte, dann müssen dco1out1:dco1out0 Registerpaare sein, ansonsten würde MOVW generell fehlschlagen.
Datum:
hier nochmal was zum Testen... etwas abgekürzt:
//------------------------------------------------------------------- // Ringmodulation Sample1 (dco1out0 8Bit) * Sample2 (dco2out0 8Bit) // Multiplikationsergebnis durch 16 teilen für 12Bit Ausgabe auf DAC //------------------------------------------------------------------- Ringmod: subi dco1out0,0x80 ; make signed Wave subi dco2out0,0x80 muls dco1out0, dco2out0 ; Multipl signed DCO1_out * DCO2_out ; remove first sign bit andi r1, 0x7F ; shift 3 times left lsr r1 ror r0 lsr r1 ror r0 lsr r1 ror r0 ; make unsigned 12bit subi r1, 0x08 ; save Result movw dco1out1:dco1out0, r1:r0 sts 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) sts 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Datum:
Danke Maik. Es funktioniert. Ich musste es allerdings etwas anpassen.
Ringmod: subi dco1out0,0x80 ; make signed Wave subi dco2out0,0x80 MULS dco1out0, dco2out0 ; Multipl signed DCO1_out * DCO2_out ; Multiply signed word with 2 bst r1,7 bld r1,6 lsl r0 rol r1 ; Make unsigned word //subi r1,0x80 ; save Result //movw dco1out1:dco1out0, r1:R0 movw dco1out0,r0 subi dco1out1,0x80 LSR dco1out1 ; DCO_out reduction to 12Bit (div 4) ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 LSR dco1out1 ROR dco1out0 STS 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) STS 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Datum:
das mit dem abkürzen (2. Code-Beitrag von mir) wird wohl nicht funktionieren... jetzt bin ich mit dem Signed-Kram auch durcheinandergekommen.
Datum:
evtl. geht's so, vielleicht:
//------------------------------------------------------------------- // Ringmodulation Sample1 (dco1out0 8Bit) * Sample2 (dco2out0 8Bit) // Multiplikationsergebnis durch 16 teilen für 12Bit Ausgabe auf DAC //------------------------------------------------------------------- Ringmod: subi dco1out0,0x80 ; make signed Wave subi dco2out0,0x80 muls dco1out0, dco2out0 ; Multipl signed DCO1_out * DCO2_out ; shift 3 times left lsr r1 ror r0 lsr r1 ror r0 lsr r1 ror r0 ; make unsigned 12bit subi r1, 0x88 ; save Result movw dco1out1:dco1out0, r1:r0 sts 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) sts 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Datum:
Der Compiler meckert immer bei "subi r1, 0x88" Meldung: Error 1 register number above 15 required Dieser Befehl funktioniert nur mit den oberen 16 Registern. Ich hab es jetzt so geschrieben:
Ringmod: subi dco1out0,0x80 ; make signed Wave subi dco2out0,0x80 muls dco1out0, dco2out0 ; Multipl signed DCO1_out * DCO2_out ; shift 3 times left lsr r1 ror r0 lsr r1 ror r0 lsr r1 ror r0 ; make unsigned 12bit //subi r1, 0x88 ; save Result //movw dco1out1:dco1out0, r1:r0 movw dco1out0,r0 subi dco1out1,0x88 sts 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) sts 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Datum:
aja... wohl weil das nicht auf dem Register erlaubt ist. Vielleicht so:
//------------------------------------------------------------------- // Ringmodulation Sample1 (dco1out0 8Bit) * Sample2 (dco2out0 8Bit) // Multiplikationsergebnis durch 16 teilen für 12Bit Ausgabe auf DAC //------------------------------------------------------------------- Ringmod: subi dco1out0,0x80 ; make signed Wave subi dco2out0,0x80 muls dco1out0, dco2out0 ; Multipl signed DCO1_out * DCO2_out ; shift 3 times left lsr r1 ror r0 lsr r1 ror r0 lsr r1 ror r0 ; save Result movw dco1out1:dco1out0, r1:r0 ; make unsigned 12bit subi dco1out1, 0x88 sts 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) sts 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Edit: ja, so wie du's jetzt ergänzt hast, ist's genau wie ich es hier vorgeschlagen habe.
Datum:
Danke Maik für deine tolle Unterstützung. Ich sach mal Schüß bis zum nächsten Problem :) und schönen Sonntag noch. Gruß Rolf
Datum:
Hallo Ich komme einfach nicht weiter in Bezug auf die Tune-Funktion des Oszillators in meinem AVR-Synthi. Um die Midi-Note 1-127 in eine Tonfrequenz umzuwandeln greife ich auf eine 16Bit Tabelle mit 127 Frequenzwerten im Flash-Speicher des Xmegas zu. Wenn ich zB Oszillator2 eine Oktave tiefer stellen möchte, dann teile ich einfach den Frequenzwert der Midi-Note. Funktioniert auch problemlos und über alle Oktaven sehr genau. Aber wie kann ich den Oszillator um einen Halbton verstellen. Ich möchte später mit der Tune-Funktion den Oszillator um +-24 Halbtöne verstellen können. Alle meine Berechnungen liefern "Krumme Werte" so das eine genaue Einstellung nicht möglich ist.
//*********************************************** // Frequenz_Tune // Wiedergabefrequenz mit Tune-Werten berechnen // // noten_nr = Midi-Key_Nr. //*********************************************** void frequency_tune() { frequenz = pgm_read_word (&(midi_frequenz[noten_nr])); schrittweite1 = (__uint24) 411 * frequenz; // Phasendelta für Oszillator1 schrittweite2 = (__uint24) 411 * frequenz >> 1; Phasendelta für Oszillator2 (eine Oktave niedriger) |
Gruß Rolf
Datum:
Hallo Ich hab das jetzt mal so gelöst:
//*********************************************** // Frequenz_Tune // Wiedergabefrequenz mit Tune-Werten berechnen //*********************************************** void frequency_tune() { frequenz = pgm_read_word (&(midi_frequenz[noten_nr])); schrittweite1 = (__uint24) 411 * frequenz; print_16bit_number(frequenz,20,20,3); uint8_t halbton = 8; uint32_t temp_schrittweite2 = 0; temp_schrittweite2 = (uint32_t)schrittweite1 >> 1; temp_schrittweite2 = (uint32_t)temp_schrittweite2 / 12; temp_schrittweite2 = (uint32_t)temp_schrittweite2 * halbton; schrittweite2 = (__uint24) schrittweite1 + temp_schrittweite2; |
Um die Rundungen bei der Berechnung der Schrittweite2 (Phasendelta) für Oszillator2 so gering wie möglich zu halten, habe ich den Zahlenwert auf 32Bit erhöht. Gruß Rolf
Datum:
Du gehst die Sache sehr Ressourcenfressend an. Ich habe diesen Teil bei meinem Synth auch in Assembler gemacht. Es ist nicht kompliziert, und man kann mit der richtigen Technik auch sehr viel Ressourcen sparen. Bei mir schaut das ungefähr so aus: Ich habe 1 Table, der enthält 14 Akkumulatoren-Deltas, nennen wir ihn mal "PitchTable". Der erste Wert ist das Delta für B-1, der 14. Wert ist für das C+1, dazwischen sind endsprechend die anderen Noten-Werte. Eingänge sind: inNote(0..127), inSemi(-24..24), inFine(-128..127) Ausgang ist outPitch
fNote = inNote + inSemi; if (fNote & 0x80)fNote = 0;// <-- Überschlag vermeiden fOctave = fNote / 12; // <-- Ganzzahlig fPitchIndex = fNote % 12; // <-- Ganzzahlig fPitch1 = PitchTable[fPitchIndex+1] << fOctave; fPitch2 = PitchTable[fPitchIndex+(inFine>0) ? 2 : 0] << fOctave; fFineByte = abs(inFine) << 1; outPitch = ( fPitch1 * (255-fFineByte) ) >> 8 + ( fPitch2 * (fFineByte) ) >> 8; |
Das is Pseudocode. Aber die Voregehensweise ist im Groben: Oktave werden geschiftet, Semi einfach ganz am Anfang auf die Notennummer addiert, Fine wird linear zwischen zwei benachbarten Akkumulatoren-Werten interpoliert.
Datum:
Ah Käse, geht noch fixer:
fNote = inNote + inSemi; if (fNote & 0x80)fNote = 0;// <-- Überschlag vermeiden fOctave = fNote / 12; // <-- Ganzzahlig fPitchIndex = (fNote % 12) + 1; // <-- Ganzzahlig fPitch1 = PitchTable[fPitchIndex]; fPitch2 = PitchTable[fPitchIndex+(inFine>0) ? 1 : -1]; fFineByte = abs(inFine) << 1; outPitch = ( fPitch1 * (255-fFineByte) ) >> 8 + ( fPitch2 * (fFineByte) ) >> 8; outPitch <<=fOctave; |
Datum:
Danke für deine Hilfe. Werde deinen Vorschlag ausprobieren und wenns klappt oder auch nicht noch einmal hier melden. Gruß Rolf
Datum:
Hallo Maik Die Routine funktioniert leider nicht so wie sie soll. Als Ergebnis erhalte ich immer Frequenzen im Bereich von 0-5Hz über die spielbaren Oktaven. Mein Code:
//********************************************* // // PhaccuDelta-Value from Midi Note-Nr. 0-11 // // Phaccu_Delta = 411 * Midi-Note Frequenz // //********************************************* uint16_t phaccu_delta [14] = { 3171, // B-1 3360, // C1 // Midi-Note 0-11 3560, 3771, 3996, 4233, 4485, 4752, 5034, 5334, 5651, 5987, 6343, 6720 // B+1 }; //*********************************************** // Frequenz_Tune // Wiedergabefrequenz mit Tune-Werten berechnen //*********************************************** void frequency_tune() { uint8_t fNote; uint8_t inNote = noten_nr; char inSemi = 0; char inFine = 0; uint8_t fFineByte = 0; char fOctave = 0; uint8_t fPitchIndex; __uint24 fPitch1; __uint24 fPitch2; __uint24 outPitch; fNote = inNote + inSemi; if(fNote & 0x80) fNote = 0; fOctave = fNote / 12; fPitchIndex = (fNote % 12) + 1; fPitch1 = phaccu_delta[fPitchIndex]; fPitch2 = phaccu_delta[fPitchIndex + (inFine > 0) ? 1 : -1]; fFineByte = abs(inFine) << 1; outPitch = ( fPitch1 * (255-fFineByte) ) >> 8 + ( fPitch2 * (fFineByte) ) >> 8; outPitch <<=fOctave; schrittweite1 = (__uint24)outPitch; |
Änder ich die Zeile mit Null shift so ab:
outPitch = ( fPitch1 * (255-fFineByte) ) >> 0 + ( fPitch2 * (fFineByte) ) >> 8; |
erhalte ich fast die richtige Frequenzen (A = 438.5 Hz). Der Wert für die Oktavierung funktioniert leider auch nicht und hat keine Auswirkungen auf die Wiedergabefrequenz. Gruß Rolf
Datum:
Das mit der Oktavierung war eine falsche Aussage von mir. Ich sehe gerade das eine Oktavierung nur über den Semiton-Werte funktioniert. Also Semiton-Wert zb "12" wäre eine Oktave höher und "-12" eine Oktave niedriger.
Datum:
Ich habe so meine Probleme mit C/C++. Da muss man sehr auf die Typenbreite achten, besonders bei dieser Zeile:
outPitch = ( fPitch1 * (255-fFineByte) ) >> 8 + ( fPitch2 * (fFineByte) ) >> 8; |
Ich glaube C/C++ rechnet hier in 24bit, die Multiplikation aus 24bit mit 8bit ergibt allerdings 32bit und der Compiler convertiert das runter indem er die höheren (wichtigeren) 8bit weglässt. Das müsste irgendwie mit Typecasting lösbar sein, allerdings bin ich da nicht so Fit. Evtl. geht es so:
outPitch = uint24_t(( (uint32_t)fPitch1 * (255-fFineByte) ) >> 8 + ((uint32_t)fPitch2 * (fFineByte) ) >> 8); |
Datum:
@Maik, aber das lineare Interpolieren zwischen zwei Halbton-Pitches müsste doch eigentlich fehlerhaft sein da es ja eine Exponentialfunktion ist die die Frequenzen zwischen den Oktaven und auch entsprechend den Halbtönen bestimmt. Wie genau das Ohr diese unterschiede wahrnehmen kann weiß ich nicht, aber ich denke das man bei ner abweichung von 50cent schon hörbare Frequenzunterschiede wahrnehmen müsste zwischen tatsächlicher Frequenz und interpolierter Frequenz. Ansonsten ist das Verfahren ja richtig und auch recht platzsparend. Ich wär bzw bin ganz bruteral mit ner Tabelle über 120 Halbtöne und 8/16/32 Abstufungen drangegangen, aber das ist im Prinzip ja quatsch, da sich die Oktaven ja durch Shiften bilden lassen, und man dann von den höchsten Inkrementen bzw Schrittweiten ausgeht und runtershiftet.
Datum:
Was passiert, wenn du die Zeile:
outPitch = ( fPitch1 * (255-fFineByte) ) >> 8 + ( fPitch2 * (fFineByte) ) >> 8; |
durch diese ersetzt:
outPitch = fPitch1; |
bzw:
outPitch = fPitch2; |
Datum:
Ja das wollte ich gerade machen. outPitch = (__uint24)fPitch1 << fOctave; = 440,1Hz outPitch = (__uint24)fPitch2 << fOctave; = 261,6Hz
Datum:
Rene B. schrieb: > @Maik, > > aber das lineare Interpolieren zwischen zwei Halbton-Pitches müsste doch > eigentlich fehlerhaft sein da es ja eine Exponentialfunktion ist die die > Frequenzen zwischen den Oktaven und auch entsprechend den Halbtönen > bestimmt. Ja im Prinzip ist es falsch, aber man muss halt Kompromisse eingehen. Zur Not könnte man einen Exponential-Tabelle nutzen, aber richtig berechnen kann man das auf einem AVR nicht.
Datum:
Rolf Degen schrieb: > Ja das wollte ich gerade machen. > > outPitch = (__uint24)fPitch1 << fOctave; = 440,1Hz > outPitch = (__uint24)fPitch2 << fOctave; = 261,6Hz ja, dann hat es irgendwas mit der Typenkonvertierung in der Zeile zu tun. Wie gesagt, das war nie mein Ding :)
Datum:
Ohne Typkonvertierung könnte es so gehen: outPitch = ( (fPitch1>>8) * (255-fFineByte) ) + ( (fPitch2>>8) * (fFineByte) ); Allerdings produziert das massive Rundungsfehler
Datum:
Damit ändern sich die Notenwerte in einer Oktave nicht mehr. Sie bleiben gleich und verdoppeln sich bei der nächsten Oktave.
Datum:
Vielleicht geht's ja so:
//********************************************* // // PhaccuDelta-Value from Midi Note-Nr. 0-11 // // Phaccu_Delta = 411 * Midi-Note Frequenz // //********************************************* uint16_t phaccu_delta [14] = { 3171, // B-1 3360, // C1 // Midi-Note 0-11 3560, 3771, 3996, 4233, 4485, 4752, 5034, 5334, 5651, 5987, 6343, 6720 // B+1 }; //*********************************************** // Frequenz_Tune // Wiedergabefrequenz mit Tune-Werten berechnen //*********************************************** void frequency_tune() { uint8_t fNote; uint8_t inNote = noten_nr; char inSemi = 0; char inFine = 0; uint8_t fFineByte; uint8_t fOctave; uint8_t fPitchIndex; uint16_t fPitch1; uint16_t fPitch2; int16_t fPitchDiff; __uint24 outPitch; fNote = inNote + inSemi; if(fNote & 0x80) fNote = 0; fOctave = fNote / 12; fPitchIndex = (fNote % 12) + 1; fPitch1 = phaccu_delta[fPitchIndex]; fPitch2 = phaccu_delta[fPitchIndex + (inFine > 0) ? 1 : -1]; fPitchDiff = (int16_t) (fPitch2-fPitch1); fFineByte = ((uint8_t)(abs(inFine))) << 1; outPitch = (__uint24)(((((int32_t)fPitch1)<<8) + ((int32_t)fPitchDiff*(int32_t)fFineByte)) >> 8); outPitch <<=fOctave; schrittweite1 = outPitch; ... |
Datum:
Ich habe das Programm etwas abgeändert und es kommen jetzt zumindest die richtigen Frequenzen heraus. Allerdings funktioniert es mit "inFine"-Werten noch nicht.
//*********************************************** // Frequenz_Tune // Wiedergabefrequenz mit Tune-Werten berechnen //*********************************************** void frequency_tune() { uint8_t fNote; uint8_t inNote = noten_nr; char inSemi = 0; char inFine = 10; uint8_t fFineByte = 0; uint8_t fOctave = 0; uint8_t fPitchIndex; uint16_t fPitch1; uint16_t fPitch2; __uint24 outPitch; fNote = inNote + inSemi; if(fNote & 0x80) fNote = 0; fOctave = fNote / 12; fPitchIndex = (fNote % 12) + 1; fPitch1 = phaccu_delta[fPitchIndex]; fPitch2 = phaccu_delta[fPitchIndex + 1];// (inFine > 0) ? 1 : -1]; fFineByte = abs(inFine) << 1; outPitch = (__uint24)( fPitch1 * (255-fFineByte) ) >> 8 + ( fPitch2 * (fFineByte) ) >> 8; outPitch = (__uint24)fPitch2 << fOctave; schrittweite1 = outPitch; |
Ups.. du warst schneller. Ich werde deine Programm jetzt testen.
Datum:
Dein Programm funktioniert soweit. Nur bei den inFine-Werten stimmt was nicht. Ich bekomm bei positiven und negativen Werten immer eine niedrige Frequenzen heraus. Zum Beispiel: inFine = 0 = 440Hz inFine = 10 = 426Hz inFine = -10 = 426Hz
Datum:
ups ... Auskommtierung vergessen ersetze
fPitch2 = phaccu_delta[fPitchIndex + 1];// (inFine > 0) ? 1 : -1]; |
durch
fPitch2 = phaccu_delta[fPitchIndex + (inFine > 0) ? 1 : -1]; |
Datum:
Die Programmzeile hatte ich bereits wieder geändert. Ich habe mir den fPitch2 Wert mal angesehen. Der Wert (3360) ist bei inFine = +10 bei jeder Midi-Note gleich groß.
Datum:
Das kann nicht sein, der müsste sich bei jeder Note um 1 Index verschoben zu Pitch1 bewegen.
Datum:
Midi-Note = 440Hz (Messung: 440Hz) inFine = 0 fPitch1 = 5651 fPitch2 = 3360 fPitchDiff = 63245 Midi-Note = 440Hz (Messung: 426.3Hz) inFine = 10 fPitch1 = 5651 fPitch2 = 3360 fPitchDiff = 63245 Midi-Note = 440Hz (Messung: 426.1Hz) inFine = -10 fPitch1 = 5651 fPitch2 = 3360 fPitchDiff = 63245
Datum:
Also das die beiden fPitch's bei +10 und -10 cent diesselben sind kann ja nicht sein. fPitch2 müsste ja ggü fPitch1 den Pitch für einen Halbton unter fPitch1 liegen, oder ?
Datum:
argh... auf ein Neues...
//********************************************* // // PhaccuDelta-Value from Midi Note-Nr. 0-11 // // Phaccu_Delta = 411 * Midi-Note Frequenz // //********************************************* uint16_t phaccu_delta [14] = { 3171, // B-1 3360, // C1 // Midi-Note 0-11 3560, 3771, 3996, 4233, 4485, 4752, 5034, 5334, 5651, 5987, 6343, 6720 // B+1 }; //*********************************************** // Frequenz_Tune // Wiedergabefrequenz mit Tune-Werten berechnen //*********************************************** void frequency_tune() { uint8_t fNote; uint8_t inNote = noten_nr; char inSemi = 0; char inFine = 0; uint8_t fFineByte; uint8_t fOctave; uint8_t fPitchIndex; uint16_t fPitch1; uint16_t fPitch2; int16_t fPitchDiff; __uint24 outPitch; fNote = inNote + inSemi; if(fNote & 0x80) fNote = 0; fOctave = fNote / 12; fPitchIndex = (fNote % 12); fPitch1 = phaccu_delta[fPitchIndex+1]; if (inFine > 0)fPitchIndex+=2; fPitch2 = phaccu_delta[fPitchIndex]; fPitchDiff = (int16_t) (fPitch2-fPitch1); fFineByte = ((uint8_t)(abs(inFine))) << 1; outPitch = (__uint24)(((((int32_t)fPitch1)<<8) + ((int32_t)fPitchDiff*(int32_t)fFineByte)) >> 8); outPitch <<=fOctave; schrittweite1 = outPitch; ... |
Datum:
Ja es funktioniert jetzt. Prima :) Der Notenwerte liegen zwar jetzt etwas höher A 440Hz = gemessen 440,5 aber das ist ok. Kann man mit dem inFine-Wert -1 aber korregieren. Danke für deine großartige Hilfe. Das Ganze bringt mich in meinem Projekt wieder einen großen Schritt nach vorne. Schönen Tag noch und lieben Gruß Rolf
Datum:
Angehängte Dateien:Hallo Ich habe Heute die Menü-Seite für die DCO-Einstellung fertig gestellt (siehe Bild). Jeder Oszillator kann in +-24 Semitone-Schritten (entspricht +- 2 Oktaven) verstellt werden. Zusätzlich kan man mit der Fine-Einstellung (Schrittweite +-100 Cent) den Oszillator zwischen zwei Halbtönen verstimmen. Mit den Tasten "+" und "-" ist außerdem eine genauere Einstellung der Parameter möglich. Nochmals besten Dank an Maik. Ohne seine großartige Unterstützung hätte es nicht funktioniert. Bild: DCO-Einstellung im AVR-Synthi MfG Rolf
Datum:
Hallöchen.. Damits hier nicht zu langweilig wird, gibts zur Abwechslung ein paar Demo-Sound. Was in den Sounds noch fehlt, ist die Filter und Amplituden-Modulation sowie FM und Synchronisation der Oszillatoren. AVR-Synthi Demo-Sounds Link: http://soundcloud.com/rolfdegen/avr-demo-31102012
Datum:
Sehr schönes Demo. Vor allem gefällt mir der Sound ab 11:30. Aber ist der Filter wirklich noch nicht mir drin ? Tlw klingt es ja schon so :-) Aber echt sehr schön gemacht. Weiter so. Bin mal gespannt auf die restlichen Features wie Ringmod/Sync/FM und eben alles noch mit Filtern zusammen :-)
Datum:
Hallo Ich bin gerade dabei die Sync-Funktion für die Oszillatoren zu programmieren. Ich weis allerdings nicht ob mein Ansatz richtig ist (siehe Code).
//=============================================================== // SUBTRAKTIVE KLANGSYSYNTHESE //=============================================================== SubSynthese: //--------------------------------------------------------------- // DCO-1 // * 24-Bit Akku-Breite // * 24-Bit Phasen-Delta (2,384185mHz/Unit) // * 8-Bit Sample //--------------------------------------------------------------- // Phasen-Akku1 incrementieren // ---------------------------- LDS delta0, schrittweite1+0 ; 2 Phasen-Delta1 aus SRAM laden LDS delta1, schrittweite1+1 ; 2 LDS delta2, schrittweite1+2 ; 2 LDS phakku0, phaccu1+0 ; 2 Phasen-Akku1 aus SRAM laden LDS phakku1, phaccu1+1 ; 2 LDS phakku2, phaccu1+2 ; 2 ADD phakku0, delta0 ; 1 Phasen-Akku1 + Phasen-Delta1 ADC phakku1, delta1 ; 1 ADC phakku2, delta2 ; 1 // DCO2 sync BRCC test_01 ; setze Phasen-Akku2 auf null wenn Phasen-Akku1 Überlauf CLR r21 STS phaccu2+0, r21 STS phaccu2+1, r21 STS phaccu2+2, r21 test_01: STS phaccu1+0, phakku0 ; 2 Phasen-Akku1 in SRAM zurückschreiben STS phaccu1+1, phakku1 ; 2 STS phaccu1+2, phakku2 ; 2 // Basis-Adresse für Wavetable laden // ------------------------------------------------- LDS R30, wavetable1+0 ; 1 Startadr. Wave-Table (Low-Byte) LDS R31, wavetable1+1 ; 1 (High-Byte) // Sample1 aus Wavetable laden (8Bit Auflösung) // ------------------------------------------------------------------ BL_Wave1: clr R21 ADD R30, phakku2 ; 1 Adresse Sample-Nr. ADC R31, r21 ; 1 LPM dco1out0, Z+ ; 3 Sample aus Wavetable laden (8-Bit) LPM dco1out1, Z ; 3 clr dco1out1 // Phasen-Akku2 incrementieren // ---------------------------- DCO2: LDS delta0, schrittweite2+0 ; 2 Phasen-Delta aus SRAM laden LDS delta1, schrittweite2+1 ; 2 LDS delta2, schrittweite2+2 ; 2 LDS phakku0, phaccu2+0 ; 2 Phasen-Akku aus SRAM laden LDS phakku1, phaccu2+1 ; 2 LDS phakku2, phaccu2+2 ; 2 ADD phakku0, delta0 ; 1 Phasen-Akku + Phasen-Delta ADC phakku1, delta1 ; 1 ADC phakku2, delta2 ; 1 STS phaccu2+0, phakku0 ; 2 Phasen-Akku in SRAM zurückschreiben STS phaccu2+1, phakku1 ; 2 STS phaccu2+2, phakku2 ; 2 // Basis-Adresse für Wavetable laden // ------------------------------------------------- LDS R30, wavetable2+0 ; 1 Basis-Adresse Saw-Tabelle (Low-Byte) LDS R31, wavetable2+1 ; 1 (High-Byte) // Sample1 aus Wavetable laden // ------------------------------------------------- BL_Wave2: clr R21 ADD R30, phakku2 ; 1 Adresse Sample-Nr. ADC R31, r21 ; 1 LPM dco2out0, Z+ ; 3 Sample aus Wavetable laden (8-Bit) LPM dco2out1, Z ; 3 clr dco2out1 //----------------------------------------------------------- // Addition Sample1 + Sample2 //----------------------------------------------------------- Wave_out: ADD dco1out0,dco2out0 ; DCO1_out + DCO2_out ADC dco1out1,dco2out1 LSL dco1out0 ; Ausgabewert auf 12Bit (mul 3) ROL dco1out1 LSL dco1out0 ROL dco1out1 LSL dco1out0 ROL dco1out1 // -------------------------------------------------------------- // 12Bit Ergebnis zum DAC-Converter (DACA Chanal 0) // -------------------------------------------------------------- DAC_out: STS 0x0318, dco1out0 ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318) STS 0x0319, dco1out1 ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319) |
Für eine Info wäre ich dankbar.
Datum:
Meine AVR-Assembler sind zwar recht begrenzt, aber im Prinzip müsste es so gehen. Sobald ein Überlauf im Phasenakku 1 festegestellt wird, wird Phasenakku 2 genullt. Damit wird OSC2 durch OSC1 synchronisiert (was ja auch angestrebt ist :-)).
Datum:
Ja super. Dann werde ich das im Prinzip so und zusätzlich mit einer Abfrage für die Sync-Funktion in meinem Programm implementieren. Gruß Rolf und schönes Wochenende.
Datum:
Hallo Ich brauch mal wieder Hilfe. Ich möchte in Assembler auf einen 256 Byte großen Ringbuffer in meinem Main-Programm (in C) zugreifen. So wie ich es versuche funktioniert es leider nicht. Ein Rat wäre sehr hilfreich. Schon mal Danke im Vorraus. LG Rolf Ring-Buffer (FIFO) in C:
//****************************** // write data in to FIFO-Buffer //****************************** buf_data = 170; test_buffer[wrbuf_pointer] = buf_data; // save data in to buffer wrbuf_pointer++; // inc Buffer-Pointer buf_data = 0; buf_status = 1; _delay_ms(10); print_8bit_number(buf_data,120,70,2); |
Lesen eines Bytes aus dem Ringbuffer in der Assembler-Routine und anschließend zurückschreiben in buf_data. buf_dat wird im Main-Programm ausgewertet.
// Buffer Testfunktion lds r20, buf_status; ; Bufferstatus prüfen (ist 1 wenn Byte vorhanden) cpi r20, 1 ; brne next ; wenn ungleich Sprung zu next ldi r20, lo8(rdbuf_pointer) ; ein Datenbyte aus dem Buffer lesen sts buf_data, r20 ; und wieder abspeichern next: |
Datum:
habe zwar von dem gemixe von C und ASM nicht soviel Ahnung, aber die Zeile
ldi r20, lo8(rdbuf_pointer) ; ein Datenbyte aus dem Buffer lesen |
schaut schon merkwürdig aus. Wenn der Ringbuffer im SRAM liegt, müsste die Adressierung 16Bit haben. Keine Ahnung was rdbuf_pointer überhaupt ist, aber wäre es ein Pointer in den SRAM (Elementindex eingeschlossen ), dann würdest du mit ldi nur die Hälfte der Addresse bekommen. Das ist jetzt nur wilde Spekulation, aber vielleicht geht es so:
ldi XL, low(rdbuf_pointer)
ldi XH, high(rdbuf_pointer)
ld r20, X
|
Datum:
Danke. Werde deinen Vorschlag gleich testen. rdbuf_pointer ist der Adresszeiger bein lesen des Buffers und wrbuf_pointer beim schreiben in den Buffer.
Datum:
Funktioniert leider nicht. Bekomme die Fehlermeldung :"Error 1 garbage at end of line" Die Dekleration der Buffer-Variablen sieht bei mir im Main-Programm so aus: // Test-Buffer (Lesezugriff erfolgt in ASM-Teil) volatile uint8_t test_buffer[256]; // Receive Buffer for Wave-Data uint8_t wrbuf_pointer = 0; // Write_Pointer volatile uint8_t rdbuf_pointer = 0; // Read_Pointer volatile uint8_t buf_data = 0; // Bufferdaten uint8_t buf_status = 0; // buf_status = 1 wenn Daten im Buffer Die Buffer-Funktion soll später für die Soundausgabe in der ASM-Routine genutz werden. Die Sounddaten werden alle im Main-Programm vorberechnet und im Buffer gespeichert, wo sie dann im ASM-Teil ausgegeben werden.
Datum:
Hallo Ich konnte es jetzt so lösen:
// Buffer Testfunktion lds r20, buf_status; ; Bufferstatus prüfen (ist 1 wenn Byte vorhanden) cpi r20, 1 ; brne next ; wenn ungleich Sprung zu next ldi ZL, lo8(test_buffer) ; Startadresse des Test-Buffers laden ldi ZH, hi8(test_buffer) lds r17,(rdbuf_pointer) ; Position des Lesezeigers laden add ZL, r17 ; und zur Startadresse hinzu addieren ldi r16,0 adc ZH, r16 ld r20, Z ; ein Byte aus dem Test-Buffer laden sts buf_data, r20 ; und für Testzweck speichern next: |
In ZL+ZH befinden sich die Start-Adresse des Test-Buffer. In r17 die Position des Lesezeiger der auf das aktuelle Datenbyte zeigt. Gruß Rolf
Datum:
da war ich doch nah dran... würde mich interessieren, was bei meinem falsch war. Das low/high?
Datum:
Ich programmiere unter atmel Studio 6 und der Assembler ist da etwas eigen. Statt low/high muss lo8/Hi im Quellcode stehen. LG Rolf
Datum:
rolf degen schrieb: > Ich programmiere unter atmel Studio 6 und der Assembler ist da etwas > eigen. Statt low/high muss lo8/Hi im Quellcode stehen. > > LG Rolf Ich meine lo8 und hi8
Datum:
Hallo Ich habe die Soundausgabe des AVR-Synthis testweise über einen 256 Byte großen Ring-Puffer geleitet (siehe Code). Der Puffer wird im Main-Programm (siehe Code) ständig mit Sample-Daten aus einer 8Bit Sinus-Tabelle befüllt und in der Interruptroutine für die Soundausgabe geleert. Soweit funktioniert das auch ganz nett. Aber sobald ich Eingaben und andere Dinge auf dem Touch-Display mache, bekommt der Puffer nicht mehr genug Daten und es treten Fehler in der Soundausgabe auf. Viele Funktionen für das Touch-Display benötigen mehr Zeit als der Puffer es erlaubt. Die maximale Pufferzeit beträgt 6.4 msec bis der Puffer leer ist. In der Main-Schleife wird ständig der Füllstand geprüft und nach Bedarf wieder gefüllt. Wenn der Prozessor aber z.Zt. mit anderen Dingen wzB mit der Display-Ausgabe und Auswertung der Touch-Eingaben beschäftigt ist, läuft der Puffer leer und kann nicht rechtzeitig wieder befüllt werden. Man müsste jetzt also hergehen und in den Display-Routinen eine Füllstandsabfrage des Puffers integrieren. Sobald die Füllstandsanzeige den "Beinahe"-Leerstand signalisiert, wird die Display-Routine unterbrochen und der Puffer wieder befüllt. Mal schaun wie ich das umsetze. Das Ganze müsste dann später genauso mit den Routinen für die Soundberechnung gemacht werden. Da kommt Freude auf.. ASM-Code: Ring-Puffer für die Soundausgabe
//**************************************************************
// ATMEL Studio 6 Assembler-Routine
// Soudausgabe auf DACA Chanal 0
// Timer1 Interruptroutine: alle 25usec = 40.0 KHz Samplerate
//
// (CPU ATxmega128A1 Clock 32MHz)
//
// Testversion Sound-Puffer 66 Prozessorzyklen = 2,062 µsec
//
//**************************************************************
#include "avr/io.h"
.extern sound_out // Name der Assembler-Funktion
.global TCC1_OVF_vect // Timer1 Interrupt-Vektor
//---------------------------------------------------------------
// Definition und verwendete Prozessor-Register
//---------------------------------------------------------------
temp = 16 ; R15 Temp-Register für Berechnungen
sample_low = 17 ; R16 Sample Low-Byte
sample_high = 18 ; R17 Sample High-Byte
//---------------------------------------------------------------
// Prozessor-Register inkl. Status-Register sichern
// Interrupt-Routine Timer1-Overflow (40.000Hz)
//---------------------------------------------------------------
TCC1_OVF_vect:
PUSH R0 ; 2 R0 auf Stack schieben
IN R0, SREG ; 1 Status-Register über bereits gesichertes
PUSH R0 ; 2 R0 auf Stack schieben
PUSH R1 ; 2 R1 auf Stack schieben
PUSH R16 ; 2 R16 auf Stack schieben
PUSH R17 ; 2 R17 auf Stack schieben
PUSH R18 ; 2 R18 auf Stack schieben
PUSH R30 ; 2 R30 auf Stack schieben (ZL)
PUSH R31 ; 2 R31 auf Stack schieben (ZH)
; 17 Zyklen
//------------------------------------------------------------
// Sample aus dem Ring-Puffer laden
//------------------------------------------------------------
ldi ZL, lo8(sample_puffer) ; 1 Puffer-Startadr. laden
ldi ZH, hi8(sample_puffer) ; 1
lds temp,(rd_pointer) ; 2 Puffer-Lesezeiger laden
add ZL, temp ; 1 und als Offset zur Puffer-Startadr. addieren
ldi temp,0 ; 1
adc ZH, temp ; 1
ld sample_low, Z ; 3 lade Datenwert in R16
ldi sample_high, 0 ; 1 lösche High-Byte im Sample-Word
; 11 Zyklen
//-----------------------------------
// 8Bit Sample auf 12Bit erhöhen
// Multiplikation mit 16
//-----------------------------------
LSL sample_low ; 1 Ausgabewert auf 12Bit (mul 16)
ROL sample_high ; 1
LSL sample_low ; 1
ROL sample_high ; 1
LSL sample_low ; 1
ROL sample_high ; 1
LSL sample_low ; 1
ROL sample_high ; 1
; 8 Zyklen
//------------------------------------
// Sample-Ausgabe auf 12Bit DAC
//------------------------------------
STS 0x0318, sample_low ; 2 L-Byte to DAC-Register (CH0DATAL Adr. 0x0318)
STS 0x0319, sample_high ; 2 H-Byte to DAC Register (CH0DATAH Adr. 0x0319)
; 4 Zyklen
//-------------------------------------
// Puffer-Lesezeiger inc
//-------------------------------------
lds temp,rd_pointer ; 2 Puffer-Lesezeiger inc
inc temp ; 1
sts rd_pointer, temp ; 2 und sichern
; 5 Zyklen
// --------------------------------------------------------------
// Prozessor-Register inkl. Status-Register wiederherstellen
// --------------------------------------------------------------
POP R31 ; 2 R31 von Stack wiederherstellen (ZH)
POP R30 ; 2 R30 von Stack wiederherstellen (ZL)
POP R18 ; 2 R18 von Stack wiederherstellen
POP R17 ; 2 R17 von Stack wiederherstellen
POP R16 ; 2 R16 von Stack wiederherstellen
POP R1 ; 2 R1 von Stack wiederherstellen
POP R0 ; 2 Status-Register über R0 wieder
OUT SREG, R0 ; 1 herstellen
POP R0 ; 2 R0 von Stack wiederherstellen
RETI ; 4 Return Interrupt und I-Flag quittieren
; 21 Zyklen
// --------------------------------------------------------------
.end
//
|
C-Code: Puffer-Funktion in der Main-Programm Schleife
//------------------------------------ Main-Loop --------------------------------------- while(1) { //----------------------------------------------------- // Wenn sich Sample-Puffer leert, dann // Daten aus der Sinus-Tabelle nach schieben //----------------------------------------------------- while (rd_pointer != wr_pointer) // Wenn beide Puffer-Zeiger ungleich { // dann ist freier Platz im Puffer buf_data = pgm_read_byte (&(sinus_8Bit[sample_index])); // Sample aus Sinus-Tabelle laden sample_puffer[wr_pointer] = buf_data; // Sample in Puffer schreiben wr_pointer++; if (sample_index < 255) { sample_index++; } else sample_index = 0; } //_delay_ms(6); // maximale Wartezeit bis Puffer leer ( ein Sample 25µsec * 256 = 6,4msec) get_encoder(); // Drehgeber abfragen touch_panel(); // Touch-Panel abfragen mididata_avail(); // Prüfe ob Midi-Daten im Empfangspuffer midi_play(); // Midi-Daten spielen } } //*********************************** END Program ************************************** |
Noch ein Tip. Wer eine sehr gute Befehlsbeschreibung der AVR-Befehle für die Assembler-Programmierung benötig findet diese hier: http://www.avr-roboter.de/controller/befehle/besch... Gruß Rolf
Datum:
@Rolf
Wie wäre es wenn du in der Main Loop das Funktionskonglomerat
"get_encoder, touch_panel, mididata_available, midi_play" immer nur pro
durchlauf einmal aufrufst.
Quasi eine Statemachine die erst get_encoder, dann touch_panel, dann
mididata_available und dann midi_play aufruft ?
also etwa so :
char state = 1;
while (1)
{
while (rd_pointer != wr_pointer)
{
...
}
switch (state)
{
case 1 : state = 2; get_encoder (); break;
case 2 : state = 3; touch_panel (); break;
case 3 : state = 4; mididata_available (); break;
case 4 : state = 1; midi_play (); break;
}
}
Ich weiß zwar nicht wie lange die einzelnen Funktionen brauchen, aber
vllt bietet es sich an längere Funktionen (vor allem wenn Verzögerungen
im Spiel sind) ebenfalls über eine Statemachine zu realisieren. Der
Vorteil ist das du dann nur dann was machen mußt, wenn auch wirklich was
zu tun ist, und du ersparst dir so Wartezeiten die den Prozi dann
komplett blockieren. Ein weiterer Nebeneffekt ist das solche
"Salami"-Funktionen eine gewisse Nebenläufigkeit mitbringen. Sprich : Es
wird quasi ein eigener "Task" daraus, der je nachdem wie er programmiert
ist eben keine anderen Aufgaben blockiert.
Datum:
Angehängte Dateien:Hallo Rene Ich hab das vorläufig etwas anders gelöst. Der Hinweis von Franz und Wolfgang aus dem CC2-Forum war die Lösung. Ich habe in die Routine für das Senden der Daten zum Display eine Abfrage für den Soundpuffer integriert (siehe Code). Jetzt funktioniert die gleichzeitige Display-Steuerung und Soundausgabe ohne Probleme. Verzögerungen bei der Ansteuerung des Displays sind mir kaum aufgefallen. Code: Routine zum Senden der Daten ans Display
//************************************** // Ein Byte über SPI zum Display senden // SPI Datenrate 2MHz // ************************************* void spi_send (unsigned char data) { fuellstand = wr_pointer - rd_pointer; // Füllstand Soundpuffer prüfen if (fuellstand < 50) // wenn < 50 Soundpuffer füllen { sound_puffer(); } else _delay_us(100); // wenn Soundpuffer nicht befüllt wird, // dann warte 100µsec bis Display bereit für den Datenempfang // (nur notwendig wenn SPI-Datentransfer schneller als 100KHz) SPIC.DATA = data; // ein Byte zum Display senden while(!(SPIC.STATUS & (1 << SPI_IF_bp))){} // wartet ca. 4µsec bis Byte gesendet wurde } |
Soundpuffer Routine
//--------------------------------------------- // Sound-Puffer füllen //--------------------------------------------- void sound_puffer() { uint8_t i; // Anzahl der Samples für die Befüllung uint8_t sample; // Sample aus der Sinus-Tabelle for (i=0;i<200;i++) { sample = pgm_read_byte (&(sinus_8Bit[sample_index])); // Sample aus Sinus-Tabelle laden sample_puffer[wr_pointer] = sample; // Sample in Puffer schreiben wr_pointer++; // Schreibzeiger des Soundpuffers +1 sample_index++; // Sample-Index für Datenposition in Sinustabelle inc PORTA.OUT |= (1<<PIN0); // Für Testzweck: Portbit High PORTA.OUT &= ~ (1<<PIN0); // Portbit Low } } |
Bild 1: Kanal 1 (Oben) Portbit signalisiert die Übertragung von 200 Bytes an den Soundbuffer in ca. 230µsec Kanal 2 (Unten) Sinus-Wave aus dem Soundpuffer Gruß Rolf
Datum:
Hallo Ich verkaufe meinen beiden Original CEM3320 Filterbausteine. Geprüft und kaum benutzt. Lagen bei mir in der Schublade auf einer Iso-Matte. Alter ca. 10 Jahre. Da ich in meinem Synthi-Projekt die SSM2044 einsetze sind die CEM3320 überflüssig. Preis ist Verhandlungssache. Gruß Rolf Achso.. hät ich beinahe vergessen. Zur Zeit teste ich die Speicheranbindung des 8MByte großen SDRAM auf Xplained-Board das ich in meinem AVR-Synthi als Wave-Speicher verwenden will. Die Transverleistung des Speicherinterface im Xmega zum 8MByte SDRAM liegt bei beachtlichen 1.4Mbyte in der Sekunde. Für so einen 8Bitter eine stolze Leistung. Falls alles nach meinen Vorstellungen funktioniert, soll der XMega-Prozessor verschiedene 16Bit Waveforms nach dem Systemstart vorrausberechnen und in dem 8MByte SDRAM zwischen speichern. Per Timer-Interrupt werden die Wave-Daten aus dem Speicher gelesen und an als 12Bit Wert an den DAC gesendet. Das ganze funktioniert per Direct Digital Synthese und Waveform-Tabellenzugriff. Gruß Rolf
Datum:
Angehängte Dateien:Hallo Ich will noch einmal auf das Thema Interpolation zu sprechen kommen. Wolfgang aus dem CC2-Forum hatte ja bereits in seinem Beitrag (http://www.cczwei-forum.de/cc2/thread.php?postid=7...) viel erklärt und gute Tips für die Berechnung geliefert. Da mir jetzt "Unbegrenzter" Speicherplatz in meinem Synthesizer zur Verfügung steht (ganze 8 MegaByte wow..) habe ich einige Test mit der Interpolation von Soundsamples gemacht (siehe Bild 1+2) . Die Original-Samples hatten jeweils eine Auflösung von 7 Bit. Bild 1: Links Original Waveform 7Bit, Rechts interpolierte Waveform Bild 2: Links Original 7Bit Waveform, Mitte interpolierte Waveform Das Ergebnis ist wirklich gut. Kein Rauschen kein nix. Die Original 7Bit Soundsamples klangen im unteren Frequenzbereich (< 500Hz) sehr verrauscht. Nach der Interpolation klingt das ganze schon super finde ich. Mein Code für die Interpolation
//-------------------------------------------------------------------------- // Wave-Interpolation // ------------------ // Zwei Sample aus Wave-Tabelle laden und drei neue Zwischenwerte berechnen. // Dann 1.Sample und die drei neuen Zwischenwerte für die Soundausgabe ins // SDRAM schreiben. //--------------------------------------------------------------------------- void init_wave2() { // schreiben uint8_t sample_index = 0; uint16_t wr_pointer = 0; uint32_t sample_a = 0; uint32_t sample_b = 0; uint32_t sample_xa = 0; uint32_t sample_xb = 0; uint32_t sample_xc = 0; for (sample_index = 0; sample_index < 127; sample_index++) { sample_a = pgm_read_byte (&(wave_7Bit[sample_index])); // 1.Sample aus Sinus-Tabelle laden sample_b = pgm_read_byte (&(wave_7Bit[sample_index+1])); // 2.Sample aus Sinus-Tabelle laden sample_a = sample_a << 8; // 1.Sample to 16Bit sample_b = sample_b << 8; // 2. Sample to 16Bit sample_xb = (sample_a + sample_b) >> 1; // 1. - 3.Zwischenwerte berechnen sample_xa = (sample_a + sample_xb) >> 1; sample_xc = (sample_b + sample_xb) >> 1; hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_pointer,sample_a); // write 1.Sample to Puffer wr_pointer = wr_pointer + 2; // inc Sample-Puffer (+2 wegen 16Bit) hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_pointer,sample_xa); // write 1.Zwischenwert to Puffer wr_pointer = wr_pointer + 2; hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_pointer,sample_xb); // write 2.Zwischenwert to Puffer wr_pointer = wr_pointer + 2; hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_pointer,sample_xc); // write 3.Zwischen to Puffer wr_pointer = wr_pointer + 2; // inc Sample-Puffer (+2 wegen 16Bit) } } |
Neue (interpolierte) Wave aus SDRAM abspielen
void play_wave2() { uint16_t sample_index = 0; uint16_t rd_pointer = 0; uint16_t sample = 0; for (sample_index = 0; sample_index < 508; sample_index++) { sample = hugemem_read16(BOARD_EBI_SDRAM_BASE + 512 + rd_pointer); DACA.CH0DATA= sample >> 4; // 16Bit Sample to 12Bit _delay_us(1); rd_pointer = rd_pointer + 2; } } |
Mir geht es bei der Interpolation in erster Linie darum, die niedrige Auflösung der Wavefiles (8Bit/256Byte Länge und 7Bit/129Byte Länge) die sich im Flashspeicher des Xmega-Prozessors befinden, wärend des Systemstarts auf 12Bit/1024Byte Länge zu erhöhen und in das SDRAM abzulegen. Von da aus soll nach Bedarf jeweils ein Wavefiles für Oszillator1+2 in einen Soundpuffer (SRAM im XMega) kopiert, gemixt und auf den DAC gesendet werden. Das gleiche passiert mit Berechnungen von Wellenformen. In Bezug auf die SDRAM-Steuerung vielleicht noch ein paar interessante Infos. Ein 8Bit Lesezugriff auf das SDRAM dauert mit der "hugemem" Routine komplett ca. 1µsec (inlkusiv Adressierung und Rückgabe des Speicherwertes). Die ganze Adressierung und Rückgabe des 8Bit Speicherwertes wird also in ca. 32 CPU-Takten erledigt. Für einen 16Bit Lesezugriff ist die Zeit doppelt so lang. Das interne Steuerinterface (EBI) für das SDRAM wird im Xmega-Prozessor mit dem doppelten CPU-Takt von 64MHz betrieben. Die schnellste Zugriffszeit für das SDRAM auf meinem Xplained Board liegt laut Datenblatt bei 7.5nsec. Gruß Rolf
Datum:
Hallo Bin jetzt etwas verärgert . Habe das neue SP2 für Atmel Studio6 installiert und jetzt kann ich kein Programm mit meinem AVRISP MKII mehr flashen. Kann mir da einer weiterhelfen ? Liegt es vielleicht an Win8 ? Wenn ja fliegt Win8 im hohen Bogen von meiner Festplatte. Mit Win8 bin ich wieso nicht ganz zufrieden !
Datum:
Irgendetwas stimmt da nicht mit dem Programmiergerät. Die ausgelesenen Hex-Daten aus dem Flashpeicher des Xmegas sehen im unteren Teilbereich anders aus als die erzeugten Hex-Datei in Atmel Studio6 ???
Datum:
Hallo.. ich bins noch einmal Ich habe Win8 noch einmal neu installiert und danach Atmel Studio 6 SP2. Leider ohne Erfolg. Der Xmega wird vom AVRISP MKII nicht richtig programmiert. Ein manuelles Verify über die Tool-Funktion in Atmel-Studio zeigt Fehler am Ende der Programmdaten im XMega. Ich habe jetzt unter Windows8 die Treibersignierung deaktiviert und Atmel Studio 5.1 installiert. Das funktioniert auf Anhieb und ohne Probleme Atmel: "Don't change a running system" :( Ich werde jetzt erst einmal bei Atmel Studio 5.1 bleiben und mein Projekt unter Windows 8 weiter entwickeln. Aber ich wunder mich schon ein wenig, das Atmel die Version 6 mit dem SP2 für Windows8 kompatilen hält und keiner meckert ?? LG Rolf
Datum:
Angehängte Dateien:Hallo ihr Lieben Nachdem sich nun die Fachleute von Atmel um mein Problem mit dem Programmieradapter AVRISP MKII und ATMEL Studio 6 kümmern, kann ich mich wieder voll meinem Synthi-Projekt widmen. Ich möchte den AVR-Synthi mit zwei VCA-Chips (spannungsgesteuerter Verstärker) vom Typ SSM2164 austatten, weil ich mit der Soundqualität nicht zu frieden bin. Bei leisen Klängen ist ein Hintergrundrauschen vom DA-Wandler und dem Filterbaustein SSM2044 zu hören. Da der VCA-Chip am Ende der Übertragungskette, also hinter den Filtern sitzt, wird das Rauschen vom DAC und Filterbaustein mit abnehmbarer Lautstärke des VCAs auch leiser und ist dann kaum noch warnehmbar. Gesteuert werden die beiden VCA-Chips wie auch die Filter durch die PWM-Anschlüsse am Xmega-Prozessor. Das Hardwarekonzept für die Klangerzeugung sieht jetzt so wie in Bild 1 aus. Allerdings sind VCA-Chips nicht gerade billig. Ich habe sie bei einem Münchner Lieferanten (Sahin Electronic) für einen Stückpreis von 18,- Euro bekommen. Auf Ebay sind die Chips preisgünstiger zu bekommen, haben aber sehr lange Lieferzeiten (5-7 Wochen) weil aus Übersee. Bild 1: AVR-Synthi "WAVE 1" LG Rolf
Datum:
Rolf Degen schrieb: > Ich möchte den AVR-Synthi mit zwei VCA-Chips (spannungsgesteuerter > Verstärker) vom Typ SSM2164 austatten, weil ich mit der Soundqualität > nicht zu frieden bin. Hast Du schon mal darüber nachgedacht, einen externen I2S-DAC (16...24Bit) zu verwenden? Mittels UART im SPI-Mode und per Event-System synchronisiertem Timer für die WordClock bekommt man ein astreines, komplett in Hardware laufendes I2S-Interface hin. Nachladen kann man die Daten per DMA. I2S-DACs so in Richtung CS4344 kosten zum Beispiel bei CSD-electronics keine 3 EUR. I2S kann man auch wunderbar auf SPDIF umwandeln :-)
Datum:
Hallo Knut Das wäre auf jeden Fall eine Option bzw Verbesserung über die man später nachdenken kann. Aber erst einmal muss das ganze Projekt funktionieren. Es sind momentan noch zu viele Baustellen an denen ich arbeite. Gruß Rolf
Datum:
Angehängte Dateien:Hallöchen.. Heute sind meine zwei bestellten VCA-Chips (SSM2164D) angekommen. Die werde jetzt mal schnell in die Synthi-Schaltung geklebt und dann die Ansteuerung über die Software programmieren. Mal schaun wies klingen wird. Softwaremäßig sieht es zur Zeit etwas schwierig aus. Der Programmcode ist mittlerweile sehr groß und unübersichtlich geworden. Aus diesem Grund, habe ich damit angefangen, die vielen Funktionen in Funktionsblöcke zusammenzufassen und in sogenannten Include-Files abzulegen. Das ganze Code wird dadurch übersichtlicher und verständlicher. Das Projekt sieht zum Beispiel jetzt so aus wie im Bild 1. Auf der linken Seite steht eine ausgewählte Funktion, die zB. Daten über die SPI-Schnittselle des XMega-Prozessor zum Display sendet. Auf der rechten Seite sieht man die Ordnerstruktur und die ganzen Include-Files mit den darin befindlichen Funktionen. Bild 1: AVR-Synthi Projekt mit ATMEL Studio6 Gruß Rolf
Datum:
Hallo Rolf, Hut ab vor Deinen Experimenten. Aber ein paar Dinge sind mir noch unklar: > uint32_t sample_a = 0; > uint32_t sample_b = 0; > uint32_t sample_xa = 0; > uint32_t sample_xb = 0; > uint32_t sample_xc = 0; Warum 32? 16 sollte da voll ausreichen. > for (sample_index = 0; sample_index < 127; sample_index++) Zeitkritische for-Schleifen lasse ich immer bis 0 laufen, da der Vergleich wegfällt, er wird implizit im Dec-Befehl ausgeführt (Zero-Flag). Natürlich muss es auch beim Schreiben in dieser Reihenfolge geschehen. Außerdem: muss es nicht <128 (oder <=127) heißen für 0..127 ? also: sample_index=127;do{...}while(--sample_index!=0); wichtig ist vorher decrement, dann vergleich, sonst vergleicht er gern mit 0xff. Außerdem würde ich hier ebenfalls mit einem Pointer arbeiten. Du liest jedes Sample 2 mal aus, zuerst als b, dann als a. Du kannst ja statt des 1. Reads sample_a=sample_b schreiben. Mein Vorschlag (aus dem Stegreif, alles ungetestet) dürfte doppelt so schnell laufen: uint8_t cnt; uint16_t sample_a,sample_b; uint16_t* sample_ptr,wrt_ptr; sample_ptr = .....;wrt_ptr = ....; sample_b = pgm_read_byte (&(wave_7Bit[sample_ptr++])); cnt=128;do{ sample_a=sample_b; sample_b=pgm_read_byte (&(wave_7Bit[sample_ptr++])); delta=sample_b - sample_a; sample_a*=4; hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_ptr ,sample_a ); hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_ptr+=2,sample_a+=d); hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_ptr+=2,sample_a+=d); hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_ptr+=2,sample_a+=d); }while(--cnt);
Datum:
Hallo eProfi Danke für deine guten Vorschläge. Ich weis, das ganze ist von mir noch nicht optimal programmiert. Es war auch mein erster Versuch mit dem Zugriff aufs SDRAM. Ich werde deine Vorschläge auf jeden Fall berücksichtigen. Danke. Gruß Rolf
Datum:
Nochwas:
hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_ptr ,sample_a );
hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_ptr+=2,sample_a+=d);
hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_ptr+=2,sample_a+=d);
hugemem_write16(BOARD_EBI_SDRAM_BASE + 512 + wr_ptr+=2,sample_a+=d);
geht so schneller, da er die beiden Adress-Additionen nicht jedes mal
machen muss:
vor der do..while:
uint16_t wrt_ptr; //war oben fälschlich ein Pointer uint16_t*
wr_ptr = BOARD_EBI_SDRAM_BASE + 512;
in der do..while:
hugemem_write16(wr_ptr ,sample_a );
hugemem_write16(wr_ptr+=2,sample_a+=d);
hugemem_write16(wr_ptr+=2,sample_a+=d);
hugemem_write16(wr_ptr+=2,sample_a+=d);
Ausgabe würde ich unbedingt mit timergesteuerter DMA machen.
Habe ich mal mit einem Renesas M32C (interner DAC als DMA-Ziel) so
gemacht, keine Belastung durch die Ausgabe.
Datum:
eProfi schrieb: > Ausgabe würde ich unbedingt mit timergesteuerter DMA machen. > Habe ich mal mit einem Renesas M32C (interner DAC als DMA-Ziel) so > gemacht, keine Belastung durch die Ausgabe. Ich weis nicht recht, ob meine Methode (timergesteurte Soundausgabe über Assembler-Routine) im Vergleich zur DMA-Funktion doch die bessere ist. In dem Assembler-Teil für die Soundausgabe wird der 12Bit Wert aus dem Soundpuffer direkt in das Ausgaberegister des DA-Wandler geschriebe. Gruß Rolf
Datum:
Hallo Zur Abwechslung mal ein geiler Demo-Sound aus dem AVR-Synthi. Dabei wurde die Filterfrequenz und die Oszillatorfrequenz moduliert. https://soundcloud.com/rolfdegen/lfovcfmod Gruß Rolf
Datum:
Angehängte Dateien:Hallo Ich habe ein kleines Verständnis Problem mit der abgebildeten VCA-Schaltung von Oliver Gillert (Entwickler des Shruthi Synthis). Wie man erkennen kann, ist im Gegenkopplungszweig von Operationsverstärker (IC3A) ein VCA (IC7C) geschaltet (rotes Rechteck). Ich bin mir einfach nicht genau im klaren darüber, wozu der VCA (IC7C) notwendig ist. Vielleicht dient er zur Anpassung an eine lineare Steuerspannungskennlinie für den eigentlichen VCA in IC9D. Bild: VCA-Schaltung Gruß Rolf
Datum:
Hallo zusammen.. Wolfgang aus dem CC2-Forum meint, das es sich hierbei um ein Lin-Log-Wandler als Multiplizierer handelt. Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen Die Weihnachtstage habe ich dazu genutzt, um die VCA-Schaltung für meinen AVR-Synthesizer zu bauen und zu testen. Herausgekommen ist die im Bild1 gezeigte Schaltung. Grundlage war der Schaltungsentwurf von Oliver Gillert [https://ox1aha.bay.livefilestore.com/y1psza5s_RUtu...]. Ich musste allerdings ein paar Änderungen für meine AVR-Synthi machen, da Oliver in seinem Shruthi-Synthesizer mit einem anderen Spannungspegel (+5Volt) am PWM-Eingang arbeitet. Bild 1: AVR-Synthesizer VCA-Schaltung Mit dem Trimmer R5 wird die Steuerkennlinie für den VCA angepasst. Mit R3 wird das Steuersignal für den VCA verstärkt. Bei der Beschaltung des VCA's gibt es noch eine Besonderheit. Der VCA besitzt einen Mode-Pin (Pin1). Der Mode-Pin ermöglicht die Einstellung des Ruhestroms durch den Verstärker im VCA. Ist er der Mode-Pin nicht beschaltet, dann treten am VCA-Ausgang geringere Verzerrungen aber höheres Rauschen auf. Ist der Mode-Pin mit einem Pullup-Widerstand (hier R12) beschaltet, dann nehmen die Verzerrungen zu und das Rausches ist geringer. Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen.. Ich hoffe, ihr seit alle gut in das neue Jahr gerutscht. Ich habe mit meinen Freunden aus China gefeiert und das Neujahr begrüsst. Zur Party hatte ich extra Luftschlangen, Konfetti und Bleigießen mitgebracht, um zu zeigen, wie hier das neue Jahr gefeiert wird. Es war wunderschön.. :) Auch diese Tage hatte ich etwas Zeit für mein Projekt und habe die Filterschaltung für den AVR-Synthi etwas verbessert und getestet (siehe Bild 1). Meine Annahme, das der Steuereingang des Filter-ICs SSM2044 die gleiche logarithmische Steuercharakteristik besitzt wie der VCA-Chip SSM2164D war ein Irrtum. Da der Filter-Chip eine lineare Steuerkennlinie besitzt, ist der Bauteilaufwand dafür sogar etwas geringer. Das IC1d dient hier als Filter für das PWM-Steuersignal. Durch R1 wird das Steuersignal am Ausgang des Operationsverstärkers auf +0.90V angehoben und über den Spannungsteiler an den Steuereingang für die Filterfrequenz geführt. Die Steuerspannung für den Filter liegt hier, wie im Datenblatt genannt, zwischen -90mV und +90mV. Das Audiosignal vom XMega-DAC wird über einen LP-Filter IC2c an den Eingang des Filter-ICs geführt. Über den Trimmer P1 kann das Filter-Eingangssignal abgeschwächt werden, um Übersteuerungen am Filterausgang zu vermeiden. Ich habe den Audiopegel am Filterausgang auf 6.0 V~ eingestellt um etwas Reserven nach oben zu haben. Maximal ist ein Ausgangspegel von 8.0 V~ am Filterausgang möglich. Bei eingestellter Resonanz kann es schon mal vorkommen, das der maximale Audiopegel überschritten wird und es zu Verzerrungen kommt. Die Lösung ist entweder den Filtereingangspegel mit P1 zu reduzieren, oder die Steuerspannung für die Resonanz zu verringern. Gruß Rolf
Datum:
Angehängte Dateien:Hallo Hab mal ein kleines Video gedreht und auf Youtube hochgeladen. Es zeigt die VCA-Schaltung im AVR-Synthi in Aktion. Link zum Youtube-Video: Youtube-Video "AVR-Synthesizer VCA-Test" Gruß Rolf
Datum:
Angehängte Dateien:Hallo VCF und VCA-Schaltung sind jetzt fertig. Hier ein kleines Youtube Demo-Video. Es zeigt die LFO-Modulation von VCF und VCA. Youtube-Video "AVR_Synthesizer" Achtung! Sound ist sehr laut. Hier noch schnell ein Bild mit dem kompletten Hardwareaufbau meines AVR-Synthis in der Stereo-Version. Bild 1: AVR-Synthi Stereo-Version Gruß Rolf
Datum:
Na das geht doch schon ganz ordentlich. Ich stell mir das Teil jetzt schon mal an einem Sequencer vor :-)
Datum:
Hallo Knut Danke. Ich bin jetzt dabei, die LFO's zu programmiere. Insgesammt sollen es einmal sechs Stück werden für 2x VCA, 2x VCF, DCO, PAN. Davon sind jeweils zwei für die Stereo-Kanäle vorgesehen. Gruß Rolf
Datum:
Wenn Du das Ding fertig hast und ordentlich dokumentierst, baue ich mir vielleicht auch einen :-)
Datum:
An einer Dokumentation solls nicht scheitern. Sind immerhin schon 12 Blog-Seiten im CC2-Forum mit vielen Informationen die das Thema Synthesizebau und Softwareentwicklung betreffen. Das Ganze könnte sogar für ein Buch ausreichen. Mal schaun was da noch kommen wird. Auf jeden Fall steckt noch eine Menge an Arbeit für die Software drin. Gruß Rolf PS: Bald wirds wieder ein paar "verrückte" Demo-Sounds geben, die ich beim experimentieren mit dem Synth zufällig erzeugt habe. Aber dieses mal in Stereo :)
Datum:
Rolf Degen schrieb: > Sind immerhin schon 12 > Blog-Seiten im CC2-Forum mit vielen Informationen die das Thema > Synthesizebau und Softwareentwicklung betreffen. Ja, war schon drauf ;-). Rolf Degen schrieb: > Auf jeden > Fall steckt noch eine Menge an Arbeit für die Software drin. Darum lass ich Dich erst mal in Ruhe machen :-P. Vielleicht kann man, wenn das Projekt fundierte Kenntnisse abwirft, mal über die Hardware schauen. Ich denke, dass man den Controller gegen einen neueren XMEGA tauschen sollte und zu den Wandlern / Schnittstellen hätte ich auch noch die eine oder andere Idee. Rolf Degen schrieb: > Bald wirds wieder ein paar "verrückte" Demo-Sounds geben, die ich > beim experimentieren mit dem Synth zufällig erzeugt habe. Aber dieses > mal in Stereo :) Freu mich drauf!
Datum:
Angehängte Dateien:Hallöchen.. Es gibt wieder was neues rund um den AVR-Synthi zu berichten Ich habe das DCO-Menü etwas verändert und hoffe das es jetzt etwas übersichtlicher ist (Bild 1). Die Tune-Funktion für die Oszillatoren wird einen eignen Menü-Seite bekommen. Bild 1: DCO-Menü im AVR-Synthi Bild 2: Auswahl der Wellenform im DCO-Menü Da es ja zwei Oszillatoren im AVR-Synthi gibt, kann man für beide auch auch unterschiedlichen Wellenformen auswählen. Drückt man auf den Button "Wave", dann öffnet sich ein weiters Menüfenster, in dem man die Wellenform für den Oszillator mit dem Encoder oder Bargraph auswählen kann. Die ausgewählte Wellenform wird zusätlich auf dem Display dargestellt (Bild 2). Im neuen DCO-Menü kann für jeden Oszillator auch die Lautstärke von 0-127 eingestellt werden. Ferner können die beiden Oszillatoren entweder als Mono-Summe auf beide DA-Wandler Ausgänge geschaltet werden, oder getrennt auf die zwei DA-Wandler Kanäle für Links und Rechts (Stereo). Heute werde ich auch ein Youtube-Video mit den ersten Stereo-Demo Sounds vom AVR-Synthi hochladen und hier verlinken. So.. hier ist das angekündigte Youtube-Video mit den Stereo Demo Sounds vom AVR-Synthi: Youtube-Video "AVR-Synthesizer "WAVE 1" Stereo Demo" Bis dann.. Lieben Gruß Rolf
Datum:
Ich habe bemerkt das der Stereo Demosound im Youtube-Video ein paar Störungen hat. Warscheinlich durch die Videokomprimierung verursacht. Deshalb habe ich den Demosound noch einmal als MP3-File mit 320kBit Auflösung auf SoundCloud hochgeladen. Stereo Demosound https://soundcloud.com/rolfdegen/avr-synthesizer-w... Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen Auf der Suche nach einer einfachen und praktischen Speicherlösung für die Wavefiles und Soundparameter in meinem AVR-Synth, bin ich auf das ALFAT-Modul von der Firma GHI-Electronics gestoßen. Bild 1: ALFAT-Modul von GHI-Electronics Mit dem ALFAT-Modul können Daten über die SPI-Schnittstelle des Xmega-Prozessors auf oder von SD & MMC-Karten und USB-Speicher-Laufwerke geladen werden. Die maximale Datenübertragungsgeschwindigkeit wird vom Hersteller mit bis zu 4MBytes pro Sekunde angegeben. ALFAT-Konzep Ein FAT-Dateisystem für eine SD-Card oder USB-Stick benötig auf einem Mikrocontroller wzB dem ATXmega große Ressourcen. Der SoC-Prozessor auf dem ALFAT-Modul ermöglicht einen schnellen und einfachen Speicherzugriff per UART, SPI oder I2C-Schnittstelle und entlastet dadurch den ATXmega-Prozessor im AVR-Synthi. Das ALFAT-Modul unterstützt lange Dateinamen und ist von Microsoft für den gewerb-lichen Einsatz lizensiert. Bild 2: ALFAT-Konzept Einige Features * Built-in 2-port USB Host controller. * FAT16 and FAT32 File system. * No limits on media size, file size or file/folder count. * LFN (Long File Name), licensed by Microsoft. * Friendly user interface through UART,SPI or I2C. * Programmable UART baud-rate. * Up to 8 simultaneous file access. * SD/SDHC card support, no 2GB limit. GHI electronics is an SD association member. *High speed 4-bit SD card interface. * Up to 4000 KBytes/sec file access speed SD cards/USB. * Single 3.3V power source. Gruß Rolf
Datum:
Angehängte Dateien:Hallo Ich habe jetzt das "ALFAT OEM Board" an den AVR-Synthesizer angeschlossen und die ersten Funktionen programmiert wzB die Initialisierung und Formatieren einer SDCARD oder das Auslesen der RealClockTime. Mit dem Auslesen der RCT hatte ich am Anfang allerdings ein Problem, weil der spezielle Uhren-Quarz auf dem ALFAT-Board nicht bestückt war (Absicht oder nicht ?). Ich hatte noch einen in meiner Krabbelkiste und habe diesen auf das Board gelötet. Danach klappte alles einwandfrei. Bild 1: AVR-Synthesizer mit ALFAT OEM Board Das ALFAT-Board benötigt eine Versorgungsspannung von +5V. Intern wird die Spannung für die SDCARD auf 3.3 Volt gewandelt. Die beiden USB-Buchsen liegen an +5Volt . Da das ALFAT-Board die +5 Versorgungs- spannungschiene vom Netzteil etwas mehr belastet, habe ich die Glättungs-Elkos von 470µF auf 2200µF erhöht. Durch die größere Belastung auf der +5Volt Schiene wurde jetzt der Festspannungsregler 7805 etwas heiss. Aus diesem Grund habe ich ihm einen kleinen Kühlkörper spendiert. Die Tage werde ich die Routinen für das Speichern und Laden von Wellenformen programmieren und als Anwendungs- beispiel hier posten. Ich denke, das ist vielleicht auch für andere Anwendungen wzB Datenlooger oder so interessant. Bis dahin lieben Gruß Rolf
Datum:
Hallo ihr Lieben.. Nach längerer Abwesenheit wegen Krankheit melde ich mich Heute wieder zurück. Ich muss mich leider noch etwas erholen und aus diesem Grund gibt es noch nichts Neues zu berichten. Ich hoffe, das ich bald wieder gesund bin und etwas mehr Zeit habe, um an meinem Projekt weiter zu arbeiten. Aber im Moment hat mir der Arzt viel Bewegung verschrieben und da bleibt leider nicht so viel Zeit für die Computerarbeit. Aber ich versuche trotzdem immer mal wieder etwas zu berichten, damit es hier nicht zu langweilig für euch wird. Bis dahin bleibt gesund und viel Spaß beim stöber hier im Forum. Lieben Gruß Rolf Nachtrag: Gerade im shruthi-Forum (http://www.mutable-instruments.net/forum/) gelesen und vielleicht interessant für euch.. In der Ausgabe 1/2013 "c't Hardware Hacks" (http://shop.heise.de/katalog/ct-hardware-hacks-1-2013) wird der Bau eines "Mini-Synthesizer" mit einem ATMEL-Chip beschrieben. Gruß Rolf
Datum:
Hallo ihr Lieben.. Gibt wieder einiges neues zu berichten auf meiner Blockseite im CC2-Forum. Da gehts um neue Boards, Soundkarten und Umbau, Cubase und ASIO-Latenz und Drehencoder. Wenn Ihr Lust habt, dann schaut doch einfach mal hier vorbei: http://www.cczwei-forum.de/cc2/thread.php?postid=8... Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen Ich möchte euch den ersten Gehäuse-Entwurf für mein Synthesizer "WAVE 1" vorstellen. Die Idee stammt von Wolfgang (alias Wiesolator) aus dem CC2-Forum. Grundlage ist ein Alugehäuse der Firma BOPLA (Bild 2). Die gelbe Frontplatte lasse ich von der Firma Schaeffer herstellen. Die zwei Gehäuseseitenteile werden aus Holz sein. Die Idee für die zusätzlichen Regler (Edit) hatte Wolfgang. Für Live-Aktionen können die Regler mit einer Funktion belegt werden. Was in dem Entwurf noch fehlt, sind Volume-Regler für den Kopfhöreranschluss und SD-Card Beschriftung (oben). Gruß Rolf
Datum:
Angehängte Dateien:Hallo zusammen.. Hier eine kleine Vorstellung meiner MiniScope-Funktion im AVR-Synthesizer: Youtube-Video: Youtube-Video "Mini-Scope Funktion in AVR-Synthesizer "WAVE-1" (Video 2)"
Datum:
Angehängte Dateien:Hallo Mein Scope im AVR-Synthesizer besitzt jetzt eine TimeBase- und Trigger-Funktion Youtube-Video: Scope-Funktion: Youtube-Video "Scope-Funktion AVR-Synthesizer "WAVE 1" (Video 3)" Gruß Rolf
Datum:
Angehängte Dateien:Hallo ihr da.. Hab mal wieder etwas an meinem Synth gebastelt bzw programmiert und herausgekommen ist eine neue Menü-Seite für die Modulation-Matrix (Bild 1). Links kann man eine Modulations-Quelle zB LFO1 auswählen und Rechts sieht man dann die Modulations Ziele für LFO1 mit den eingestellten Depth-Werten. Da es sich beim "WAVE 1" um einen "Echten" Stereo Synthesizer handelt, gibt es für den linken und rechten Kanal getrennte Modulations-Ziele zB VCF1 und VCF2. Einige Modulations-Ziele wzB PAN, FM and Noisgenerator fehlen allerdings noch. Bild 1: Modulations-Matrix im AVR-Synthesizer Meine Projekt-Seite: http://www.cczwei-forum.de/cc2/thread.php?threadid... Mein Youtube-Kanal: http://www.youtube.com/user/rolfdegen1806 Grüße Rolf














































