(C++) SDL_mixer ist Stumm
-
Hallo!
Ich arbeite gerade an einer kleinen Spieleengine für mich, die auf Windows und Linux laufen soll. Daher benutze ich auch SDL. Bisher habe ich schon alles mögliche für Video, Events, Input usw. gekapselt und läuft auch alles super. Nun möchte ich aber gerne etwas Musik ins Spiel bringen. Also habe ich mir SDL_mixer runtergeladen, die libvorbis usw. für OGG-Support ist auch alles installiert. Ich schaffe es sogar ohne jegliche Fehlermeldungen OGGs abzuspielen. Wenn ich den Status mit Mix_PlayingMusic prüfe erzählt er mir auch, dass die Musik läuft (Rückgabewert = 1). Aber ich höre nichts!
Mag es vielleicht an Linux liegen? Ich hatte schon öfter Probleme mit dem Sound-System von Linux, und mich nervt vor allem das irgendwie immer nur ein Channel gleichzeitig ausgegeben wird, was auch zur Folge hat, dass wenn bei XMMS kurz Ruhe ist um den nächsten Track zu laden unzählige (unterdrückte) Sounds von anderen Programmen auftauchen. Bis vor kurzem hatte ich noch nicht einmal Sound, ich musste erst einen bestimmten Channel Stumm schalten, damit was zu hören war (was irgendwie komisch ist) - aber das ist eine andere Geschichte.
Also was kann ich machen? Er scheint ja zu spielen, ich höre nur nichts!
Der Code ist richtig, ich habe ihn im Nachhinein mit unzähligen Tutorials und Beispielcodes verglichen.
-
Wenn dein Programm unter Linux und Windows laufen soll, dann probiers mal unter Windows. Vielleicht liegts wirklich an der Einstellung deiner Soundkarte. Vielleicht könnstest du auch ein kleines Code Beispiel posten, welches bei dir nicht klappt.
-
@MAG
Das sieht danach aus, als hättest du irgend einen schlechten OSS Treiber eingerichtet. Versuch lieber mal einen ALSA Treiber zu nehmen oder nimm einen Soundserver wie arts oder jackd zur Ausgabe.
-
Der Code ist in Klassen unterteilt, aber ich poste mal die wichtigsten Code-Zeilen:
xaudio.h
/*************************************************************************** * Copyright (C) 2005 by Mathias Kahl * * mathias_kahl@onlinehome.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef XH_AUDIO #define XH_AUDIO /*! @file xaudio.h @brief Klassen fuer Musik und Soundeffekte */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <iostream> #include <stdlib.h> #include "SDL.h" #include "SDL_mixer.h" using namespace std; /*! @class XAudio @brief Musik und Soundeffekte @author Mathias Kahl @version 0.1 @date 07.01.2005 Diese Klasse bietet Methode zur Ausgabe und Sampling von Musik und Soundeffekten. */ class XAudio { protected: /// Frequenz int m_iFrequency; /// Sample Format Uint16 m_iFormat; /// Anzahl Sound Channels, 1=mono; 2=stereo int m_iChannels; /// Chunksize int m_iChunkSize; /// Hintergrundmusik-Stream Mix_Music* m_pMusic[5]; /// Momentan ausgewaehlte Musik int m_iSelectedMusic; /// Dauer eines FadeIns in ms int m_iMusicFadeIn; /// Dauer eines FadeOuts in ms int m_iMusicFadeOut; /// Lautstaerke der Musik int m_iMusicVolume; public: XAudio(); ~XAudio(); int GetFrequency() { return m_iFrequency; } Uint16 GetFormat() { return m_iFormat; } int GetChannels() { return m_iChannels; } int GetChunkSize() { return m_iChunkSize; } Mix_Music* GetMusicStream() { return m_pMusic[m_iSelectedMusic]; } int GetMusicFadeInLenght() { return m_iMusicFadeIn; } int GetMusicFadeOutLenght() { return m_iMusicFadeOut; } int GetMusicVolume() { return m_iMusicVolume; } int GetCurrentMusic() { return m_iSelectedMusic; } void SetFrequency(int i) { m_iFrequency = i; } void SetFormat(Uint16 i) { m_iFormat = i; } void SetChannels(int i) { m_iChannels = i; } void SetChunkSize(int i) { m_iChunkSize = i; } void SetFadeInLenght(int i) { m_iMusicFadeIn = i; } void SetFadeOutLenght(int i) { m_iMusicFadeOut = i; } /// Setzt die Musiklautstaerke, Angabe in Prozent (0-100) bool SetMusicVolume(int i); /// Waehlt einen der verfuegbaren Musik-Streams, 0 - 4 void SelectMusic(int i) { m_iSelectedMusic = i; } /// Initialisiert die Sound-Engine bool Init(int chunk_size=4096); /// Laedt Musik (nur ein Musik-Channel gleichzeitig) bool LoadMusic(char* path); /// Gibt den Speicher frei und loescht die Musik bool FreeMusic(); /// Gibt die Musik als Loop wieder, 0=1mal,-1=unendlich bool PlayMusic(int loops,bool fadein); /// Pausiert die Musik void PauseMusic(); /// Nimmt die Wiedergabe von pausierter Musik wieder auf void ResumeMusic(); /// Spult die Musik auf Anfang zurueck void RewindMusic(); /// Stoppt Musik, optional mit FadeOut bool StopMusic(bool fadeout); /// Prueft ob Musik spielt bool IsMusicPlaying(); /// Prueft ob eine pausierte Musik vorhanden ist bool IsMusicPaused(); }; #endif
Implementierung (xaudio.cpp):
#include "xaudio.h" XAudio::XAudio() { m_iFrequency = 22050; // 22050 Hz Standart m_iFormat = MIX_DEFAULT_FORMAT; m_iChannels = 2; // Stereo m_iChunkSize = 1024; m_iMusicFadeIn = 3000; // 3 s FadeIn m_iMusicFadeOut = 3000; // 3 s FadeOut m_iMusicVolume = 80; // 80% Musik-Lautstaerke m_iSelectedMusic = 0; // ersten Stream Standartauswahl m_pMusic[0] = NULL; m_pMusic[1] = NULL; m_pMusic[2] = NULL; m_pMusic[3] = NULL; m_pMusic[4] = NULL; } XAudio::~ XAudio() { for(int i=0;i<4;i++) { if(m_pMusic[i] != NULL) { Mix_FreeMusic(m_pMusic[i]); m_pMusic[i] = NULL; } } Mix_CloseAudio(); } /*! initialisiert die Sound-Engine mit den Standartparametern und chunk_size. Die Standartparameter fuer Format, Frequenz usw. koennen per Set* vor Aufruf von Init geaendert werden. @param chunk_size Groesse der Sampling-Stuecke, je kleiner desto besser (und aufwendiger), Standart: 1024 @return Die Methode liefert true wenn alle Komponenten korrekt initialisiert wurden @sa SetFrequency, SetFormat, SetChannels */ bool XAudio::Init(int chunk_size) { // Audio-Subsystem intitialisieren if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { fprintf(stderr,"XAudio: Failed to init sub system: %s\n",SDL_GetError()); return false; } // MIXER starten if(Mix_OpenAudio(m_iFrequency,m_iFormat,m_iChannels,m_iChunkSize) < 0) { fprintf(stderr,"XAudio: Open Audio failed: %s\n",SDL_GetError()); return false; } return true; } /*! Es wird die Lautstaerke der Musik gesetzt. Dies funktioniert nicht waehrend eines Fades. @param i Lautstaerke in Prozent (0-100) @return Diese Methode liefert immer true zurueck */ bool XAudio::SetMusicVolume(int i) { int m_iMusicVolume = (int) ((MIX_MAX_VOLUME / 100) * i); Mix_VolumeMusic(m_iMusicVolume); return true; } /*! Diese Methode laedt eine Musik-Datei (MP3,OGG,WAV,MOD oder MIDI) @param path Speicherpfad zur Musikdatei, kann relativ oder absolut sein @return liefert true wenn die Datei erfolgreich geladen wurde */ bool XAudio::LoadMusic(char* path) { if(m_pMusic[m_iSelectedMusic] != NULL) return false; m_pMusic[m_iSelectedMusic] = Mix_LoadMUS(path); if(NULL == m_pMusic[m_iSelectedMusic]) { fprintf(stderr,"XAudio: Failed to load music (%s): %s\n",path,SDL_GetError()); return false; } return true; } /*! Gibt geladene Musik frei, wenn die Musik spielt wird sie vorher angehalten. Waehrend eines Fades wartet die Methode bis dieser abgeschlossen ist. @return gibt true zurueck wenn die Musik erfolgreich freigegeben wurde */ bool XAudio::FreeMusic() { if(m_pMusic[m_iSelectedMusic] == NULL) return false; Mix_FreeMusic(m_pMusic[m_iSelectedMusic]); m_pMusic[m_iSelectedMusic] = NULL; return true; } /*! Gibt die momentan ueber SelectMusic ausgewaehlte Musik als Loop wieder. @param loops Anzahl der Loops oder -1 fuer unendlich @param fadein Bestimmt ob die Musik mit einem FadeIn gestartet werden soll @return gibt true zurueck wenn die Musik erfolgreich gestartet werden konnte @sa SelectMusic, SetFadeInLenght, PauseMusic, StopMusic */ bool XAudio::PlayMusic(int loops, bool fadein) { if(fadein) { if(Mix_FadeInMusic(m_pMusic[m_iSelectedMusic],loops,m_iMusicFadeIn) < 0) { fprintf(stderr,"XAudio: Playing music failed: %s\n",SDL_GetError()); return false; } } else { if(Mix_PlayMusic(m_pMusic[m_iSelectedMusic],loops) < 0) { fprintf(stderr,"XAudio: Playing music failed: %s\n",SDL_GetError()); return false; } } return true; } /*! Pausiert aktuell spielende Musik */ void XAudio::PauseMusic() { Mix_PauseMusic(); } /*! Die momentan spielen Musik wird "zurueckgespult" und faengt wieder von vorne an. */ void XAudio::RewindMusic() { Mix_RewindMusic(); } /*! Spielt angehaltene Musik weiter. Diese Methode funktioniert auch sicher bei gestoppter und spielender Musik, ohne Fehler oder Exceptions zu produzieren. @sa PlayMusic, PauseMusic, StopMusic */ void XAudio::ResumeMusic() { Mix_ResumeMusic(); } /*! Die momentan spielende Musik wird angehalten, optional per Fadeout. Die Dauer des Fadeouts ist in der Membervariablen XAudio::m_iFadeOut gespeichert. @param fadeout Bestimmt ob die Musik vor dem Stoppen ausgefadet werden soll @return Diese Methode liefert true wenn die Musik gestoppt werden konnte oder der Fadeout gestartet worden ist @sa SetFadeOutLenght */ bool XAudio::StopMusic(bool fadeout) { if(fadeout) { if(Mix_FadeOutMusic(m_iMusicFadeOut) == 0) { fprintf(stderr,"XAudio: Fade Out Music failed: %s\n",SDL_GetError()); return false; } } else { Mix_HaltMusic(); } return true; } bool XAudio::IsMusicPlaying() { return (Mix_PlayingMusic() == 1); } bool XAudio::IsMusicPaused() { return (Mix_PausedMusic() == 1); }
Das ganze wird dann folgendermaßen verwendet (es handelt sich dabei nur um ein Testprogramm fuer die Klassen):
#ifdef HAVE_CONFIG_H #include <config.h> #endif #include <iostream> #include <stdlib.h> #include "SDL.h" #include "xvideo.h" #include "xevent.h" #include "xinput.h" #include "xaudio.h" using namespace std; int main() { if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_EVENTTHREAD)< 0) { cout <<"Could not initialize SDL:" << SDL_GetError() << endl; SDL_Quit(); } bool fQuit = false; XVideo* pVideo = new XVideo(); XEvent* pEvent = new XEvent(); XInput* pInput = new XInput(); XAudio* pAudio = new XAudio(); pVideo->Init(320,240,0,false); pVideo->SetWindowName("<<<< xGame >>>>"); pAudio->Init(); pAudio->LoadMusic("media/epok.ogg"); pAudio->SetMusicVolume(80); pAudio->PlayMusic(1,false); while(!fQuit) { // EventLoop while(pEvent->FetchEvents()) { if(pEvent->IsQuit()) fQuit = true; if(pEvent->IsKeyUp(SDLK_a)) fprintf(stderr,"'a' was released\n"); if(pEvent->IsKeyDown(SDLK_b) && pInput->ModActive(KMOD_LCTRL)) fprintf(stderr,"STRG+B once\n"); if(pEvent->IsKeyDown(SDLK_SPACE)) { if(pAudio->IsMusicPlaying()) fprintf(stderr,"music plays\n"); if(pAudio->IsMusicPaused()) fprintf(stderr,"music is paused\n"); } if(pEvent->IsKeyDown(SDLK_b)) { if(pAudio->IsMusicPlaying()) { pAudio->PauseMusic(); fprintf(stderr,"pause>>"); } else if(pAudio->IsMusicPaused()) { pAudio->ResumeMusic(); fprintf(stderr,"resume>>"); } } if(pEvent->IsKeyDown(SDLK_c)) pAudio->StopMusic(false); if(pEvent->IsKeyDown(SDLK_v)) pAudio->ResumeMusic(); } // Eingabebuffer aktualisieren pInput->FetchKeyboard(); pInput->FetchMouse(); // Tastatureingaben pruefen if(pInput->ModActive(KMOD_LCTRL) && pInput->KeyPressed(SDLK_a)) { fprintf(stderr,"STRG+A\n"); } if(pInput->KeyPressed(SDLK_ESCAPE)) fQuit = true; pVideo->Refresh(); SDL_Delay(50); } delete pVideo; delete pEvent; delete pInput; delete pAudio; SDL_Quit(); }
--
Was die Treiber angeht, ich will versuchen ALSA zu bekommen, wenn ich dazu was finde. Auf Windows habe ich's noch nicht ausprobiert. Danke für den Tip, das werde ich gleich mal machen.