Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Linux-UNIX-Programmierung von Jürgen Wolf
Das umfassende Handbuch – 2., aktualisierte und erweiterte Auflage 2006
Buch: Linux-UNIX-Programmierung

Linux-UNIX-Programmierung
1216 S., mit CD, 49,90 Euro
Rheinwerk Computing
ISBN 3-89842-749-8
gp Kapitel 16 SDL
  gp 16.1 Was ist und kann SDL?
  gp 16.2 SDL installieren
  gp 16.3 SDL-Anwendungen erstellen
  gp 16.4 SDL initialisieren und Videomodus einstellen
    gp 16.4.1 Programmbeispiel – SDL initialisieren und Videomodus einstellen
  gp 16.5 Direkt auf den Bildschirm zeichnen
    gp 16.5.1 Programmbeispiel – direkt auf den Bildschirm zeichnen
  gp 16.6 Bitmap laden und anzeigen
    gp 16.6.1 Programmbeispiel – Bitmap laden und anzeigen
  gp 16.7 Ein anderes Grafikformat laden und anzeigen
  gp 16.8 Der rechteckige Bildbereich von SDL
  gp 16.9 Farbenschlüssel, Transparenz und Alpha-Blending
    gp 16.9.1 Alpha-Blending
  gp 16.10 Animation
    gp 16.10.1 Programmbeispiel – Animation
  gp 16.11 Eingabe- und Ereignisverarbeitung
    gp 16.11.1 SDL-Event-Struktur
    gp 16.11.2 Maus-Events
    gp 16.11.3 Programmbeispiel – Maus-Event
    gp 16.11.4 Tastatur-Events
    gp 16.11.5 Programmbeispiel – Tastatur-Events
    gp 16.11.6 Joystick-Events
    gp 16.11.7 Programmbeispiel – Joystick-Events
    gp 16.11.8 Weitere Events
  gp 16.12 Audio
    gp 16.12.1 Programmbeispiel – Audio
  gp 16.13 Ausblick


Rheinwerk Computing

16.12 Audio  downtop

Ein Spiel ohne Geräusche kann auf Dauer keinen Spaß machen. Man muss ja nicht gleich einen hitverdächtigen Song hinzufügen, aber einige kleine Soundeffekte können nicht schaden. Das Thema Sound & Audio wird in der Spieleprogrammierung recht selten behandelt. Ein Grund dafür ist, dass dieses Thema schon einiges an Grundverständnis über Musik & Computer abverlangt. So dürfte auch klar sein, dass diese Einführung hier nicht mehr ist als eine kurze oberflächliche Einführung, wie Sie den einen oder anderen Ton Ihrer Anwendung hinzufügen können. Den meisten unter Ihnen dürfte das aber in der Regel ausreichen (dem Autor auf jeden Fall, da dieser sich als außerordentlich unmusikalisch einstuft). Daher orientiert sich der Autor ausnahmsweise mehr oder weniger an der Dokumentation von SDL, in dem Vertrauen, dass die Autoren dabei schon wissen, wovon Sie reden.


Hinweis   Da hier, abgesehen von der Funktion SDL_OpenAudio(), die Funktionen nicht genauer erklärt werden, sei hierzu die Dokumentation bzw. Manual Page für die Syntaxbeschreibung und die einzelnen Parameter empfohlen.


Vereinfacht: Musik auf dem Computer ist eine Übersetzung von Wellen, die Sie in einer Serie von Werten hören, wovon jeder Wert einer Schwingungsweite der Welle entspricht. Werden diese Werte in einen Stream der Soundkarte geschickt, kann eine Annäherung an den Originalwellen wieder erzeugt werden.

SDL unterstützt hierbei das Audio-Format 8 und 16 Bit mit einer Frequenz zwischen 11025 Hz und 44100 Hz. Diese Werte sind abhängig von der Hardware. Sofern die Hardware das Audioformat oder die Frequenz nicht unterstützt, kann diese auch emuliert werden. Gewöhnlich unterstützt aber jede gängige Hardware das Audio-Format 16 Bit und eine Frequenz von 22050 Hz.

Um etwas auf dem Lautsprecher auszugeben, müssen Sie zuerst das Audiogerät öffnen. Dies erledigen Sie mit der Funktion:

int SDL_OpenAudio( SDL_AudioSpec *desired,
                   SDL_AudioSpec *obtained);

Als Parameter müssen Sie hierbei mindestens die Angaben für desired vom Typ SDL_AudioSpec machen. SDL_AudioSpec ist eine Struktur, die wie folgt definiert ist:

typedef struct {
  int freq;
  Uint16 format;
  Uint8 channels;
  Uint8 silence;
  Uint16 samples;
  Uint32 size;
  void (*callback)(void *userdata, Uint8 *stream, int len);
  void *userdata;
} SDL_AudioSpec;

Um also ein Audiogerät zu öffnen, müssen Sie diese Struktur erst mit entsprechenden Werten füllen. Mit freq geben Sie die Anzahl der Samples an, die an das Soundgerät pro Sekunde gesendet werden. Je höher dieser Wert ist, umso besser. Gewöhnliche Werte sind hierbei 11025 Hz, 22050 Hz und 44100 Hz. Mit format geben Sie die Größe in Bits und den Typ des Samples an. Mögliche Werte und deren Bedeutung sind hierbei:


Tabelle 16.7    Mögliche Angaben für den Parameter format

Parameter format Bedeutung
AUDIO_U8 Unsigned 8 Bit Samples
AUDIO_S8 Signed 8 Bit Samples
AUDIO_U16 AUDIO_U16LSB Unsigned 16 Bit little-endian Samples
AUDIO_S16 AUDIO_S16LSB Signed 16 Bit little-endian Samples
AUDIO_U16MSB Unsigned 16 Bit big-endian Samples
AUDIO_S16MSB Signed 16 Bit big-endian Samples
AUDIO_U16SYS Entweder AUDIO_U16LSB oder AUDIO_U16MSB; abhängig von der Anordnung der Byte-Reihenfolge des Systems (little- oder big-endian)
AUDIO_S16SYS Entweder AUDIO_S16LSB oder AUDIO_S16MSB; abhängig von der Anordnung der Byte-Reihenfolge des Systems (little- oder big-endian)

Mit channels geben Sie die Anzahl der Sound-Kanäle an. 1 steht hierbei für Mono (Single Channel) und 2 für Stereo (Dual Channel). silence ist ein Wert für einen Audio-Puffer, der berechnet wird.

Mit samples geben Sie die gewünschte Größe des Audio-Puffers eines Samples an. Dieser Wert sollte immer ein typischer Wert hoch 2 sein. Gewöhnliche Werte variieren zwischen 512 und 8192, was aber auch abhängig von der Geschwindigkeit der Anwendung und der CPU ist. Kleinere Werte bewirken eine schnellere Antwortzeit, können allerdings auch bewirken, dass der Puffer nicht in der geforderten Zeit gefüllt wird, wenn die Anwendung z. B. umfangreiche Berechnungen ausführt.

size ist wieder eine Audio-Puffergröße in Bytes, die berechnet wird. callback benötigen Sie, um die Adresse einer Callback-Funktion zu übergeben. Diese müssen Sie schreiben, da hiermit die Audio-Daten gemischt und in den Audio-Stream geschrieben werden. Erst danach können das Audio-Format und die Abtastrate ausgewählt und das Audio-Gerät geöffnet werden. userdata ist ein Zeiger auf den ersten Parameter der Callback-Funktion.

Bevor Sie jetzt den Sound abspielen können, muss zuvor noch die Funktion SDL_PauseAudio(0) aufgerufen werden. Dies ist nötig, da sonst sofort die Callback-Funktion angesprungen wird, bevor noch irgendetwas initialisiert werden konnte. Damit können Sie sicher die Callback-Funktion mit Daten initialisieren, nachdem ein Audiogerät geöffnet wurde.

Jetzt, wo Sie ein Audiogerät geöffnet haben, benötigen Sie als Nächstes die Funktion SDL_LoadWAV(), um die Audio-Daten zu laden. Dann müssen Sie eine Struktur vom Typ SDL_AudioCVT mit der Funktion SDL_Build_AudioCVT() mit Werten initialisieren, um eine Konvertierung durchzuführen. Dabei handelt es sich um die Werte des Quell- und Zielformats für die anschließende Konvertierung. Ebenfalls werden die Werte über die Anzahl der Kanäle (1 = Mono, 2 = Stereo) und die Frequenz (Samples pro Sekunde) jeweils vom Quell- und Zielformat benötigt. Die so mit Werten bestückte Struktur SDL_AudioCVT kann anschließend als Parameter für die Funktion SDL_ConvertAudio verwendet werden, um die Audio-Daten in das gewünschte Format zu konvertieren.

Anschließend sollten Sie mit SDL_LockAudio() die Callback-Funktion sperren, um so Initialisierungen der Daten, die Sie von der Konvertierung mit SDL_ConvertAudio() erhalten haben, durchzuführen. Nachdem Sie die Callback-Funktion mit SDL_UnlockAudio() wieder freigegeben haben, sollte die von Ihnen zur Verfügung gestellte Mixer-Funktion (Callback-Funktion) den Sound ausgeben. Am Ende sollten Sie das Audio-Gerät mit SDL_CloseAudio() wieder freigeben.


Hinweis   Ich denke, es versteht sich fast schon von selbst, dass Sie beim SDL_Init() das Flag SDL_INIT_AUDIO mit angeben müssen.



Rheinwerk Computing

16.12.1 Programmbeispiel – Audio  toptop

Das folgende Programmbeispiel demonstriert Ihnen die Verwendung von Audio-Daten (in diesem Beispiel einfache Wave-Dateien (*.wav)), die bei einem bestimmten Tastendruck vom Lautsprecher wiedergegeben werden sollten.

/* sdl10.c */
#include <SDL/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SOUNDS 5
struct sample {
  Uint8 *daten;
  Uint32 pos;
  Uint32 len;
} sounds[SOUNDS];
static void
AudioMixing (void *nichtVerwendet, Uint8 * stream, int laenge) {
  unsigned int i;
  Uint32 menge;
  for (i = 0; i < SOUNDS; ++i) {
    menge = (sounds[i].len - sounds[i].pos);
    if (menge > laenge) {
      menge = laenge;
    }
    SDL_MixAudio(stream, &sounds[i].daten[sounds[i].pos],
       menge, SDL_MIX_MAXVOLUME);
    sounds[i].pos += menge;
  }
}
static void
AudioPlay (const char *datei) {
  int index;
  SDL_AudioSpec wave;
  Uint8 *daten;
  Uint32 len;
  SDL_AudioCVT cvt;
  /* einen leeren Audio-Slot suchen */
  for (index = 0; index < SOUNDS; ++index) {
    if (sounds[index].pos == sounds[index].len) {
      break;
    }
  }
  if (index == SOUNDS)
    return;
  /* Audio-Datei laden und nach 16 Bit und 22 kHz wandeln */
  if (SDL_LoadWAV (datei, &wave, &daten, &len) == NULL) {
    fprintf (stderr, "Konnte '%s' nicht laden: %s\n",
       datei, SDL_GetError ());
    return;
  }
  SDL_BuildAudioCVT ( &cvt, wave.format, wave.channels,
                      wave.freq, AUDIO_S16, 2, 22050 );
  cvt.buf = malloc (len * cvt.len_mult);
  memcpy (cvt.buf, daten, len);
  cvt.len = len;
  SDL_ConvertAudio (&cvt);
  SDL_FreeWAV (daten);
  /* die Audiodaten in den Slot schreiben */
  /* (Abspielen startet sofort)           */
  if (sounds[index].daten) {
    free (sounds[index].daten);
  }
  SDL_LockAudio ();
  sounds[index].daten = cvt.buf;
  sounds[index].len = cvt.len_cvt;
  sounds[index].pos = 0;
  SDL_UnlockAudio ();
}
static int eventloop (void) {
  SDL_Event event;
  while (SDL_WaitEvent (&event)) {
    SDL_keysym keysym;
    switch (event.type) {
    case SDL_KEYDOWN:
      keysym = event.key.keysym;
      if (keysym.sym == SDLK_ESCAPE) {
        printf ("ESCAPE gedrückt.\n");
        return EXIT_SUCCESS;
      }
      if (keysym.sym == SDLK_a) {
        printf ("Alarm\n");
        AudioPlay ("alarm.wav");
      }
      if (keysym.sym == SDLK_c) {
        printf ("Cry in the hall\n");
        AudioPlay ("cry 2.wav");
      }
      if (keysym.sym == SDLK_b) {
        printf ("Blood\n");
        AudioPlay ("bloodflo.wav");
      }
      if (keysym.sym == SDLK_m) {
        printf ("Like a cat?\n");
        AudioPlay ("meeeow.wav");
      }
      if (keysym.sym == SDLK_z) {
        printf ("Are you angry?\n");
        AudioPlay ("zorn.wav");
      }
      break;
    case SDL_QUIT:
      printf ("Quit event. Bye.\n");
      return EXIT_SUCCESS;
    }
  }
  return 1;
}
int main (void) {
  SDL_Surface *screen;
  int done = 1;
  SDL_AudioSpec format;
  if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
    printf ("Unable to initialize SDL: %s\n", SDL_GetError ());
    return EXIT_FAILURE;
  }
  atexit (SDL_Quit);
  atexit (SDL_CloseAudio);
  screen = SDL_SetVideoMode (256, 256, 16, 0);
  if (screen == NULL) {
    printf ("Unable to set video mode: %s\n", SDL_GetError ());
    return EXIT_FAILURE;
  }
  /* Format: 16 Bit, stereo, 22 KHz */
  format.freq = 22050;
  format.format = AUDIO_S16;
  format.channels = 2;
  format.samples = 512;
  format.callback = AudioMixing;
  format.userdata = NULL;
  /* das Audio-Gerät öffnen und das Abspielen beginnen */
  if (SDL_OpenAudio (&format, NULL) < 0) {
    printf ("Audio-Gerät konnte nicht geöffnet werden: %s\n",
       SDL_GetError ());
    exit (EXIT_FAILURE);
  }
  SDL_PauseAudio (0);
  while (done) {
    printf ("ESC für Ende\n  A, C, Z, M und B für Sound "
            " abspielen.\n");
    done = eventloop ();
  }
  SDL_PauseAudio (1);
  SDL_CloseAudio();
  return EXIT_SUCCESS;
}

Das Programm übersetzen:

$ gcc `sdl-config --libs` `sdl-config --cflags` -o sdl10 sdl10.c
$ ./sdl10
 << zurück
  
  Zum Rheinwerk-Shop
Neuauflage: Linux-UNIX-Programmierung
Neuauflage:
Linux-UNIX-
Programmierung

bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: Linux-Server






 Linux-Server


Zum Rheinwerk-Shop: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Rheinwerk-Shop: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Rheinwerk-Shop: Shell-Programmierung






 Shell-
 Programmierung


Zum Rheinwerk-Shop: Linux Handbuch






 Linux Handbuch


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
Info





Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern