Kommandozeilenparser ~~~~~~~~~~~~~~~~~~~~ Datenquellen ~~~~~~~~~~~~ Es sind nacheinander drei Datenquellen abzuscannen: - Systemweite Defaults - Userspezifische Defaults - Kommandozeile Die systemweiten und userspezifischen Einstellungen sind über ein Filehandle zu bekommen, in dem Newline-terminierte Argumente stehen: extern int GetProgrammDefaultsMachine ( const char* ProgramBaseName ); extern int GetProgrammDefaultsUser ( const char* ProgramBaseName ); Die Kommandozeile erfährt das Modul über einen von außen zu tätigen Aufruf: void setargv ( int argc, char** argv ); Je nach Betriebssystem kann dabei argv schon Wildcards aufgelöst haben oder nicht. ================================================================================================= Lesen und Schreiben von PCM-Dateien ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Alle Interaktion der AUDIO-Lib geschehen über einen Zeiger von Typ AUDIO. Es handelt sich dabei um eine anonyme Struktur von einem ähnlichen Schlage wie die berühmte Struktur FILE, die in C für gepufferte Ein- und Ausgaben benutzt wird. Gewonnen wird sie durch die Funktionsaufrufe audio_open_XXXXX und audio_create_XXXXX. Sie enthält alle für die AUDIO-Lib intern notwendigen Daten. Vernichtet wird die Struktur mittels audio_close(AUDIO*); typedef struct { unsigned long AUDIO_Signature; // Signatur zum Erkennen gültiger AUDIO*-Strukturen unsigned int AUDIO_Length; // Länge dieser Struktur (kann auch für Version-Checks mißbraucht werden) int AUDIO_fd; // HANDLE oder SOCKET (Windows) oder int (Unix) int MIXER_fd; long double SampleFreq; // Sample Frequenz unsigned int Channels; // Anzahl der Kanäle unsigned long long Length; // Gesamtlänge in Samples pro Channel (oder -1 falls unendlich) unsigned long long Position; // Aktuelle Position unsigned int BitsPerSample; // Benutzte Bits pro Sample enum Coding; // linear, alaw, µlaw (ADPCM würde ich nicht unterstützen) unsigned long long HeaderSize; // Offset des ersten Samples in der Datei unsigned int IsSeekable : 1; // seek() works unsigned int IsSocket : 1; // socket(), es ist mit recv/recvfrom und send/sendto statt mit read/write zu arbeiten unsigned int UsesPopen : 1; // 1, wenn Daten von einem Coprozeß generiert werden unsigned int UseDither : 1; // Erst in den 2.xx-Versionen benutzt unsigned int UseShapedDither : 1; // Erst in den 2.xx-Versionen benutzt unsigned int UseNoiseShaping : 1; // Erst in den 2.xx-Versionen benutzt const signed short* RecodingTable; // µlaw, Alaw, DAT-LongPlay etc. float DitherLevel; const float* DitherShapingCoeff; // const float* NoiseShapingCoeffs; // NoiseShapingCoeffs[16], immer NS 16. Ordnung ... } AUDIO; Normalerweise legt die Quelldatei (WAV, AIFF, CDDA) gewisse Parameter fest. Beim Schreiben von Daten oder bei Ausgabe auf einer Audiokarte gibt es so was nicht, dort müssen solche Parameter zusätzlich festgelegt werden. Die real eingestellten Parameter können aber von den geforderten abweichen (z.B. Samplefrequenz) oder völlig anders sein (16 bit trotz geforderter 24 bit). Dies ist durch die Inspect-Funktionen herauszufinden (es würde aber auch gehen, daß die richtigen Werte in die Struct zurückgeschrieben werden). typedef struct { unsigned int Channels; unsigned int BitsPerSample; enum Coding; long double SampleFreq; } AUDIO_ioctl; Audioströme können aufgemacht zum Lesen werden mittels: AUDIO* audio_open_filename ( const char* filename, unsigned int ChunkNumber ); AUDIO* audio_open_filedescriptor ( int fd, unsigned int ChunkNumber ); AUDIO* audio_open_socket ( const char* IP, unsigned short Port, unsigned char TTL, int socktype, int prototype, ... ); AUDIO* audio_open_socketdescriptor ( int socket_fd ); AUDIO* audio_open_http ( const char* URL ); AUDIO* audio_open_module ( const char* ModuleName, ... ); AUDIO* audio_open_device ( const char* DeviceName, const char* MixerName, AUDIO_ioctl* format, ... ); AUDIO* audio_open_cuesheet ( const char* filename ); XXX_filename: Daten werden aus einem Filename-Descriptor spezifiziert. Es kann sich hierbei um eine reguläre Datei, eine Named Pipe oder einen lokalen Socket handeln. Audiodevices sollten damit nicht aufgemacht werden, dafür ist XXX_device da, das u.a. ein Mixerdevice mit erhält und bei dem Formatspezifikationen via format übergeben werden können. XXX_cuesheet liest das Cuesheet aus (Datei) und arbeitet alle enthaltenen Dateien der Reihe nach ab. XXX_filedescriptor arbeitet wie XXX_filename, es wird aber kein Name, sondern ein Handle übergeben. XXX_socket öffnet einen Socket auf der IP:Port u.s.w.. Alle Daten, die von diese socket kommen, sind z.B. als MP3/WAV oder was auch immer Stream zu interpretieren (OSI Layer 3 oder 4 Stream). XXX_socketdescriptor wird ähnlich zu XXX_filedescriptor schon mit einem fertigen Socket-Handles. XXX_http arbeitet auf OSI Layer 5, d.h. hier ist z.B. noch eine Filauswahl und ähnliches möglich. XXX_module bekommt den Namen eines *.so-Modules sowie Inititialisierungsparameter mit übergeben. Gedacht für berechnete Signale. AUDIO* audio_create_filename ( const char* filename, AUDIO_ioctl* format, unsigned int ChunkNumber ); AUDIO* audio_create_filedescriptor ( int fd, AUDIO_ioctl* format ); AUDIO* audio_create_socket ( const char* IP, unsigned short Port, AUDIO_ioctl* format, unsigned char TTL, int socktype, int prototype, ... ); AUDIO* audio_create_socketdescriptor( int socket_fd ); AUDIO* audio_create_device ( const char* DeviceName, const char* MixerName, AUDIO_ioctl* format, ... ); Das gleiche noch mal für die Ausgabe. Unterschied zu den audio_open_XXX-Rufen ist, daß hier eine Format-Spezifier Pflicht ist. int audio_flush ( AUDIO* ap ); off_t audio_seek ( AUDIO* ap, int whence, signed long long offset ); // in samples statt in bytes off_t audio_tell ( AUDIO* ap ); // in samples statt in bytes off_t audio_filelength ( AUDIO* ap ); // in samples statt in bytes int audio_close ( AUDIO* ap ); int audio_eof ( AUDIO* ap ); int audio_error ( AUDIO* ap ); int audio_channels ( AUDIO* ap ); long double audio_samplefreq ( AUDIO* ap ); int audio_ioctl ( AUDIO* ap, AUDIO_ioctl* format ); Nun die eigentlichen Funktionen zum Lesen und Schreiben: size_t audio_read_interleaved_int16 ( AUDIO* ap, int16_t* dst, size_t len ); size_t audio_read_interleaved_int32 ( AUDIO* ap, int32_t* dst, size_t len ); size_t audio_read_interleaved_float32 ( AUDIO* ap, float32_t* dst, size_t len ); size_t audio_read_interleaved_float64 ( AUDIO* ap, float64_t* dst, size_t len ); size_t audio_read_consequent_int16 ( AUDIO* ap, int16_t* dst, size_t len ); size_t audio_read_consequent_int32 ( AUDIO* ap, int32_t* dst, size_t len ); size_t audio_read_consequent_float32 ( AUDIO* ap, float32_t* dst, size_t len ); size_t audio_read_consequent_float64 ( AUDIO* ap, float64_t* dst, size_t len ); size_t audio_read_indirect_int16 ( AUDIO* ap, int16_t** dst, size_t len ); size_t audio_read_indirect_int32 ( AUDIO* ap, int32_t** dst, size_t len ); size_t audio_read_indirect_float32 ( AUDIO* ap, float32_t** dst, size_t len ); size_t audio_read_indirect_float64 ( AUDIO* ap, float64_t** dst, size_t len ); size_t audio_write_interleaved_int16 ( AUDIO* ap, const int16_t* dst, size_t len ); size_t audio_write_interleaved_int32 ( AUDIO* ap, const int32_t* dst, size_t len ); size_t audio_write_interleaved_float32 ( AUDIO* ap, const float32_t* dst, size_t len ); size_t audio_write_interleaved_float64 ( AUDIO* ap, const float64_t* dst, size_t len ); size_t audio_write_consequent_int16 ( AUDIO* ap, const int16_t* dst, size_t len ); size_t audio_write_consequent_int32 ( AUDIO* ap, const int32_t* dst, size_t len ); size_t audio_write_consequent_float32 ( AUDIO* ap, const float32_t* dst, size_t len ); size_t audio_write_consequent_float64 ( AUDIO* ap, const float64_t* dst, size_t len ); size_t audio_write_indirect_int16 ( AUDIO* ap, const int16_t** dst, size_t len ); size_t audio_write_indirect_int32 ( AUDIO* ap, const int32_t** dst, size_t len ); size_t audio_write_indirect_float32 ( AUDIO* ap, const float32_t** dst, size_t len ); size_t audio_write_indirect_float64 ( AUDIO* ap, const float64_t** dst, size_t len ); Zu interpretieren: *_int16: Daten werden als 16 bit signed integer abgespeichert. *_int32: Daten werden als 32 bit signed integer abgespeichert. *_float32: Daten werden als 32 bit FP abgespeichert. *_float64: Daten werden als 64 bit FP abgespeichert. *interleaved*: Werte sind interleaved, dst-typ wäre damit eigentlich so was wie int16 [len][channels]; *consequent*: Werte sind hintereinander, dst-typ wäre damit eigentlich so was wie int16 [channels][len]; *indirect*: dst zeigt auf ein Array mit je einem Eintrag pro Channel. Dieser zeigt auf die Daten. dst-typ wäre damit eigentlich so was wie *int16 [channels]; Pflicht für die erste Implementierung: AUDIO* audio_open_filename ( const char* filename, unsigned int ChunkNumber ); // Unterstützung von FLAC, LPAC, SZIP etc. über Koprozesse AUDIO* audio_open_filedescriptor ( int fd, unsigned int ChunkNumber ); AUDIO* audio_open_device ( const char* DeviceName, const char* MixerName, AUDIO_ioctl* format, ... ); // Windows und Linux AUDIO* audio_create_filename ( const char* filename, AUDIO_ioctl* format, unsigned int ChunkNumber ); AUDIO* audio_create_filedescriptor ( int fd, AUDIO_ioctl* format ); AUDIO* audio_create_device ( const char* DeviceName, const char* MixerName, AUDIO_ioctl* format, ... ); // Windows und Linux size_t audio_read_interleaved_int16 ( AUDIO* ap, int16_t* dst, size_t len ); size_t audio_read_interleaved_int32 ( AUDIO* ap, int32_t* dst, size_t len ); size_t audio_read_interleaved_float32 ( AUDIO* ap, float32_t* dst, size_t len ); size_t audio_read_interleaved_float64 ( AUDIO* ap, float64_t* dst, size_t len ); size_t audio_write_interleaved_int16 ( AUDIO* ap, const int16_t* dst, size_t len ); size_t audio_write_interleaved_int32 ( AUDIO* ap, const int32_t* dst, size_t len ); size_t audio_write_interleaved_float32 ( AUDIO* ap, const float32_t* dst, size_t len ); size_t audio_write_interleaved_float64 ( AUDIO* ap, const float64_t* dst, size_t len ); int audio_flush ( AUDIO* ap ); off_t audio_seek ( AUDIO* ap, int whence, signed long long offset ); // in samples statt in bytes off_t audio_tell ( AUDIO* ap ); // in samples statt in bytes off_t audio_filelength ( AUDIO* ap ); // in samples statt in bytes int audio_close ( AUDIO* ap ); int audio_eof ( AUDIO* ap ); int audio_error ( AUDIO* ap ); int audio_channels ( AUDIO* ap ); long double audio_samplefreq ( AUDIO* ap ); int audio_ioctl ( AUDIO* ap, AUDIO_ioctl* format );