Letzte Änderungen: 12.03.2009

Zur Hauptseite kurs9


Audio innerhalb des MIDI-Sequencers

Grundsätzlich kann man eine komplette Audiospur wie ein einziges MIDI-Event behandeln. Das Audio-Event ist ein systeminternes Event, und triggert dabei eben keine MIDI-Geräte, sondern startet eine Audio-Datei, die meistens auf der Festplatte des Rechners vorhanden ist. Audio- und MIDI-Events können sogar auf ein und demselben Track liegen. Grundsätzlich kann statt einer Audio-Spur natürlich auch z.B. eine Videosequenz abgespielt werden. Die Audio-Dateien werden meistens im AIFF oder WAVE Format abgespeichert. Beschreibungen über das AIFF und das WAVE Format findet man im Internet. In beiden Formaten besteht die Audio-Datei aus einem (oder mehrer) Chunk/s, gefolgt von den eigentlich Audio-Daten, die im RAW-Format vorliegen. Üblicherweise liegen diese RAW-Audiodaten im 16 oder 24 Bit Auflösung/Sample, und 44.1, 48 oder 96 Khz Abtastung vor.

Beispiel eines Audio-Events (Hinweis: Die spätere Verwaltung von Events erfolgt später per C++ Klassen)

struct AudioEventNode
{
struct EventNode *ln_Succ; // Pointer to next ListNode (Successor)
struct EventNode *ln_Pred; // Pointer to previous ListNode (Predecessor)

UQWORD en_TimeStamp; // Die Uhrzeit des Audio/MIDI-Events - 64 Bit
struct *en_Pattern;// Zeiger auf das PatternUBYTE status; // Audio-Event

UBYTE *filename; // z.B. C:/hdrec/audiotest.wav
UBYTE typ; // Mono+Stereo
UQWORD en_Audiolänge // Länge der Audiodaten in ms oder als PPQ-Wert
UWORD bits; // 8,16,24 Bit auflösung
UWORD frequenz; // Abtastung
... weitere Informationen
};
typedef struct AudioEventNode AudioEventNode_s;
typedef struct AudioEventNode *AudioEventNode_p;


Die Scan-Datei

Um eine Audio-Datei (Audio-Spur) grafisch darzustellen, muss man zusätzlich zu der Audio-Datei eine Scan-Datei erzeugen, die eine komprimierte, grafische Form der Audio-Daten darstellt, und zur optischen Anzeige und Editierung der Audio-Datei genutzt werden kann. Ob diese Scan-Datei aktuell ist kann man recht einfach per Datumsvergleich überprüfen, das Datum der Audio-Datei muss stets älter als das Datum der Scan-Datei sein, falls nicht muss die Scan-Datei eben neu erzeugt werden- die Audiodatei könnte irgendwie bearbeitet worden sein.


Das Abspielen von Audio-Spuren (Audio-Events)

Grundsätzliche Aufgabe des Audio-Sequencers ist das Transportieren der rohen Audio-Daten aus einer oder mehreren Audio-Daten zur einer oder mehreren Soundkarten. Dabei funktioniert der Sequencer praktisch wie ein analoges Tonband. Zum Abspielen einer Audio-Datei kann man das Double-Bufferprinzip verwenden - im Speicher des Rechners werden pro Audio-Datei 2 Buffer von x KByte-Grösse gehalten, die abwechselnd zur Soundkarte geschickt werden, während der andere Buffer mit neuen Audio-Daten aus der Audio-Datei aufgefüllt wird. Zwischen den Transfer der rohen Audio-Daten aus der Audio-Datei zur Soundkarte kann man einfache (z.B. Volumeänderung) oder komplexe Audio-Effekte (z.B. Echo) hängen, die diese Audio-Daten in Echtzeit bearbeiten. Diese Effekte besitzt entweder der Sequencer selber, oder können per Schnittstelle (Libraries) z.B. der VST-Schnittstelle eingebunden werden. Der Sequencer "füttert" diese Plugin-Effekte dann mit Audio-Daten und erhält bearbeitete Audio-Daten zurück und gibt diese dann an die Soundkarte weiter.

Da die Länge der Audio-Daten bekannt ist, kann man auch einen Audiospur starten, falls die Sequenceruhr "auf" der Audio-Spur liegt, indem man einfach per Fileystem abhängig von der Startposition der Audio-Datei und der Sequencerposition einen Seek-Befehl ausführt.

Beispiel: Startposition der Audio-Spur 1-1-1-1, Sequencerposition ist 2-1-1-1, die Audiospur ist 16-Bit Mono und 44.1 Khz.

In diesem Beispiel muss man also den Startpunkt der Audio-Datei um exakt einen Takt nach "rechts" verschieben. Es handelt sich hierbei z.B. um einen Song mit 130 BPM und 4/4 Takt.

1. Einrechnung des Tempo. Bei einem Tempo von 120 BPM ist die Länge einer 1/4 Note 500ms. Bei 130 BPM (120/130 BPM =) 0.92*500ms=461ms. Hinweis: Falls vor der Sequencerposition mehrere Tempowerte liegen muss man diese natürlich per Schleifenberechnung einbeziehen.

2. Einrechung des Sequenceruhr. 1 Takt im 4/4 Song sind bei 130 BPM also 4*461ms=1846ms.Da die Audio-Datei eine 16 Bit Mono/44.1 Khz Auflösung hat, benötigt eine Millisekunde exakt (2 (sind ja 16 Bit) *44100)/1000 Bytes=88 Bytes. Um 1846 ms zu "seeken" muss man 1846*88 Bytes=162448 Bytes springen, um die Audio-Spur mit der Sequenceruhr zu "synchronisieren". Die Informations-Chunks der Wave oder AIFF Datei muss man dabei noch mit addieren !


Die Aufnahme von Audio-Spuren (Audio-Events)

Bei der Aufnahme arbeitet der Sequencer wie ein Tonbandgerät, per Doublebuffer werden die von der Soundkarte kommenden rohen Audio-Daten in eine vom Sequencer neu erzeugte Datei (entweder AIFF oder WAVE-Format) geschrieben. Grundsätzlich ist die Anzahl der gleichzeitig aufgenommenen Audio-Dateien (Audio-Spuren) nur durch die Leistung des Systems (also CPU, Festplatten, Festplattencontrollers) begrenzt. Nach der Aufnahme muss nur noch eine Scan-Datei erzeugt werden und die Audio-Spur kann bearbeitet und wieder abgespielt werden. Das Erzeugen der Scan Datei sollte von einem Hintergrundprozess erfolgen, damit das Hauptprogramm gleich wieder einsatzbereit ist.

Ausnutzung der Multi Core CPU's in der Audio Engine (Single Core Audio Engine und X Core Audio Engine)

Multi Core CPUs zeigen dort viel extra Leistung, wo parallele Daten bearbeitet/errechnet werden. Neben der sowieso vorhandenen Aufteilung des gesamten Programms in mehrere Processe (in CamX sind es alleine schon 12 Threads) gewinnt man CPU Leistung bei MC Cpu's durch Parallelisierung von Bearbeitungsabläufen. Als Programmierer muss man nach parallelen Abläufen suchen und diese in X Pipelines auftrennen, wobei X die Anzahl der Cores in der CPU sind. In einem Audio-Sequencer und somit auch in CamX befinden sich solche parallelen Pipelines in der Audioengine, dort speziell in den Audio Channels, die ja parallele Audio Bearbeitungs Prozesse sind.

CamX besitzt eine Single Core Audio Engine, eine X Core Audio Engine. Während bei einer Single Core Engine die gesamte Audio Engine seriell (in Echtzeit) durchgerechnet wird, kann man bei Multi Core CPU's die Berechnung der Audio Kanäle je einem Core zuordnen.

Beispiel:

Audio System besitzt 8 Kanäle/4 Cores besitzt die CPU

Core 1 Kanal 1 -> fertig Nr.1 (nimmt Kanal 5) ---> Kanal 5--->    
Core 2 Kanal 2 --->      
Core 3 Kanal 3 ---> fertig Nr. 2 (nimmt Kanal 6) ---> Kanal 6 --->    
Core 4 Kanal 4 -----> fertig Nr. 3 (nimmt Kanal 7) ---> Kanal 7 ---> fertig Nr 4. (nimmt Kanal 8) --->    

Am Ende der Kette (wenn alle Kanäle bearbeitet sind) erfolgt dann der Master Mix. Man kann innerhalb der Kanäle noch parallel arbeiten lassen, indem man z.b. Audio Instrumente/Effekte als Process laufen lässt.

Bei Tests haben sind pro CPU Core etwa 10-30% Leistungsgewinn ergeben je nach optimaler Auslastung der CPU Cores.