Meine eigene Sound-Klasse für wxWidgets
-
Hallo zusammen!
Da ich die wxSound-Klasse aud der wxWidgets-Bibliothek nicht gut finde, habe ich eine eigne Klasse Namens srOpenAL geschrieben, die ich euch nicht vorenthalten möchte. Ich bin mit der Klasse auch recht zu frieden, da ich endlich OGG/Vorbis-Dateien abspielen kann. Ich habe nur ein Problem: Das Programm kann nicht fortgeführt werden, solange die ganze Audio-Datei nicht fertiggespielt ist. Bei wxSound hat man die Möglichkeit gehabt die Audio-Datei "asynchron" abzuspielen. Ich frage mich nur wie ich das gleiche mit meine Klasse hinbekommen kann. Mit Multi-Threading kenne ich mich leider nicht aus.
Hier mein Quellcode:
openal.h:
//////////////////////////////////////////////////////////////////////////////// /// Die srOpenAL-Schablone //////////////////////////////////////////////////////////////////////////////// #ifndef _srOpenAL_h_ #define _srOpenAL_h_ #include <AL/al.h> #include <AL/alut.h> #include <vector> #include <vorbis/vorbisfile.h> #include <wx/msgdlg.h> #include <wx/string.h> class srOpenAL { private: ALenum format; ALuint bufferID; ALuint sourceID; const int oggSize; void LoadOGG(const wxString &filename, std::vector<char> &buffer, ALenum &format, ALsizei &freq); public: srOpenAL(const wxString &filename = wxEmptyString); ~srOpenAL(); void Play(); }; #endif
openal.cpp:
//////////////////////////////////////////////////////////////////////////////// /// Die srOpenAL-Implementierung //////////////////////////////////////////////////////////////////////////////// #include "openal.h" srOpenAL::srOpenAL(const wxString &filename) : oggSize(32768) { //////////////////////////////////////////////////////////////////////////////// /// Die Konfiguration //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// ALsizei freq; std::vector<char> bufferData; alutInit(0, NULL); alGenBuffers(1, &this->bufferID); alGenSources(1, &this->sourceID); alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f); alSource3f(sourceID, AL_POSITION, 0.0f, 0.0f, 0.0f); this->LoadOGG(filename, bufferData, this->format, freq); alBufferData(this->bufferID, this->format, &bufferData[0], static_cast<ALsizei>(bufferData.size()), freq); alSourcei(this->sourceID, AL_BUFFER, this->bufferID); //////////////////////////////////////// } srOpenAL::~srOpenAL() { //////////////////////////////////////////////////////////////////////////////// /// Der Dekonstrukter //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// alDeleteBuffers(1, &this->bufferID); alDeleteSources(1, &this->sourceID); //////////////////////////////////////// } void srOpenAL::LoadOGG(const wxString &filename, std::vector<char> &buffer, ALenum &format, ALsizei &freq) { //////////////////////////////////////////////////////////////////////////////// /// Die OGG-Datei laden //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// char array[oggSize]; int endian = 0, bitStream; long int bytes; FILE *file; wxString caption, message; caption = wxT("Fehlermeldung"); file = fopen(filename.mb_str(), "rb"); if(file == NULL) { message.Printf(wxT("Die Audio-Datei\n\"%s\"\nkonnte nicht gefunden werden!"), filename.c_str()); wxMessageBox(message, caption); exit(-1); } vorbis_info *vInfo; OggVorbis_File oggFile; if(ov_open(file, &oggFile, NULL, 0) != 0) { message.Printf(wxT("Die Audio-Datei\n\"%s\"\nbezeichnet keine richtige OGG/Vorbis-Codierung!"), filename.c_str()); wxMessageBox(message, caption); exit(-1); } vInfo = ov_info(&oggFile, -1); if(vInfo->channels == 1) { this->format = AL_FORMAT_MONO16; } else { this->format = AL_FORMAT_STEREO16; } freq = vInfo->rate; do { bytes = ov_read(&oggFile, array, this->oggSize, endian, 2, 1, &bitStream); if(bytes < 0) { ov_clear(&oggFile); return; } buffer.insert(buffer.end(), array, (array+bytes)); } while(bytes > 0); ov_clear(&oggFile); //////////////////////////////////////// } void srOpenAL::Play() { //////////////////////////////////////////////////////////////////////////////// /// Die OGG-Datei abspielen //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// ALint state; alSourcePlay(this->sourceID); do { alGetSourcei(this->sourceID, AL_SOURCE_STATE, &state); } while(state != AL_STOPPED); //////////////////////////////////////// }
Anwendung:
... openal = new srOpenAL(wxT("sound.ogg")); openal->Play(); ...
Danke für Eure Hilfe!
Gruß,
littletux
-
Du musst Play() in einen wxThread auslagern.
Les doch mal die Doku zu wxThread.
rya.
-
Danke, Ich werde mir die Doku anschauen! Mal sehen vielleicht finde ich auch was passendes in den Quelltext von wxSound.
-
Kanne es sein, dass ich nur die Methoden Create, Run und Delete brauche oder muss ich wxThread erben und die Methode Entry benutzen? Mit Multi-Threads habe ich noch nie gearbeitet. wäre schön wenn mir einer bei der Ergänzung helfen könnte.
-
Ich habe meine Datei erweitert und eine Zweite Klasse Namens srSoundThread hinzugefügt. Dies lies sich zwar kompelieren, aber der Effekt ist das gleiche.
Wo liegt mein Denkfehler?Hier meine zwei Dateien in der abgeänderten Version:
openal.h:
//////////////////////////////////////////////////////////////////////////////// /// Die srOpenAL-Schablone //////////////////////////////////////////////////////////////////////////////// #ifndef _srOpenAL_h_ #define _srOpenAL_h_ #include <AL/al.h> #include <AL/alut.h> #include <vector> #include <vorbis/vorbisfile.h> #include <wx/msgdlg.h> #include <wx/string.h> #include <wx/thread.h> class srSoundThread : public wxThread { private: ALuint sourceID; void* Entry(); public: srSoundThread(ALuint source); ~srSoundThread(); }; class srOpenAL { private: ALenum format; ALuint bufferID; ALuint sourceID; const int oggSize; srSoundThread *soundthread; void LoadOGG(const wxString &filename, std::vector<char> &buffer, ALenum &format, ALsizei &freq); public: srOpenAL(const wxString &filename = wxEmptyString); ~srOpenAL(); void Play(); }; #endif
openal.cpp:
//////////////////////////////////////////////////////////////////////////////// /// Die srOpenAL-Implementierung //////////////////////////////////////////////////////////////////////////////// #include "openal.h" srSoundThread::srSoundThread(ALuint source) { //////////////////////////////////////////////////////////////////////////////// /// Die Konfiguration //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// this->sourceID = source; wxThread::Create(); //////////////////////////////////////// } srSoundThread::~srSoundThread() { //////////////////////////////////////////////////////////////////////////////// /// Der Dekonstrukter //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// } void* srSoundThread::Entry() { //////////////////////////////////////////////////////////////////////////////// /// Die Audio-Datei abspielen //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// ALint state; alSourcePlay(this->sourceID); do { alGetSourcei(this->sourceID, AL_SOURCE_STATE, &state); } while(state != AL_STOPPED); //////////////////////////////////////// } srOpenAL::srOpenAL(const wxString &filename) : oggSize(32768) { //////////////////////////////////////////////////////////////////////////////// /// Die Konfiguration //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// ALsizei freq; std::vector<char> bufferData; alutInit(0, NULL); alGenBuffers(1, &this->bufferID); alGenSources(1, &this->sourceID); alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f); alSource3f(sourceID, AL_POSITION, 0.0f, 0.0f, 0.0f); this->soundthread = new srSoundThread(sourceID); this->LoadOGG(filename, bufferData, this->format, freq); alBufferData(this->bufferID, this->format, &bufferData[0], static_cast<ALsizei>(bufferData.size()), freq); alSourcei(this->sourceID, AL_BUFFER, this->bufferID); //////////////////////////////////////// } srOpenAL::~srOpenAL() { //////////////////////////////////////////////////////////////////////////////// /// Der Dekonstrukter //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// this->soundthread->Delete(); alDeleteBuffers(1, &this->bufferID); alDeleteSources(1, &this->sourceID); //////////////////////////////////////// } void srOpenAL::LoadOGG(const wxString &filename, std::vector<char> &buffer, ALenum &format, ALsizei &freq) { //////////////////////////////////////////////////////////////////////////////// /// Die OGG/Vorbis-Datei laden //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// char array[oggSize]; int endian = 0, bitStream; long int bytes; FILE *file; wxString caption, message; caption = wxT("Fehlermeldung"); file = fopen(filename.mb_str(), "rb"); if(file == NULL) { message.Printf(wxT("Die Audio-Datei\n\"%s\"\nkonnte nicht gefunden werden!"), filename.c_str()); wxMessageBox(message, caption); exit(-1); } vorbis_info *vInfo; OggVorbis_File oggFile; if(ov_open(file, &oggFile, NULL, 0) != 0) { message.Printf(wxT("Die Audio-Datei\n\"%s\"\nbezeichnet keine richtige OGG/Vorbis-Codierung!"), filename.c_str()); wxMessageBox(message, caption); exit(-1); } vInfo = ov_info(&oggFile, -1); if(vInfo->channels == 1) { this->format = AL_FORMAT_MONO16; } else { this->format = AL_FORMAT_STEREO16; } freq = vInfo->rate; do { bytes = ov_read(&oggFile, array, this->oggSize, endian, 2, 1, &bitStream); if(bytes < 0) { ov_clear(&oggFile); return; } buffer.insert(buffer.end(), array, (array+bytes)); } while(bytes > 0); ov_clear(&oggFile); //////////////////////////////////////// } void srOpenAL::Play() { //////////////////////////////////////////////////////////////////////////////// /// Die Audio-Datei "asynchron" abspielen //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// this->soundthread->Run(); //////////////////////////////////////// }
-
Sorry, es hat doch funktioniert! Ich habe es erst später gemerkt, als ich meine Audio-Klasse auskommentiert habe und OpenGL einige Zeit brauchte, um meine Objekte zu zeichnen. Als eine danach eine Audio-Datei geladen habe, die länger als 2 Sekunden ging, konnte ich sehen, dass wxThread doch meine Audio-Datei parallel abspielte. Da war ich wohl ein wenig ungeduldig!