Tag zusammen,
hab mal eine Frage-
Vorgeschichte:
Ich habe ein mini Sampler für einen Atmega32 geschrieben. Dazu habe ich
mit audio-converter 8 Samples in (8 bit Mono 8000Hz) konvertiert und
diese auf den atmega in den flash geschrieben. Ein kleine Routine
verarbeitet dann einen ganz einfach gehalten Sequenzer der die Samples
abspielt. Ein 12 bit
Widerstandsnetzwerk sorgt für die DA-Umwandlung. Ich habe also an einer
Stelle acht byte-werte (jedes für ein Sample) die ich mischen möchte.
Bis dato gehe ich einfach hin und addiere alle acht werte und gebe sie
auf dem DA-Wandler aus.
OUT = S1 + S2 + S3 + S4 + S5 + S6 + S7 + S8
8 * 255 = 2040 als maximalen Wert der ausgegeben werden muss
Das sollte also mit dem 12bit wandler kein problem sein. Las ich nun
einzelne Samples abspielen geht alles gut, klingt "sauber" solange man
das bei 8 bit sagen kann. Wobei die Basedrums und Toms gar nicht so
schlecht klingen.
Meine Frage:
Gibt es eine bessere / richtige Möglichkeit die Samplewerte zu mischen?
Die Lautstärke könnte ich so regeln, oder?
Wobei Vn ein Wert zwischen 0 und 1 sein sollte.
OUT = (S1*V1) + (S2*V2) + (S2*V2) + ...
Ideen, Kritik alles erwünscht. Danke schonmal.
Hallo Jonas,
um mehrere Samples zu mischen erst mal etwas Mathe.
Wenn du mehrere Samples mit 8 Bit Auflösung mischst
ist auch das Ergebnis nur in 8 Bit aufgelöst.
In deiner Rechnung fehlt der Teiler durch die Anzahl
der gemischten Samples :
Out = ( In1 + In2 + ... + InX ) /X
Da du eine 32 Bit CPU benutzt solltest du im Programm Code
darauf achten, das du keine Rechenfehler (durch falsche Rundung )
bekommst durch 8 Bit Variablen ( das Ergebnis der Addition von 2
8 Bit Variablen muss in einer 16 Bit Variablen gespeichert werden.
Das Selbe gilt bei der Division : Das teilen einer 16 Bit
Variablen durch eine 8 Bit Variablen hat muss als Ziel eine 16 Bit
Variable haben. Der Compiler rundet und wandelt zwischen den
Variablengrössen gerne mal anders als man erwartet.
Zum Test der Software ist es praktisch, 2 Samples mit einem Sinus
mit der Frequenz 1 kHz und 2 kHz abzuspielen und die Ausgabe sich
auf dem Oszilloskop anzuschauen. Zusammengemischt sollten die Peak
Werte nicht höher sein als ein Peak wert eines einzelnen Samples.
Wenn dein DA Wandler nur positive Spannungen erzeugt, kann die
Tonqualität
auf einen Audio Verstärker noch besser werden, wenn du mit einem
Kondensator den Gleichstromanteil ausfilterst.
Perfekt wird es erst wenn du in Software mit vorzeichenbehafteten Werten
rechnest und die Wandlung ebenso erfolgt.
Gruß,
dasrotemopped.
dasrotemopped schrieb:
Mit dem meisten bin ich einverstanden. Aber ein paar Punkte lassen mir
dann doch die Haare zu Berge stehen.
> Da du eine 32 Bit CPU benutzt
Prust. Nö, auch ein Mega32 ist nur eine 8 Bit CPU.
Das 32 im Namen bezieht sich auf die Größe des Flash
> solltest du im Programm Code> darauf achten, das du keine Rechenfehler (durch falsche Rundung )> bekommst durch 8 Bit Variablen ( das Ergebnis der Addition von 2> 8 Bit Variablen muss in einer 16 Bit Variablen gespeichert werden.
Soweit, so gut
> Das Selbe gilt bei der Division : Das teilen einer 16 Bit> Variablen durch eine 8 Bit Variablen hat muss als Ziel eine 16 Bit> Variable haben.> Der Compiler rundet
Nö
> und wandelt zwischen den> Variablengrössen gerne mal anders als man erwartet.
Auch das nicht.
Je nachdem was genau du unter "Compiler" verstehst. Ich geh mal von
einem C Compiler und Integer Rechnung aus. Die Regeln, wie die
Operationen ausgeführt werden, sind eindeutig festgelegt. Wenn da also
nicht das passiert, was du erwartest, dann ist deine Erwartung falsch.
Ein Blick in die nächstbeste C-Literatur kann das aber beheben.
Und nein: Bei Integer-Rechnungen wird überhaupt nicht gerundet. Die
Berechnung wird so durchgeführt, als ob entstehende Kommastellen einfach
abgeschnitten werden würden. Das ist sogar so etwas wie ein allgemeines
Prinzip, da es auch dann zur Anwendung kommt, wenn ein Floating Point
Ergebnis an einen Integer zugewiesen wird.
Mea culpa,
Hat sich ein Tippfehler schwer ausgewirkt :
> Da du eine 32 Bit CPU benutzt
korrigiert : Da du >k<eine 32 Bit CPU benutzt
Warum sollte ich mir Gedanken um 8 oder 16 Bit machen wenn ich als
default 32 Bit zur Verfügung habe ?
Und mit Rundung meinte ich Über/Unterlauf bei einer Rechenoperation.
Der C Kompiler mag nach Definition immer richtig arbeiten, nur hat man
nicht immer alle Definitionen auswendig im Kopf oder beachtet nicht alle
beim Programmieren.
Daher auch mein Tip, die Rechenergebnisse per Oszilloskop zu
"überprüfen".
@MCUA
Welchen Mischalgorithmus würdest du Jonas denn bei seiner Frage
empfehlen ?
Gruß,
dasrotemopped
dasrotemopped schrieb:> Mea culpa,>> Hat sich ein Tippfehler schwer ausgewirkt :>>> Da du eine 32 Bit CPU benutzt> korrigiert : Da du >k<eine 32 Bit CPU benutzt
Bamm! (das war die Stirn, die auf der Tischplatte aufschlägt)
Jetzt ergibt auch der komplette Satz auf einmal Sinn. Und ich hab mich
schon gefragt: Was will uns der Dichter eigentlich sagen. Aber auf ein
fehlendes 'k' bin ich nicht gekommen.
> Und mit Rundung meinte ich Über/Unterlauf bei einer Rechenoperation.> Der C Kompiler mag nach Definition immer richtig arbeiten, nur hat man> nicht immer alle Definitionen auswendig im Kopf oder beachtet nicht alle> beim Programmieren.
Na ja
Die sollte man aber eigentlich schon im Kopf haben. Das man nicht immer
darauf achtet, gestehe ich gerne zu. Nichts desto trotz sollte das so
selbstverständlich sein, wie 'Punkt vor Strich'-Rechnen in der
Mathematik.
dasrotemopped schrieb:> um mehrere Samples zu mischen erst mal etwas Mathe.> Wenn du mehrere Samples mit 8 Bit Auflösung mischst> ist auch das Ergebnis nur in 8 Bit aufgelöst.
Ich denke da hat MCUA schon recht, das ist eine Definitionsfrage. Das
Ergebnis muss doch keineswegs wieder in den gleichen Wertebereich
gezwängt werden. Da er den Hardwareaufwand offenbar nicht scheut, ist
Jonas' Lösung doch durchaus besser.
Bei den 12-bit mit R2R stellt sich mir aber die Frage, ob das an den
Ausgängen eines 8-bit µC so einfach geht. Irgendwo habe ich mal eine
Lösung mit zwei 8-bit D-Flipflops gesehen, die erst mit je einem Byte
eines 16-Bit-Samples geladen wurden um das dann gleichzeitig auf das
Wiederstandsnetz loszulassen. Wenn man direkt die Ausgänge des AVR
nimmt, dann hat man doch das Problem, dass der Wert zwischen zwei
Kopieraktionen mal nicht stimmt, oder geht das irgendwie einfacher?
Mich würde das Projekt durchaus mal näher interessieren, einen
Drumcomputer möchte ich auch irgendwann mal bauen.
Mirko