Forum: Mikrocontroller und Digitale Elektronik Mischen von digitalen Sounds


von Dominik Walter (Gast)


Lesenswert?

Hi!

Mir hat der Thread Xmega Soundcheck von Kai ziemlich viel geholfen bei 
einem kleinen Sound Projekt an dem ich derzeit arbeite ( Xmega1A 
Xplained Board ) .
Jetzt bin ich allerdings an einer Stelle angelangt an der mein Gehirn 
einfach nur aussetzt. Wenn ich jetzt 2 Sound-Dateien als C-arrays habe 
und diese mixen will, wie gehe ich  da am besten vor?

ich weiss nicht ob das hier richtig ist:

(soundbyte-A / 2) + (soundbyte-B /2)

Wichtig ist auch noch. Der erste Sound der läuft ist im Grunde ein 
Dauerloop eines Motoren-Geräuschs   darüber möchte ich aber nun z.b noch 
ein Horn oder ne Glocke spielen lassen , welche im Grunde jederzeit 
starten können sollen.

Ich bin mir nicht sicher wie man hierbei vorgehen muss, daher wäre ich 
für Rat sehr dankbar !

gruß Dominik

von Hannes L. (hannes)


Lesenswert?

Da gibt es verschiedene Varianten. Z.B. beide 8-Bit-Samples addieren 
(Übertrag landet im Carry) und dann einmal nach rechts rotieren (durch 2 
teilen, incl. Carry).

Wenn ich mehr Stimmen brauche, summiere ich die Sounds mit Übertrag in 
zwei Register (16-Bit-Variable) und teile sie anschließend durch die 
Anzahl der Stimmen (Kanäle). Dabei achte ich darauf, dass die Anzahl 
eine Zweierpotenz ist. (M)ein Dampflokgeräusch mit Tiny85 hat z.B. 4 
Stimmen. Davon ist eine für die Glocke reserviert, drei für die 
Dampfstöße. Alle Sounds enden im Loop für das Grundrauschen (Sieden). 
Die Dampfstöße werden von einem Radsensor ausgelöst, dabei wird die Spur 
hochgezählt und die Adressdaten (Anfang, Ende) in ein Array gelegt. Die 
Ausgaberoutine gibt den Sound aus, bis die Endadresse erreicht ist und 
fälscht den Zeiger dann auf den Siedeloop, der bei Erreichen der 
Siede-Endadresse wieder auf Siede-Anfang gesetzt wird. Durch den Einsatz 
von 3 Spuren für Dampfausstöße können zwei vorherige Dampfausstöße 
gemütlich zu Ende laufen, während der dritte gestartet wird. Das klingt 
irgendwie besser als wenn der vorherige Dampfstoß abgewürgt wird. Der 
Platz im Tiny85 reicht allerdings nicht mehr für eine Dampf-Pfeife, die 
kommt dann auf ein Soundrecorder-Modul und wird in den NF-Pfad zum LM386 
eingekoppelt.
Bei der Diesel-Version passen Anlasser, Diesel, Glocke und Horn in einen 
Tiny85. Bei der Dampf-Version Glocke, Sieden und zwei verschiedene 
Dampfstöße. Letztere deshalb, um jedes vierte (oder sechste bei 
Verbund-Lok) mal einen anderen Sample zu benutzen, damit es nicht wie 
ein Maschinengewehr klingt.

Das Tiny85-Soundmodul sieht dann so aus:
http://www.hanneslux.de/planet5b/Harzkamel/DSCN0003.JPG

...

von Dominik Walter (Gast)


Lesenswert?

>> Alle Sounds enden im Loop für das Grundrauschen (Sieden).

Das heißt im Grunde genommen werden die anderen Sounds nur in das 
Grund-Rauschen "eingekoppelt" mathematisch? also in den jeweiligen 
Buffer?

von Hannes L. (hannes)


Lesenswert?

Dominik Walter schrieb:
>>> Alle Sounds enden im Loop für das Grundrauschen (Sieden).
>
> Das heißt im Grunde genommen werden die anderen Sounds nur in das
> Grund-Rauschen "eingekoppelt"

Naja, eher "ersetzt"... Das gilt aber nur für die Dampf-Variante. Beim 
Diesel hat jedes Geräusch seine eigene "Spur", der Motor (und Anlasser) 
auch noch seinen eigenen Timer-Interrupt wegen der Drehzahländerung 
(Änderung der Ausgaberate).

> mathematisch? also in den jeweiligen
> Buffer?

Es laufen (beim Dampf) 4 Spuren. Jede Spur gibt das Grundrauschen (sehr 
geringe Lautstärke, also Werte um die 128) aus, solange sie nichts "zu 
tun" hat. Die Zeiger auf die Streams (laufende Adresse und Endadresse) 
liegen in einem Array. Dies ermöglicht Gleichbehandlung aller Spuren 
(durch Unterprogramm, das nur den Index übergeben bekommt) bei der 
Ausgabe, reduziert also den Programmcode. Erreicht die (im Array 
gehaltene) laufende Adresse einer Spur die (auch im Array liegende) 
Endadresse, so wird die laufende Adresse auf Anfang des Grundrauschens 
"gefälscht".

Um einen Sound zu starten, wird nur Anfangs- und Endadresse (Flash) des 
entsprechenden Sounds in das Array geschrieben. Den Rest macht die 
Ausgaberoutine dann selbst.
Der Start wird über Steuerleitungen ausgelöst, die softwaremäßig 
entprellt werden. Für die Glocke läuft ein eigener Zähler, der über die 
Steuerleitung auf Startwert gesetzt wird. Bei Auslösung durch 
Fernsteuerung (DCC, Funk) wird dieser auf 1 gesetzt. Soll die Glocke 
über einen am Gleis "vergrabenen" Magneten ausgelöst werden, wird der 
Zähler auf die Anzahl der gewünschten Glockenschläge gesetzt.

Ich habe vor, das Ganze irgendwann noch mal mit einem Mega1284 
umzusetzen, um mit höherer Samplerate und mehr (und längeren) Sounds 
arbeiten zu können. Mich stört dabei aber etwas, dass es keine PLL für 
Timer gibt, die PWM-Frequenz des als DAC genutzten Timers also begrenzt 
ist. Ein externer DAC macht die Sache ja wieder komplizierter. Mit dem 
Tiny85 erreicht man ja ohne Klimmzüge 250 kHz PWM-Frequenz, was die 
Ansprüche an den Tiefpass erheblich reduziert. Ideal dafür wäre ein 
Tiny25 mit 1 oder 16 MB internem EEP (der auch gut als Datenlogger 
geeignet wäre). Aber den haben wir leider nicht... 8-(

...

von Mirko (Gast)


Lesenswert?

Dominik Walter schrieb:
> (soundbyte-A / 2) + (soundbyte-B /2)

Wichtig ist halt, dass Du die Division nicht nur durchführst, wenn beide 
Sounds ertönen, weil Du sonst den Loop immer in der Lautstärke 
veränderst, wenn was anderes dazu kommt (gern gemachter Anfängerfehler 
:). Wenn es immer nur um die zwei Sounds geht, kannst Du die Werte auch 
von vornherein auf 7 Bit reduzieren, dann sparst Du Dir die Division.

Mirko

von Dominik Walter (Gast)


Lesenswert?

Ich habe es jetzt so weit das ich insgesamt 8 Kanäle gleichzeitig 
abspielen kann.  Insgesamt auf einige Timer verteilt (Motor / 
Anlasser/gas-geben ist Pitch-bar).

Ich bin jetzt allerdings an der stelle angelangt wo der interne Flash 
Speicher nicht mehr ausreicht.

Im Augenblick arbeite ich mit 11khz bei 8bit , ich würde aber gerne 
wieder auf 22khz oder 44khz hoch , weil der 11khz sound doch sehr .. 
naja dürftig ist ;)

Ich würde daher gerne auf SD karte als Sound speicher gehen. Ich weis 
wie ich die SD-Lese-Routinen einbinden muss. allerdings ist mir das 
Konzept nicht ganz schlüssig wie ich es schaffe mehrere Sounds 
gleichzeitig von der SD karte abzuspielen. (sofern das überhaupt geht!) 
Der XmegaA1 auf dem ich arbeite hat zwar einen Externen RAM mit so weit 
ich weis 64Mbit (Xplained Board) , aber wie ich das genau in der 
Software anspreche weis ich noch nicht. Auch hatte ich in einem anderen 
Forum gelesen das es mit solch großen Ram-Bausteinen und AVR-GCC ein 
Problem gibt mit den 16bit Pointer und damit verbundenen maximal 
Adressierbaren speicher von 64k?

der Logik halber nach müsste ich (korrigiert mich wenn ich falsch liege) 
zu Anfang bei Programmstart von der SD karte die Sounds in den Externen 
RAM laden und dann den externen RAM in meine Abspiel-Routinen füttern , 
anstelle wie im Augenblick einfach auf Arrays im Programmspeicher zu 
verweisen.

Falls irgend jemand das schon gemacht hat und mir helfen kann ich bin 
für jeden Rat dankbar, da ich nun nach mehrmaligem suchen keine einfach 
verständliche Anleitung gefunden habe.

PS:  Eine Sache die ich nicht ganz verstehe...  wieso kann ich 
eigentlich bei meinem Xmega128  nur die ersten 64Kb für Progmem Daten 
verwenden?..

von Hannes L. (hannes)


Lesenswert?

Dominik Walter schrieb:
> wieso kann ich
> eigentlich bei meinem Xmega128  nur die ersten 64Kb für Progmem Daten
> verwenden?..

Ich habe zwar noch keinen Xmega eingesetzt, aber eigentlich sollte er 
das können. Das Register RAMPZ ist vorhanden und der Befehl ELPM wird 
auch unterstützt.

...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.