mikrocontroller.net

Forum: Projekte & Code AVR Synthesizer mit ATxmega128A1


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
6 lesenswert
nicht lesenswert
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

: Verschoben durch Admin
Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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-avr-synthesizer/ 
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

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 
:)

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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-cyc2-2C20N.html#note2
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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/04/Raspberry-Pi-Schematics-R1.0.pdf

Gruß Rolf

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 
:-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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=76123#post76123

Gruß Rolf

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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 :-)

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Rene

Im Anhang findest du eine c.File aus dem FM Sound Projekt fuer das 
Discovery Board. Vielleicht hilft es dir.

Gruss Rolf

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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=76348#post76348

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich werde jetzt erst einmal weiter an meinem 12Bit AVR-Synthi basteln 
und ein GUI mit einem Tochdisplay integrieren. Die Programmierung mit 
dem AVR ist auf jeden Fall leichter und unkomplizierter im Vergleich zum 
Cortex M4 Prozessor.

Gruß Rolf

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ?

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Von Jo-MIDI FM Version 1.2

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Maik

Welches Altera-Board hast du genau ?

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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/boards/de2/unv-de2-board.html

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 :))

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rene B. (themason) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So ... hier mal Schaltplan und die Bauteilplatzierung von dem neuen 
Board so wie es ist.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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-Codeoptimierung

Aber so etwas Zyklenkritisches würde ich eh komplett in Assembler 
angehen. Dann hat man eine genaue Kontrolle.

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

wie berechnest Du die Hüllkurve bzw. die Variable adsr_1?

Kannst Du den C code mal einstellen?

Gruß

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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=76427#post76427

Gruß Rolf

Autor: Musikus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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"

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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=76548#post76548

Gruß Rolf

Autor: Alessandro R. (alessandro_r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 
!!

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: alessandro_r (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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=76539#post76539

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

In meinem Code ist noch eine einfache FM-Sound Erweiterung 
hinzugekommen.

LG Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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=76736#post76736

Gruß Rolf

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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).

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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&topic=AVR-PolySynth).

Gruß Rolf

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

kannst Du bitte mal den kompletten code posten?
Ich möchte das auf einem AVR32 testen.



Viele Grüße

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Rolf,

vielen Dank, ich versuche mich jetzt daran den code auf dem AVR32 zum 
laufen zu kriegen.

Viele Grüße

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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=76877#post76877

LG Rolf

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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=77145#post77145

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Sascha W. (arno_nyhm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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=72107#post72107

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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-Entwicklungstools/AT-AVR-XPLAIN/3/index.html?;ACTION=3;LA=2;ARTICLE=96802;GROUPID=2969;artnr=AT+AVR+XPLAIN;SID=10T4MPon8AAAIAADLU5TM70bd5d4d8cb84aecb656096e17edfa00

Gruß Rolf

Autor: Sascha W. (arno_nyhm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super - Danke Euch für die Hinweise! Ist zur Abwechslung ja auch mal 
einfach zu bekommen, nicht nur direkt aus Hongkong ;)

Grüße
Sascha

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Es gibt wieder was neues über die Stromversorgung des AVR-Synthis. 
Näheres auf: 
http://www.cczwei-forum.de/cc2/thread.php?postid=77648#post77648

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo und guten Morgen

Ich habe einen Schaltplan für den AVR-Synthi gezeichnet. Auf 
http://www.cczwei-forum.de/cc2/thread.php?postid=78070#post78070 kann 
man sich jetzt den Schaltplan ansehen.

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
// 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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
//

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@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).

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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" ?

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Rene

Dann schau mal hier: http://musicdsp.org/archive.php?classid=1

Gruß Rolf

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Maik

Achso meintest das. Ja, so gesehen ist das nen Proviorium. Und 
Frequenzanteile oberhalb von fS/2 zu Nullen wird noch eingebaut ...

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier noch ein paar Bilder von speziellen Wellenform-Kombinationen.

Gruß Rolf

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf Degen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :)

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Code operiert nur im positivem Bereich, das ist generell schlecht 
für DSP.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie könnte ich das ändern ?

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das mit dem abkürzen (2. Code-Beitrag von mir) wird wohl nicht 
funktionieren... jetzt bin ich mit dem Signed-Kram auch 
durcheinandergekommen.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Maik für deine tolle Unterstützung. Ich sach mal Schüß bis zum 
nächsten Problem :) und schönen Sonntag noch.

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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;

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für deine Hilfe. Werde deinen Vorschlag ausprobieren und wenns 
klappt oder auch nicht noch einmal hier melden.

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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);

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich teste es jetzt.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne.. leider kein Erfolg. Frequenz immer noch auf 0-32Hz

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was passiert, wenn du die Zeile:
outPitch = ( fPitch1 * (255-fFineByte) ) >> 8 + ( fPitch2 * (fFineByte) ) >> 8;

durch diese ersetzt:
outPitch = fPitch1;

bzw:
outPitch = fPitch2;

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja das wollte ich gerade machen.

 outPitch = (__uint24)fPitch1 << fOctave; = 440,1Hz
 outPitch = (__uint24)fPitch2 << fOctave; = 261,6Hz

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :)

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ohne Typkonvertierung könnte es so gehen:
outPitch = ( (fPitch1>>8) * (255-fFineByte) ) + ( (fPitch2>>8) * 
(fFineByte) );

Allerdings produziert das massive Rundungsfehler

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Damit ändern sich die Notenwerte in einer Oktave nicht mehr. Sie bleiben 
gleich und verdoppeln sich bei der nächsten Oktave.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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;
...

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ups ... Auskommtierung vergessen

ersetze
fPitch2 = phaccu_delta[fPitchIndex + 1];// (inFine > 0) ? 1 : -1];

durch
fPitch2 = phaccu_delta[fPitchIndex + (inFine > 0) ? 1 : -1];

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß.

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kann nicht sein, der müsste sich bei jeder Note um 1 Index 
verschoben zu Pitch1 bewegen.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ?

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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;
...

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne der Filter wird z.Zt. mit dem ADSR-Werten gesteuert.

Autor: Rolf Degen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)).

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
  

Autor: Maik M. (myco)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke. Werde deinen Vorschlag gleich testen. rdbuf_pointer ist der 
Adresszeiger bein lesen des Buffers und wrbuf_pointer beim schreiben in 
den Buffer.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
da war ich doch nah dran... würde mich interessieren, was bei meinem 
falsch war. Das low/high?

Autor: rolf degen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich programmiere unter atmel Studio 6 und der Assembler ist da etwas 
eigen. Statt low/high muss lo8/Hi im Quellcode stehen.

LG Rolf

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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/beschreibung/beschreibung.html

Gruß Rolf

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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=79168#post79168) 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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 !

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ???

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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);

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klingt doch ganz manierlich ;-)

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klingt echt toll dein AVR Synthi :-) Nur weiter so.

Autor: egonotto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

klingt wirklich gut.

MfG
egonotto

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen..

Wolfgang aus dem CC2-Forum meint, das es sich hierbei um ein 
Lin-Log-Wandler als Multiplizierer handelt.

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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_RUtuXITmcuMA58lD5eyOBqyuXUQMaaMn7uBGqJqOuzvw-yzL8Q-P8wOXyN1doNAyF2V1vleuuO1fYgZ7lN4EPhcD2v/VCA_01.png].

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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
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

Autor: Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na das geht doch schon ganz ordentlich. Ich stell mir das Teil jetzt 
schon mal an einem Sequencer vor :-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du das Ding fertig hast und ordentlich dokumentierst, baue ich mir 
vielleicht auch einen :-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :)

Autor: Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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-wave-1-stereo

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Soundbeispiele sind wieder sehr schön.

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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=80909#post80909

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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)"

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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=5878&threadview=0&hilight=&hilightuser=0&page=15

Mein Youtube-Kanal: http://www.youtube.com/user/rolfdegen1806

Grüße Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo ihr Lieben..

Heute Morgen will ich wie gewohnt etwas an meinem Synthesizer Projekt 
arbeiten und starte dafür Atmel Studio 6.1. Morgens hat man ja meistens 
die beste Phase für gute Ideen und Gedanken. Aber dann erlebe ich eine 
Überraschung die mich echt umgehauen hat.

Beim compilieren meines Projekt-Files zeigt mit Atmel Studio plötzlich 
7791 Fehler an. Ups.. was ist das denn ?? Gewohnt bin ich ja ab und zu 
so ein paar blöde Syntax-Fehler die man so aus Flüchtigkeit beim 
programmieren macht wzB das vergessen einer Geschweiften Klammer am Ende 
einer Funktion, oder oft ein vergessenes Semikolon am Ende einer 
Anweisung. Aber 7791 Fehler. Ne.. das is doch a bissel viel

Nach langem Suchen und vielem hin und her wollte ich schon aufgeben und 
da kam mir der Zufall zur Hilfe. Im ASF Wizard von Atmel Studio 6.1 kann 
man die ASF-Module Version upgraden. Der Eintrag stand bei mir auf 
3.5.0. Ich habe ihn auf die letzte Version 3.9.1 gestellt und konnte 
mein Projekt jetzt ohne Fehler compilieren.

Bild 1: Atmel Studio 6.1 ASF Wizard

Wieso der Fehler Heute Morgen aufgetreten ist und nicht schon Gestern 
Nacht, als ich das letzte mal mein Projekt compeliert habe, das bleibt 
mir ein Rätsel. Auf jeden Fall bin ich froh das es wieder funktioniert.

Mein Fazit: Ich mach jetzt jeden Tag ein Backup auf einer externen 
Festplatte.

Gruß Rolf

Autor: Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ATMEL-Studio ist immer für Überraschungen gut. Mein Kollege flucht auch 
öfter. Da ich in ASM programmiere, bleibe ich weitgehend verschont ;-). 
Manchmal ist Fortschritt nicht auf Anhieb zu verstehen...

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Knut

Schön von dir zu hören. Mit der Zeit hat man ja so seine Erfahrungen mit 
ATMEL STUDIO gemacht und kann damit umgehen. Mein Projekt ist 
mittlerweile schon sehr groß geworden. Bin gerade dabei, das ATMEL 
Xplained-Board 
(http://www.watterott.com/de/Atmel-UC3-A3-Xplained-AT32UC3A3-XPLD) durch 
ein Breakout-Board mit einem ATXmega128A1 
(http://mikrocontroller-praxis.de/de/Development-Tools/AVR-Mikrocontroller-Module/XMega100-Breakout.html) 
zu ersetzen, damit ein Nachbau günstiger wird. Auf dem Xplained-Board 
gabs viele Dinge die ich für mein Synthesizer-Projekt nicht benötigte 
und einige Ports waren nicht zugänglich. Dies ist mit dem Xmega 
Breakout-Board jetzt kein Problem mehr. Ein preisgünstiges SD/MICRO-SD 
CARD BREAKOUT MODULE 
(http://mikrocontroller-praxis.de/de/Development-Tools/SD/MICRO-SD-CARD/SD/MICRO-SD-CARD-BREAKOUT-MODULE.html) 
habe ich ebenfalls bestellt. Hatte davor eine teures SDCARD-Modul von 
ALFAT (https://www.ghielectronics.com/catalog/product/337) mit USB 
geplant. Aber das ist mit über 50,- Euro doch sehr teuer. Das Display 
teure Touch-Display wurde ebenfalls ersetzt gegen ein preisgünstiges 
DOGXL160 Display. Damit wird der Synth im Nachbau etwas günstiger. 
Überlege noch wegen den verwendeten Filter-IC SSM2044, ob ich diese 
nicht gegen eine günstige Filterschaltung mit OTAS vom Typ LM13700 
ersetzen soll. Aber vorerst bleib ich bei den SSM2044.

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Einen wunderschönen, sonnigen und guten Montag Morgen wünsch ich Euch 
allen :)

Hier ein paar Bildchen von meinem Synth-Gehäuse. Bin gerade dabei das 
Frontpanel für die Frontplatte zu löten. Aber sieht schon nicht schlecht 
aus find ich.. :)

Bilder: AVR-Synthesizer Gehäuse


Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo again.. ich schon wieder smile

Damit man einen kleinen Eindruck gewinnt, wie der Synthesizer später 
einmal aussehen wird, hab ich mal eine Fotomontage gemacht. Ist mir 
nicht so gut gelungen, bin aber auch kein "gut bezahlter" Grafiker smile

Bild 1: Synthesizer "WAVE 1"

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Für den Xmega-Prozessor in meinem Synthesizer plane ich noch eine 
Speichererweiterung von 512KByte SRAM. Das SRAM gibt es als Breakout 
Board auf eBay schon ab 7,99 US $. Dann hätte ich die Möglichkeit, beim 
Systemstart die Soundparameter und großen Wellenform Dateien von der 
SDCard in das SRAM zu laden. Angebunden wird das SRAM an den EBI-Bus 
(Port H-K) des Xmega. Mit dem Xmega kann ich wesentlich schneller auf 
Wellenform Daten und Soundparameter zugreifen als über die SDCard. Die 
SDCARD dient dann lediglich als externer Datenspeicher.

Bild 1: IS62WV51216BLL SRAM Board
Bild 2: EBI Port Xmega

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallöchen..

Ich habe gerade festgestellt, das auf dem bestellten SRAM-Board 
(IS62WV51216BLL SRAM Board) ein 16Bit SRAM sitzt und nicht wie gedacht 
um ein 8Bit Typ. Das freut mich doch sehr, da es insgesammt 1MByte 
Speicherplatz sind. Wow.. smile

Die Adressierung mit dem Xmega ist allerdings etwas tricki. Um das SRAM 
zu adressieren sind zwei Stück 8-BIT D-LATCH Typ 74HC573 für die 
Bereitstellung der höheren Adressleitungen von A8-A18 notwendig. 
Zusätzlich ist für die vollen 16Bit Nutzung des SRAMs eine freie 
Adressleitungen (zB A19) notwendig, die auf den "LB" Anschluss 
(LowerByte) und über einen Inverter an "UB" Anschluss SRAM zu legen ist.

Bild 1: Xmega EBI-Interface
Bild 2: SRAM IS62WV51216BLL-55TLI

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo ihr Lieben..

Die VCA-Page in meinem Synth ist jetzt fertig (siehe Bilder). Mit der 
Taste "Function" kann man auf der VCA-Page zwischen den Einstellungen 
für die Lautstärke und Balance umschalten. Die rechteckigen Symbole für 
Osc und Noise werden entsprechend der Balance-Einstellung wie bei einem 
analogen Fader nach oben oder unten verschoben.

Softwaretechnisch ware es nicht ganz leicht (zumindes für mich 
Augenzwinkern ) die Volume- und Balance-Funktionen für Oszillator und 
Rauschgenerator umzusetzen. Ein Teil der Funktionen (Berechnung 
Lautstärkeverhältnis Linker und Rechter Audiokanal) wurde in der 
Menüsteuerung, die komplett in C geschrieben ist, umgesetzt (siehe 
C-Code). Ein anderer Teil dieser Funktion wurde in die Assembler 
Routinen für die Soundausgabe integriert (siehe unten).

Im Anhang zwei Bilder von der VCA-Page und Code-Beispiel.


Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallöchen..

Habe mit großartiger Unterstützung von Andre (tubeohm.com) nun einen 
neuen Stereo Audio-Filter für meinen Synth gebaut. Im Vergleich zum 
alten Filter mit den SSM2044 IC klingt der neue Filter im Bass- und 
Hochtonbereich sehr ausgewogen.

Hier meine Stereo Filter Demo: 
Youtube-Video "Stereo Filter DIY-Synthesizer "WAVE 1""

Was noch fehlt ist die Auswahl von verschiedenen Filterkombinationen zB. 
LP+LP zu einem 4pol LP Filter mit 24dB pro Oktave (mono) oder HP+HP, 
LP+HP oder BP+BP.

Bild 1: Stereo Filter Hardware
Bild 2: Vorläufiges Schaltbild eines Filterkanals

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Happy Halloween :)

Noch rechtzeitig zu Halloween hier ein paar Geistersounds aus meinem AVR 
Synthesizer. Dank der neuen Modulation Matrix in meinem Synth, sind ein 
paar irre Sounds entstanden. Viel Spaß beim anhören.

https://soundcloud.com/rolfdegen/halloween-sound

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen..

Es hat sich wieder was getan in meinem Synthesizer. Die Envelope Pages 
haben eine Realtime-Anzeiger für den Verlauf der Hüllkurve (ADSR) 
erhalten. Die Anzeige (kleines schwarzes Fenster) befindet sich oben 
Rechts und ist mit Env gekennzeichnet. Wird zB eine Noten Taste am 
Keyboard gedrückt, erscheint der Verlauf der ADSR-Hüllkurve vom AMP Env 
in Echtzeit in dem kleinen schwarzen Fenster.

Bild 1: Hüllkurvenverlauf


Die Modulations Matrix ist fast fertig. Mit "Source" wird der Modulator 
zB LFO1 ausgewählt. Mit "Destin." (Destination) das Modulations Ziel zB 
Osc1. Mit "Depth" wird die Modulationhöhe eingestellt. Um eine bessere 
Übersicht über die zur Zeit aktiven Modulatoren zu haben, habe ich diese 
mit einem Stern Symbol gekennzeichnet. Nicht aktive Mudulatoren haben 
keinen Stern.

Die Verknüpfung der Modulatoren mit dem Ziel erfolgt immer additativ. 
Wenn zB LFO1 und LFO3 auf das gleiche Modulationziel zB Osc1 geschaltet 
werden, wirkt die Summe beider Modulationssignale auf den 
Modulationseingang von Osc1.

Bild 2: Modulations Matrix

Der Synthesizer besitzt jetzt außer dem AMP Env und Filter Env noch zwei 
weitere freie Envelope Generatoren (Env3+4). Diese besitzen eine eigene 
Menü-Page mit den gleichen Parametereinstellungen wie der AMP Env und 
Filter Env und sind für Modulationszwecke vorgesehen.

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute

Ich habe Probleme mit EBI Interface auf meinem ATxmega128A1 (siehe 
Bild). Ich verwende ein 512KB SRAM und einen ATMEL Xmega128A1 (Rev H) im 
EBI-Modus. Die höheren Adress-Bits A16-18 an Port H funktionieren nicht 
korrekt. Die Adressbits A0-A15 funktionieren ohne Problem. Das Speichern 
und Lesen von 64KB SRAM Daten ist kein Problem. Aber oberhalb des 64KB 
Adressraums werden die Adressleitungen A16-A18 (CS0-CS2) vom EBI 
Interface nicht richtig angesteuert. Die Adressleitungen A16-A18 sind 
bei jedem Schreibsignal (WR-Signal low aktive) immer auf high Pegel.

Bild 1: SRAM Anbindung an Xmega128A1

Bild 2: EBI-Port Konfiguration


Mein Code:
//---------------------------------------------------- 
// init extern 512KB SRAM 
// --------------------------------------------------- 
void init_sram(void) 
{ 
   // Set signals which are active-low to high value 
   PORTH.OUT = 0xFF; 
    
   // Configure bus pins as outputs(except for data lines). */ 
   PORTH.DIR = 0xFF; 
   PORTK.DIR = 0xFF; 
    
   // init EBI 3PORT/AL1/CS3 (A16-19) 
   EBI.CTRL |= EBI_SRMODE_ALE1_gc; 
   EBI.CTRL |= EBI_IFMODE_3PORT_gc; 

   EBI.CS3.CTRLA |= EBI_CS_MODE_SRAM_gc; 
   EBI.CS3.CTRLA |= EBI_CS_ASIZE_16M_gc; 
   EBI.CS3.BASEADDR = 0x00; 
   EBI.CS3.CTRLB |= EBI_CS_SRWS_2CLK_gc; // EBI time 
} 

//---------------------------------------------------- 
// write sram 
// --------------------------------------------------- 
void wr_sram(void) 
{ 
   uint32_t start_adr = 0x4000; // init Startadr. over 16KB SRAM space in Xmega128A1 
   uint8_t data = 0; 
   for (uint32_t i = 0; i < 0x80000; i++) 
   { 
      hugemem_write8(start_adr + i, data); 
      data++; 
   } 
}

Im Voraus vielen Dank für eure Hilfe. Schöne Grüße aus Wuppertal. Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebe Mitleser..

Mit Hilfe des ATMEL Support Team konnte ich mein Problem jetzt lösen. 
Leider funktioniert der schnellere EBI-Mode mit nur einem Adresslatch im 
ATxmega128A1-AU nicht. Diese Version des Prozessor ist leider schon 
etwas älter und Fehler wurden nur noch in den neuen Version wzB dem 
ATxmega128A1U behoben. Das U in der Bezeichnung steht für ein 
zusätzliches USB-Interface im Prozessor. Um die Kompatibilität und die 
Verwendung beide Prozessoren im Synthesizer zu gewährleisten, habe ich 
einen EBI-Mode mit zwei Adresslatch für das SRAM ausgewählt. Dieser 
funktioniert mit beiden Prozessoren fehlerfrei, ist aber im Zugriff auf 
das SRAM um 2 Takte langsamer (siehe EBI-Timing).

Bild 1: EBI Interface mit zwei Adresslatch

Bild 2: EBI Timing

Um die Ansteuerung des 512KB SRAM zu testen, habe ich ein Beispiel (EBI 
SRAM Example - STK600 ATxmega128A1) aus dem ATMEL Studio 6.1 geladen. 
Das ATMEL AVR STK600 ist ein Starter-Kit und Entwicklungs-System für AVR 
8-Bit bis 32-Bit ATMEL Mikrocontroller. Das Beispiele funktioniert aber 
auch mit einem ATxmega ohne Entwicklungsboard. Wichtig ist dann aber, 
das der Prozessortakt beim Systemstart richtig eingestellt wird (siehe 
init_clock im Beispiel Code).

Bild 3: SRAM Example Project from ASF

Beispiel Code für 512KB SRAM:
/* 
 * Include header files for all drivers that have been imported from 
 * Atmel Software Framework (ASF). 
 */ 
#include <asf.h> 
#include <hugemem.h> 
#include <ebi.h>

//*************************************************************************
//
//             init CPU Clock 32Mhz (ext. Clock 16MHz)
//
//*************************************************************************
void init_clock(void)
{    
    
    // set startuptime for extern Crystal Oscillator
    OSC_XOSCCTRL = OSC_XOSCSEL_XTAL_16KCLK_gc | OSC_FRQRANGE_12TO16_gc;
    
    // enable ext. 16MHz Crystal Oscillator
    OSC.CTRL = OSC_XOSCEN_bm;
    
    // wait oscillator is stable
    while(!(OSC.STATUS & OSC_XOSCRDY_bm));
    
    // set PLL  16MHz * 2
    OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 0x02;
    
    // enable PLL
    OSC.CTRL |= OSC_PLLEN_bm;
    
    // wait PLL is stable
    while(!(OSC.STATUS & OSC_PLLRDY_bm));
    
    // protect I/O register
    CCP = CCP_IOREG_gc;
    
    // enable PLL-Clock
    CLK.CTRL = CLK_SCLKSEL_PLL_gc;
}
 

static struct ebi_cs_config     cs_config; 

//------------------------- 
// init EBI for 512KB SRAM 
//------------------------- 
void init_sram(void) 
{ 
   // Set signals which are active-low to high value 
   PORTH.OUT = 0xFF; 
    
   // Configure bus pins as outputs(except for data lines). */ 
   PORTH.DIR = 0xFF; 
   PORTK.DIR = 0xFF; 
    
   ebi_setup_port(18, 2, 0, EBI_PORT_SRAM | EBI_PORT_3PORT 
   | EBI_PORT_CS0); 
   ebi_cs_set_mode(&cs_config, EBI_CS_MODE_SRAM_gc); 
   ebi_cs_set_address_size(&cs_config, EBI_CS_ASPACE_512KB_gc); 
   ebi_cs_set_base_address(&cs_config, BOARD_EBI_SRAM_BASE); 
   ebi_cs_set_sram_wait_states(&cs_config, EBI_CS_SRWS_1CLK_gc); 
   ebi_cs_write_config(3, &cs_config); 
   ebi_enable_cs(3, &cs_config); 
} 

//---------------------------------------------------- 
// write sram 
// --------------------------------------------------- 
void wr_sram(void) 
{ 
   hugemem_ptr_t   p; 
   uint32_t base = BOARD_EBI_SRAM_BASE; 
   uint_fast8_t    data = 0; 
   uint32_t offset = 0x00; 
   p=(hugemem_ptr_t)((uint32_t)base + offset); 
    
   for (uint32_t i = 0; i < 0x80000; i++) 
   { 
      if (i== 0x12345) 
      { 
         hugemem_write8(p+i, 0x55); 
      } 
      else 
      { 
         hugemem_write8(p+i, data); 
          
      } 
      data++; 
   } 
} 

//---------------------------------------------------- 
// write sram 
// --------------------------------------------------- 
void rd_sram(void) 
{ 
   hugemem_ptr_t   p; 
   uint32_t base = BOARD_EBI_SRAM_BASE; 
   uint_fast8_t   data1 = 0; 
   uint_fast8_t   data2 = 0; 
   uint32_t offset = 0x00; 
   p=(hugemem_ptr_t)((uint32_t)base + offset); 
       
   for (uint32_t i = 0; i < 0x80000; i++) 
   { 
      data1 = hugemem_read8(p+i); 
      if (i==0x12345) 
      { 
         if (data1 != 0x55) 
         { 
            Led1_on; 
         } 
      } 
       
      else 
      { 
         if (data1 != data2) 
         { 
            Led1_on; 
         } 
          
      } 
      data2++; 
       
   } 
}

conf_board.h:
/** 
 * \file 
 * 
 * \brief User board configuration template 
 * 
 */ 

#ifndef CONF_BOARD_H 
#define CONF_BOARD_H 


//! State that huge memory access (beyond 64k RAM) should be enabled 
#define CONFIG_HAVE_HUGEMEM 

//! Base address of SRAM on board 
#define BOARD_EBI_SRAM_BASE    0x800000UL 

//! Size of SRAM on board, given in bytes: 1 Mb / 128 kB 
#define BOARD_EBI_SRAM_SIZE    0x80000UL 

#endif // CONF_BOARD_H

PS: Empfehlenswert ist es, bei Neuentwicklungen den neusten 
ATxmega128A1U Chip zu verwenden, da der alte ATxmega128A1 einige Bugs 
hat. Leider sitzt auf vielen der angeboten Xmega Developementboards noch 
der alte ATxmega128A1-AU drauf.

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallöchen..

Es geht langsam vorran. Momentan habe ich wieder etwas mehr Zeit für 
mein Projekt. Das 512KB große SRAM soll als Wellenformspeicher im 
Synthesizer dienen. Da das SRAM einen 16Bit breiten Datenbus besitzt und 
das Speicher-Interface (EBI) des Xmegas nur einen 8Bit Datenbus hat, 
kann man eigentlich nur die Hälfte der SRAM Kapazität mit den 
Datenleitung von D0-D7 nutzen. Aber mit einer kleinen Trickschaltung 
lässt sich auch die andere Hälfte nutzen.

Dafür besitzt das SRAM zwei Anschlüsse mit der Bezeichnung "LB" 
(Lower-Byte) und "UB" (Upper-Byte). Wird "LB" auf Low Pegel geschaltet, 
dann werden die Ein- oder Ausgänge für das Lower-Byte auf die 
Datenleitung D0-D7 geschaltet. Die Datenleitung D8-D15 wird zum gleichen 
Zeitpunkt hochohmig. Das gleiche geschieht mit dem "UB" Anschluss. Wird 
"UB" low, dann wird D8-D15 auf die Datenleitungen geschaltet und D0-D7 
sind hochohmig. Durch diese Art der Ansteuerung kann man problemlos die 
Datenleitungen D0-D7 und D8-D15 am SRAM parallel schalten. Für die 
Umschaltung von Lower-Byte auf Upper-Byte sorgt die Adressleitung A19 am 
Pin 16 von IC4 und das Nandgatter IC5. Im Adressbereich von 0x00000 - 
0x7FFFF (0 - 524.287) wird jetzt das Lower-Byte im SRAM benutzt und im 
Adressbereich von 0x80000 - 0xFFFFF (524.288 - 1.048.575) das 
Upper-Byte. Damit ergibt sich eine Speicherkapazität von 2*512KB = 
1MByte.

Bild 1: 512KB-SRAM am Xmega

Bild 2: SRAM Pinout

Bild 3: SRAM Funktionsblock

Bild 4: 512x16 SRAM Steckboard

Das SRAM gibts in SMD Bauform aufgelötet auf einem Steckboard mit einer 
Power-LED für knapp 6,- Euro plus Versand bei Waveshare Electronics oder 
ebay: http://www.wvshare.com/product/IS62WV51216BLL-SRAM-Board.htm


Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallöchen..

Hier eine kleine Klangkostprobe aus meinem Synthesizer:
https://soundcloud.com/rolfdegen/wavedemo-01

Die Wavesounds habe ich in Audacity monophon aufgenommen und als 
RAW-File im 8Bit/16KHz Format exportiert. Über die SDCard habe dann das 
Wavefile in meinem Synth eingelesen. Die Zwei Oszillatoren habe ich 
gegeneinander etwas verstimmt um einen räumlichen Klang zu erzeugen. Die 
Sounds werden noch ohne Loops abgespielt, da ich diese Funktion zur Zeit 
programmiere.

Gruß Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallöchen..

Obwohl Weihnachten vor der Tür steht und noch so viele Dinge zu tun sind 
(wir wollen am 24. eine kleine Weihnachtsparty geben), habe ich noch 
etwas Zeit gefunden an meinem Synthesizer zu arbeiten.

Wie in meinem letzten Beitrag schon erzählt, programmiere ich gerade an 
einem simplen Wave Editor in meinem Synthesizer. Zur Zeit können nur 
Loop-Punkte für die Wiedergabe der Wavefiles gesetzt werden. Später 
werden noch mehr Funktionen folgen.
Man glaubt gar nicht, wieviel Entwicklungsarbeit hinter so simplen 
Funktionen wie zB einer Cursorsteuerung für ein Grafikdisplay stecken 
und die Auswahl eines Loop-Pointers für die Wellenform. Es reicht leider 
nicht aus, eine einfach senkrechte Linie für den Cursor auf dem Display 
zu zeichnen. Bevor das geschieht, muss als erstes der 
Bildschirmhintergrund gerettet werden, damit beim späteren Ändern der 
Cursorposition der alte Hintergrund (Wellenform) wieder restauriert 
werden kann.

Bild: Wave-Editor

Youtube:Youtube-Video "WAVE-Editor in my DIY-Synthesizer "WAVE 1""

Viel Gedankenschweiß hat mich auch die Zoom-Funktion für die Darstellung 
der Wellenform gekostet. Wenn man bei einer kleineren Auflösung der 
Wellenform zB nur jeden 10.Sample darstellt, dann enstehen große Lücken 
in der Amplitudenabbildung der Wellenform und somit auch eine 
fehlerhafte Darstellung auf dem Display. Das könnte man sicherlich in 
"Hoher Mathematik" lösen, aber Rechenzeit auf dem Xmega-Prozessor ist 
kostbar. Also habe ich nach einer anderen Lösung gesucht. Nach etlichen 
Überlegungen und viel Gedankenschweiß bin ich mit Hilfe von "Audacity" 
(Audioeditor) auf eine annehmbare Lösung gestoßen. Mal angenommen der 
1.Sample hätte einen Amplitudenwert von 10, der 2. von 255, der 10. von 
18. Dann würde bei einer Sampleabtastung von nur jedem 10.Samplewert der 
2. Wert (255) mit der höchten Amplitude und der Rest bis 10 fehlen. Also 
liegt es doch nahe, aus der Gruppe von den 10 Samples nur diesen zu 
nehmen, der die höchsten Amplitude hat. Und genau das ist die Lösung. 
Die Abbildung entspricht jetzt einer Hüllkurve dieser Wellenform.

Gruß Rolf

: Bearbeitet durch User
Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rolf

Sehr schön gemacht. Sieht ja mittlerweile sehr ansehnlich aus dein 
Synthesizer. Schick schick.

Aber wieso musst du vorher den Bildschirm sichern beim Cursorverschieben 
? Wenn du doch eine invertierte vertikale Linie zeichnest und vor dem 
verschieben bzw bevor du deine Darstellung und/oder den Cursor änderst 
einfach die vertikale Linie erneut invertieren hast du doch wieder den 
Ausgangsbildschirm nur ohne Cursor Linie, oder ?
Das mit der höchsten Amplitude bzw dem 'zusammenfassen' von Samples hab 
ich auch mal so gemacht. Geht ganz gut und erspart einem jede Menge 
Rechenzeit.
Gerade wenn man 'nur' auf einem AVR hantiert muß man ja so einige Kniffe 
parat haben damit sich das ganze a) noch halbwegs bedienen lässt und b) 
der AVR nicht nur mit der Darstellung ausgelastet ist, sondern seine 
'Hauptaufgaben' auch noch wahrnehmen kann.

Weiter so, und schonmal nen frohes Fest und viel Spaß noch beim Basteln 
:-)

Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Rene
Schön von dir zu hören :) Das DOGXL 160-7 Display besitzt leider keinen 
internen Speicher. Aus diesem Grund muss ich die Pixel, die der Cursor 
überschreibt, für eine spätere Wiederherstellung vorher sichern.

Gruß Rolf und Frohes Fest

: Bearbeitet durch User
Autor: Rolf D. (rolfdegen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wünsche Allen ein schönes Weihnachtsfest und guten Rutsch ins neue Jahr.

Ein großes Dankeschön auch an die Macher und Admins des mikrocontroller 
Forums :)

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Die Loop Funktion im Synthesizer
Mein Synthesizer ist jetzt mit einem 1MByte großen Wellenform Ram 
ausgestattet. Dadurch lassen sich auch sehr große Samples abspielen. 
Aber nur das einfache Abspielen eines Samples im Synthesizer und die 
Steuerung der Abspielgeschwindigkeit (Tonhöhe) wäre musikalisch gesehen 
etwas zu langweilig. Aus diesem Grund hat man das "Loopen" erfunden. Es 
handelt sich dabei um das wiederholte Abspielen eines bestimmten Sample 
Bereiches. Als es noch keine Sample-Player gab, hat man ein an beiden 
Enden zusammengeklebtes Stück eines Tonbandes genommen und wiederholt 
abgespielt. Eine ähnliche Technik ist im Jahre 1963 im Mellotron, dem 
Vorläufer des modernen Samplers angewendet worden.

Die Loop-Funktion für die Samples habe ich in einer Unterseite des 
Osc-Menüs integriert und kann über die Funktionstaste am Synthesizer 
aufgerufen werden. Ob ein Menü eine Unterseiten besitzt, sieht man an 
einem kleinen eingeblendeten Symbol (Fensterrahmen mit Pfeil) oben 
rechts neben der Seitennummer. An einer Funktion zum Laden verschiedener 
Wellenform-Files wird noch gearbeitet.

Um die Bedienung für die Loop Einstellung zu vereinfachen, habe ich die 
Cursorsteuerung über drei Encoder realisiert. Mit dem 1. Encoder steuer 
man den Cursor über die Wellenform. Befindet sich der Cursor jeweils am 
linken oder rechten Rand, dann wird automatisch der Wellenformauschnitt 
verschoben. Der 2. Encoder ist für die Zoom Funktion zuständig. Gezoomt 
wird immer an der aktuellen Cursor Position und in Bildschirmmitte. Mit 
dem 3. und 4. Encoder lässt sich der Loop-Anfang (LoopA) und das 
Loop-Ende (LoopB) einstellen. Zur Veranschaulichung habe ich ein Video 
auf Youtube hochgeladen.

Youtube: Youtube-Video "Loop Function"


Bis zum nächsten mal und lieben Gruß. Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen. Ich wünsche allen ein schönes und interessantes neues 
Jahr 2014

Zur Zeit arbeite ich an einer Soundverwaltung für meinen Synthesizer. 
Für die Datenspeicherung benutze ich eine handelsübliche 4Giga Byte 
große SDCard, auf der maximal 12800 Sounds verwaltet werden können. Von 
der SD Karte werden alle Soundparameter, Wellenformen und Samples in den 
Synthesizer geladen.Es ist schon erstaunlich, wenn man die Synthesizer 
und Sampler aus den 80er Jahren mit der heutigen Technologie vergleicht. 
Das Laden von Wellenformen und Samples dauerte damals je nach Datengröße 
schon mal etwas länger und nebenbei hatte man noch Zeit für eine Tasse 
Kaffee (siehe Video). Bevorzugte und preiswerte Speichermedien für die 
Synthis und Sampler waren damals 5.25 Zoll oder 3.5 Zoll Disketten. Die 
größeren und teuren Systeme hatte sogar schon Festplatten mit einer 
"sagenhaften" Kapazität von 10MByte. Die heutige Speichertechnologie ist 
im Vergleich dazu in astronomischer Größe gewachsen und auch wesentlich 
schneller und einfacher in ihrer Handhabung geworden. Eine Speichergröße 
von 64Giga Byte auf einer winzigen SD Karte wäre zur damaligen Zeit 
undenkbar gewesen.

Bild 1: PPG WAVETERM aus den 80er Jahren
Youtube: Youtube-Video "PPG Waveterm B booting and sample loading"

Ich habe versucht, das Laden und Abspeichern von Sounddateien in meinem 
Synthesizer etwas zu vereinfachen. Dafür habe ich eine einfache 
Datenstruktur mit drei Hauptordnern auf der SD Karte entwickelt (siehe 
Bild). Im Ordner "Sound" befinden sich 100 Sound Bänk. Jede Soundbank 
enthält die Klangparameter für 128 Sounds. Pro Sound sind 256 Byte für 
die Klangparameter reserviert, das macht insgesamt pro Soundbank also 
256*128 = 32KByte an Daten. Der Ordner "WAVE" beinhaltet alle 
Wellenformen für die Klangsynthese wzB Sinus, Rechteck, Sägezähn uvm. 
Der Ordner "Sample" beinhaltet, wie der Name schon sagt, alle ladbaren 
Samples. Maximal können in 100 Sample Bänken mit jeweils 128 Samples 
verwaltet werden. Das gleiche gilt natürlich auch für den Wellenform 
Ordner. Wellenformen und Samples können in der jetzigen Softwareversion 
im Synthesizer nur geladen werden. Erstellen kann man diese aber ohne 
große Probleme mit dem Audioeditor "Audacity" unter Windows und auf die 
SD Karte kopieren. So ist dem Klangbastler kaum eine Grenze gesetzt.



Bild 2: Datenstruktur auf der SD Karte für meinen Synthesizer
(Kleiner Fehler in der Zeichnung: sollten 100 statt 99 Bänke sein).

Bild 3-4: Datei Menü in meinem Synthesizer


Bild 5: SD Karte Interface in meinem Synthesizer
Wave1Disk.jpg


Wer sich näher mit der Benutzung einer SD Karte für ein eigenes Projekt 
mit einem Mikrocontroller wzB ATmega oder Arduino beschäftigen möchte 
hier ein paar nützliche Links:

http://www.ulrichradig.de/home/index.php/avr/mmc-sd
http://www.mikrocontroller.net/articles/AVR_FAT32
http://arduino.cc/de/Reference/SDCardNotes

Bis zum nächsten Mal und lieben Gruß. Rolf

Autor: Rolf D. (rolfdegen)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallöchen..
GIF-Format hochladen. Siehe Bildformate.
Text:

Zur Zeit wird mal wieder viel gelötet, gezeichnet und es werden 
Stücklisten geschrieben. Eine kleine Änderung gibts in der VCA 
Schaltung. Diese hat eine Lautstärkeregelung bekommen.

Bild1: VCA Schaltung mit Lautstärkeregelung


Die Stromversorgung für den Synth wurde ebenfalls etwas abgeändert und 
auf "Low cost" getrimmt. Ein AC-Netzteil mit 9 Volt/1000mA wird 
benötigt.

Bild2: Stromversorgung für den Synth

Ich bin gerade dabei das endgültige Layout für meinen Synthesizers auf 
einer Lochrasterplatte zu löten und dann ein PCB Board zu entwerfen. 
Dabei spielt die Positionierung der Bauteile eine wichtige Rolle. Die 
Platine habe ich in zwei Hälften unterteilt. Auf der linken Seite ist 
der ganze Analoge Teil wzB Stromversorung und der analoge Multimode 
Filter untergebracht. Auf der rechten Seite der komplette Digitalteil 
wzB Prozessor, Ram und SD-Karte. Das soll den Störeinfluss der 
Digitalschaltung auf die analoge Filterschaltung vermindern. Die 
Position des SD-Karteneinschubs habe ich zwecks besserer Bedienbarkeit 
nach vorne an die Gerätefront verlegt.

Bild3-7: Prototyp Synthesizer "WAVE 1"

Die Filterschaltung ist noch nicht ganz bestückt. Im Moment arbeite ich 
daran.

Bis zum nächsten mal. Lieben Gruß aus Wuppertal smile

: Bearbeitet durch User