Cannot play WAV file using OpenAL with wxWidgets Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
winghearn
In need of some credit
In need of some credit
Posts: 3
Joined: Sun Apr 09, 2017 8:11 am

Cannot play WAV file using OpenAL with wxWidgets

Post by winghearn »

Hello, I'm a newbie here. I want to use wxWidgets to create a WAV player with GUI. OpenAL is a good library for audio and I've written a simple version in a console application. My question is can wxWidgets work with OpenAL? I copied the code from my original version and fix a little bit to merge with my wxWidgets setup. Basically I have a toolBar and some buttons on my window. One is called "Play" and when I hit it, it will call this function.

Code: Select all

void MyFrame::OnPlay(wxCommandEvent& event) {
	char fileName[_MAX_PATH] = "F:/famitracker/karisuma.wav";

	size_t size;
	short formatType;
	short channel;
	size_t sampleRate;
	size_t byteRate;
	short bytesPerSample;
	short bitsPerSample;
	size_t dataSize;
	unsigned char* wavData = nullptr;

	ALCdevice* device;
	ALCcontext* context;
	ALuint buffer;
	ALuint source;
	ALsizei frequency;
	ALenum format;
	ALfloat sourcePos[] = {0.0, 0.0, 0.0};
	ALfloat sourceVel[] = {0.0, 0.0, 0.0};
	ALfloat listenerPos[] = {0.0, 0.0, 0.0};
	ALfloat listenerVel[] = {0.0, 0.0, 0.0};
	ALfloat listenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0};
	ALfloat volume;
	ALint loop;
	
	device = alcOpenDevice(NULL);
	if (!device) {
		wxMessageBox("ERROR: NO device");
	}
	context = alcCreateContext(device, NULL);
	if (!alcMakeContextCurrent(context)) {
		wxMessageBox("ERROR: NO context");
	}

	if (loadWavFile(fileName, &size, &formatType, &channel,
		&sampleRate, &byteRate, &bytesPerSample, &bitsPerSample,
		&dataSize, &wavData)) {

		alGenBuffers(1, &buffer);
		alGenSources(1, &source);

		if (bitsPerSample == 16) {
			if (channel == 2)
				format = AL_FORMAT_STEREO16;
			else if (channel == 1)
				format = AL_FORMAT_MONO16;
			else {
				wxMessageBox("ERROR: WEIRD NUMBER\n");
			}
		}
		else if (bitsPerSample == 8) {
			if (channel == 2)
				format = AL_FORMAT_STEREO8;
			else if (channel == 1)
				format = AL_FORMAT_MONO8;
			else {
				wxMessageBox("ERROR: WEIRD NUMBER\n");
			}
		}
		else {
			wxMessageBox("ERROR: WEIRD NUMBER\n");
		}

		frequency = sampleRate;
		volume = (float)0.5;
		loop = AL_FALSE;
		alBufferData(buffer, format, wavData, dataSize, frequency);
		alListenerfv(AL_POSITION, listenerPos);
		alListenerfv(AL_VELOCITY, listenerVel);
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcei(source, AL_BUFFER, buffer);
		alSourcef(source, AL_PITCH, 1.0);
		alSourcef(source, AL_GAIN, volume);
		alSourcefv(source, AL_POSITION, sourcePos);
		alSourcefv(source, AL_VELOCITY, sourceVel);
		alSourcei(source, AL_LOOPING, loop);

		alSourcePlay(source);
		if (wavData) {
			delete wavData;
			wavData = nullptr;
		}
		alDeleteBuffers(1, &buffer);
		alDeleteSources(1, &source);
		alcMakeContextCurrent(nullptr);
		alcDestroyContext(context);
		alcCloseDevice(device);
	}
}
And here's my function for loading a WAV:

Code: Select all

int loadWavFile(char fileName[], size_t* size, short* formatType, short* channel,
	size_t* sampleRate, size_t* byteRate, short* bytesPerSample, short* bitsPerSample,
	size_t* dataSize, unsigned char** wavData) {

	FILE* wavFile = nullptr;
	char type[4];
	int fileNameSize = strlen(fileName);
	for (int i = 0; i < fileNameSize; i++) {
		if (fileName[i] == '\\')
			fileName[i] = '/';
	}

	wavFile = fopen(fileName, "rb");
	if (wavFile) {
		fread(type, 1, 4, wavFile);
		if (type[0] == 'R' && type[1] == 'I' && type[2] == 'F' && type[3] == 'F') {
			fseek(wavFile, 8, SEEK_SET);
			fread(type, 1, 4, wavFile);
			if (type[0] == 'W' && type[1] == 'A' && type[2] == 'V' && type[3] == 'E') {
				fread(type, 1, 4, wavFile);
				if (type[0] == 'f' && type[1] == 'm' && type[2] == 't' && type[3] == ' ') {
					fread(size, 4, 1, wavFile);
					fread(formatType, 2, 1, wavFile);
					fread(channel, 2, 1, wavFile);
					fread(sampleRate, 4, 1, wavFile);
					fread(byteRate, 4, 1, wavFile);
					fread(bytesPerSample, 2, 1, wavFile);
					fread(bitsPerSample, 2, 1, wavFile);
					fread(type, 1, 4, wavFile);
					if (type[0] == 'd' && type[1] == 'a' && type[2] == 't' && type[3] == 'a') {
						fread(dataSize, 4, 1, wavFile);
						*wavData = new unsigned char[*dataSize];
						fread(*wavData, 1, *dataSize, wavFile);
					}
					else {
						wxMessageBox("ERROR: CANNOT FIND data HEAD\n");
						fclose(wavFile);
						return 0;
					}
				}
				else {
					wxMessageBox("ERROR: NOT fmt\n");
					fclose(wavFile);
					return 0;
				}
			}
			else {
				wxMessageBox("ERROR: NOT WAVE\n");
				fclose(wavFile);
				return 0;
			}
		}
		else {
			wxMessageBox("ERROR: NOT RIFF\n");
			fclose(wavFile);
			return 0;
		}
	}
	else {
		wxMessageBox("ERROR: CANNOT OPEN FILE\n", "warning", wxICON_EXCLAMATION);
		//fclose(wavFile);
		return 0;
	}
	wxMessageBox("File loaded\n");
	fclose(wavFile);
	return 1;
}
I didn't use ALUT and I write my own alternative function for the purpose. It runs pretty good when in my console application. But for some reasons it didn't work here. I checked the debugger to make sure it went through every line without errors. Everything is fine except there's no sound... Also I've tried a few times using a wrong file name or a broken WAV file, it did pop up the message box. So may the problem come from OpenAL??

Any suggestions??
User avatar
T-Rex
Moderator
Moderator
Posts: 1249
Joined: Sat Oct 23, 2004 9:58 am
Location: Zaporizhzhya, Ukraine
Contact:

Re: Cannot play WAV file using OpenAL with wxWidgets

Post by T-Rex »

wxWidgets app will work with OpenAL. At least, I managed to make OpenAL work in one of my apps.
In general, OpenAL and wxWidgets are not related to each other and if OpenAL does not work for you in your app, then the problem is, most likely, related to how you are using OpenAL in your app.

You haven't mentioned the version of wxWidgets and operating system. On Windows (according to the WAV file path) you need to install OpenAL redistributable package to make it work, I think.

BTW, you said that OpenAL worked for you in console app. Does your wxWidgets app use the same CRT linking (static CRT or dynamic)?

EDIT: Have you tried to follow any tutorials and implement the same logic in wxWidgets app? I remember that I also used some tutorial and it worked for me. Not sure whether I can find that source code, but you could try smth. like this: https://ffainelli.github.io/openal-example/
winghearn
In need of some credit
In need of some credit
Posts: 3
Joined: Sun Apr 09, 2017 8:11 am

Re: Cannot play WAV file using OpenAL with wxWidgets

Post by winghearn »

I'm using wxWidgets 3.1.0 on Windows 8.1.
For both the console and window app, I use the same option, "Multi-threaded Debug DLL (/MDd)". I think that is dynamic?
I've tried switched to other runtime library for my console app, OpenAL works just fine., but not for wxWidgets app...

I wrote this based on the tutorial you mentioned, which is really helpful and another one using ALUT.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Cannot play WAV file using OpenAL with wxWidgets

Post by doublemax »

alSourcePlay is an asynchronous call (it starts playing the sound in the background and returns immediately), but you're destroying the audio objects right afterwards.

This exact issue is even mentioned in their docs:
https://ffainelli.github.io/openal-example/ (search for "playing the source")
Use the source, Luke!
winghearn
In need of some credit
In need of some credit
Posts: 3
Joined: Sun Apr 09, 2017 8:11 am

Re: Cannot play WAV file using OpenAL with wxWidgets

Post by winghearn »

Thank you! I think I forgot to add a loop to update the status.
Now I totally understand the mechanism. :)
Post Reply