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