Mark Sachs (ksleet) wrote,
Mark Sachs
ksleet

  • Mood:
  • Music:

Much like the legendary Errol Flynn he does not floss.

Ugh, how frustrating! So it turns out that the sample code I found for loading WAV files yesterday... didn't quite work in my project. It proceeds successfully through its code path, but the actual sound is just white noise when played. I hadn't noticed it because the sample for the ship's rocket engine is kind of white-noisy, too, but playing a more specific sound made it glaringly obvious.

Now, I've actually written WAV loading code in the (distant) past, when I was working with DirectX 5. It's complicated, I know! But this just ties into something I've seen over and over again in open-source libraries such as OpenAL, which I absolutely hate. There will be a complex task, such as, say, loading WAV files, that normally requires a lot of intricate and touchy code to work right. In the early versions of the library, someone will add a utility function that easily accomplishes said task. Then a few versions later, some random person will get a bug up their butt about the quality of the code in the utility function, or worse, they'll start chin-pulling ruminations about how the utility function somehow doesn't fit in with what they've suddenly decided the library should focus on, and they'll unceremoniously remove it and replace it with nothing. And the library users are left high and dry, wondering why all the tutorials on the web no longer work, and forced once again to laboriously recreate the code from scratch.

Guys. Stop it. STOP IT! The wonderful vision in your head of what the library may someday become is all very nice, but ninety-nine times out of a hundred all we want to do is load a goddamned file without having to jump through hoops. Let us do that. Please. Or I'll bash in your kneecaps.

Um, anyway. So I searched the web some more and I found this sample code. Now, it wasn't precisely what I needed, but I got it playing at least some of my samples and knew I was on the right track. I figured out that one of my Star Castle samples is in a different format from the others, and thus loads as noise. I brought over some of the more beefy format checking code from the first version of the function, arbitrarily cut some extra data for 8-bit samples (is that correct? Who knows!) and managed to create something that does actually work for loading and playing WAVs, or at least these eight or nine WAVs I've got right here. I'll append it at the end of this post for the sake of Google. Hey Google, xcode c++ wav play alutLoadWAVFile mac!

Aside from that, I actually got a lot of good under-the-hood stuff done. While as of yesterday I could fly a ship around, it was all hard-coded into the program's main loop. I've now abstracted out a typical cEntity class to manage game objects, with the idea that a cEntity can control any number of shapes, sound sources, and such. The player ship is now its own entity and does just that. Furthermore, I also created an iInputListener interface class and reorganized cInput so that it throws keyboard input out to objects that register to listen for it, so the ship can catch the player's control input and respond as needed. (Since we can have any number of listeners, broader game functions such as hitting another key to exit the game can be handled by its own code.)

On the more sexy front, I got it so the ship can fire its gun when the space bar is pressed. I want to get powerups and multiple weapons into this version of the game, so I created a cArmament class (currently just specialized into cStandardGun, firing cStandardBullets) and gave the player's ship just a generic pointer to a gun it can try to fire. This way, the weapon can be swapped out with ease. In theory, it would also make it much easier to create a hostile ship that is equipped with a similar weapon to your own.

Ah, right, let's not forget that source code. I'll throw in code for building and tearing down OpenAL, free of charge. These are useful functions that were also pulled out of OpenAL. Note that you also need to add both the OpenAL and AudioToolbox frameworks to your Xcode project.

#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>

#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#include <OpenAL/MacOSX_OALExtensions.h>

cAudio::cAudio() : mDevice(NULL), mContext(NULL)
{
	mDevice = alcOpenDevice(NULL);
	mContext = alcCreateContext(mDevice, NULL);
	alcMakeContextCurrent(mContext);
	
	Assert(alGetError() == AL_NO_ERROR, "OpenAL error during initialization");
	
	ALfloat vZero[3] = {0.0f, 0.0f, 0.0f};
	
	alListenerfv(AL_POSITION,vZero);
	alListenerfv(AL_VELOCITY,vZero);
	alListenerfv(AL_ORIENTATION,vZero);
}

cAudio::~cAudio()
{
	alcMakeContextCurrent(NULL); 
	alcDestroyContext(mContext); 
	alcCloseDevice(mDevice); 
}

void cAudio::LoadWAVFile(const char* filename, ALuint bufferID)
{
	FSRef tFSRef;
	OSStatus status = FSPathMakeRef((const UInt8 *)filename, &tFSRef, FALSE);
	
	Assert(status == 0, "FSPathMakeRef failed");
	
	AudioFileID audioFileID;
	int err = AudioFileOpen(&tFSRef, fsRdPerm, kAudioFileWAVEType, &audioFileID);

	Assert(err == 0, "AudioFileOpen failed");
	
	UInt32 nPropertySize = 0;
	UInt32 nPropertyWritable = 0;
	AudioFileGetPropertyInfo(audioFileID, kAudioFilePropertyAudioDataPacketCount, &nPropertySize, &nPropertyWritable);
	
	UInt64 sampleLength;
	Assert(sizeof(sampleLength == nPropertySize), "Somehow couldn't handle sample length property");
	AudioFileGetProperty(audioFileID, kAudioFilePropertyAudioDataPacketCount, &nPropertySize, &sampleLength);
	
	AudioStreamBasicDescription desc;
	UInt32 nPropSize = sizeof(desc);
	AudioFileGetProperty(audioFileID, kAudioFilePropertyDataFormat, &nPropSize, &desc);
	
	UInt32 nOutNumBytes, nOutNumPackets;
	nOutNumPackets = sampleLength;
	SInt16 sampleData[sampleLength];
	
	AudioFileReadPackets
	(
		audioFileID, false, &nOutNumBytes, NULL, 0, &nOutNumPackets, sampleData
	);
	
	ALsizei nSoundSizeInBytes = sizeof(sampleData);
	ALsizei nSampleRate = desc.mSampleRate;
	
	ALenum format = 0;
	Assert(!(desc.mFormatFlags & kAudioFormatFlagIsFloat), "Can't handle float format audio flag");
	Assert(desc.mFormatID == kAudioFormatLinearPCM, "Must be Linear PCM format audio file");
	
	if ( 16 == desc.mBitsPerChannel )
	{
		if ( 1 == desc.mChannelsPerFrame )
			format = AL_FORMAT_MONO16;
		else if ( 2 == desc.mChannelsPerFrame )
			format = AL_FORMAT_STEREO16;
	}
	else if ( 8 == desc.mBitsPerChannel )
	{
		nSoundSizeInBytes /= 2;
		if ( 1 == desc.mChannelsPerFrame )
			format = AL_FORMAT_MONO8;
		else if ( 2 == desc.mChannelsPerFrame )
			format = AL_FORMAT_STEREO8;
	}
	
	Assert(format != 0, "Couldn't figure out the audio format");
	
	alBufferData(bufferID, format, sampleData, nSoundSizeInBytes, nSampleRate);
}
Tags: nagawrimo, nerd
Subscribe
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 1 comment