T2D, Mac OSX, and Open AL - Common issues explained
by Fenrir Wolf · in Torque Game Builder · 04/17/2005 (9:21 pm) · 10 replies
Okay as requested elsewhere, this is a repost of a thread that I started under the TGE Mac forums. It's also a "mega-thread" explaining all of the problems I have had with sound under OSX using the T2D/TGE.
Introduction
First of all, Open AL is distributed as a framework on the Mac. For those who aren't Mac programmers, frameworks are somewhat equivalent to DLLs under Windows. (Or extensions in prior Mac versions, but that is stretching the comparison even more.) I say "somewhat" because frameworks are more than just dynamically loaded libraries, though that is their main component. They also include the code interface (include files) which allows applications compiled using that framework to interface properly with the dynamic lib.
Confusingly, OSX also features BSD/Linux style static/dynamic libraries, so don't confuse the Open AL framework with, say, the Ogg Vorbis libraries. (Which are distributed as static libraries under TGE/T2D, which are linked at runtime.)
Anyway, back to frameworks. Your application can load frameworks in two methods. One is at executable startup, where it seems the frameworks are loaded as part of the general application load. The paths to the frameworks are hard-coded in the binary and therefore this is how it can find the necessary frameworks. You can use the "otool" command under the Terminal to examine a binary and figure out its dependences. Anyway, by using this method, a referred framework will be searched in various paths by OSX upon app startup, and if found in any of those, loaded. (Refer to Apple's developer's documentation.)
Second, your application can load the framework by hand. This is similiar to how DLLs are loaded under Windows. Your application however must do the searching itself to find the framework. There are some common helper core functions that will load a framework from the usual places, but largely it depends on how the loader is written. TGE/T2D's default loader unfortunately doesn't search for frameworks that might be stored inside of the application itself. (The so-called app bundle.)
Note, I am not a Mac programmer by trade, so I take what I say with a grain of salt. But I believe my interpretation is pretty much correct on this. (Feel free to correct me if I am wrong!)
But I can't get Open AL to work at ALL, even non-embedded!
I've had issues with the latest Open AL from Creative's site not working at under OSX 10.3. To get around this, I have used an older version that Seth Willits has posted on the forums. It works just fine for me. You might want to try this first with the Torque demo.
(on to part 2)
Introduction
First of all, Open AL is distributed as a framework on the Mac. For those who aren't Mac programmers, frameworks are somewhat equivalent to DLLs under Windows. (Or extensions in prior Mac versions, but that is stretching the comparison even more.) I say "somewhat" because frameworks are more than just dynamically loaded libraries, though that is their main component. They also include the code interface (include files) which allows applications compiled using that framework to interface properly with the dynamic lib.
Confusingly, OSX also features BSD/Linux style static/dynamic libraries, so don't confuse the Open AL framework with, say, the Ogg Vorbis libraries. (Which are distributed as static libraries under TGE/T2D, which are linked at runtime.)
Anyway, back to frameworks. Your application can load frameworks in two methods. One is at executable startup, where it seems the frameworks are loaded as part of the general application load. The paths to the frameworks are hard-coded in the binary and therefore this is how it can find the necessary frameworks. You can use the "otool" command under the Terminal to examine a binary and figure out its dependences. Anyway, by using this method, a referred framework will be searched in various paths by OSX upon app startup, and if found in any of those, loaded. (Refer to Apple's developer's documentation.)
Second, your application can load the framework by hand. This is similiar to how DLLs are loaded under Windows. Your application however must do the searching itself to find the framework. There are some common helper core functions that will load a framework from the usual places, but largely it depends on how the loader is written. TGE/T2D's default loader unfortunately doesn't search for frameworks that might be stored inside of the application itself. (The so-called app bundle.)
Note, I am not a Mac programmer by trade, so I take what I say with a grain of salt. But I believe my interpretation is pretty much correct on this. (Feel free to correct me if I am wrong!)
But I can't get Open AL to work at ALL, even non-embedded!
I've had issues with the latest Open AL from Creative's site not working at under OSX 10.3. To get around this, I have used an older version that Seth Willits has posted on the forums. It works just fine for me. You might want to try this first with the Torque demo.
(on to part 2)
#2
04/17/2005 (9:49 pm)
This is a great resource ... however I cannot get it to work. It will not use the embedded OpenAL ... even though it is clearly there within the app.
#3
04/17/2005 (10:55 pm)
Not sure what to suggest, other than stepping through that bit of code I gave and seeing what might be up. I would be interested to hear what you find.
#5
04/17/2005 (11:25 pm)
Could this becaused because I don't have my main.cs etc... inside the the app? Both Orbz and MB have their files etc... inside their respective apps.
#6
04/18/2005 (8:21 am)
I didn't do anything differently such as bundle the main.cs, and it works for me.
#7
I wish I could offer more help but I am not terribly experienced with Apple's Carbon/core API library.
04/18/2005 (2:46 pm)
Jeremy: The location of main.cs shouldn't have anything to do with it. I would suggest you place a breakpoint at the beginning of the LoadFrameworkBundle method and then step through my code. Verify that the path strings are coming up as. (You'll need to convert the CFURLRef's into standard C-strings, but there's an Apple core API function to do that. Check the developer docs, as I can't recall what it is off the top of my head.)I wish I could offer more help but I am not terribly experienced with Apple's Carbon/core API library.
#8
04/18/2005 (5:29 pm)
Man, using Con::printf("stuff"); I can see that your code is doing what it's supposed to do and it's not ever getting to Torque's normal routine. However, once I remove the OpenAL.framework from Library/Frameworks the app just won't even run ... it doesn't print anything to the console or anything ... it's very annoying as it's tough to debug especially when I can see that it's loading from the bundle. The app just won't run unless OpenAL.framework is in there.
#9
04/18/2005 (5:38 pm)
Well, my app is using the bundled drivers ... I installed the newest OpenAL which didn't work ... and I can see that KOTM is using the version 1.0.5 framework bundled with the system ... just for some reason without that framework in place the app won't initialize at all ...
#10
04/18/2005 (5:44 pm)
Yep, and if I take OpenAL.framework out of the Torque Demo bundle it loads the 1.2.1 framework installed on the system ... then if I put the 1.0.5 back in the bundle it loads those drivers so this works. Perhaps I misunderstood which OpenAL.framework you were removing to make sure this works? I was assuming this would make it possible for your game to run on a system with no OpenAL.framework on it at all.
Torque Owner Fenrir Wolf
Embedding Open AL into your games
Normally, TGE/T2D will use the standard Open AL search paths as I have mentioned above. But there is a way to get TGE/T2D to use the embedded framework in an app bundle. Then, at build time, you can instruct Xcode to copy that framework into the app bundle. Now, your application will have no external dependancies and won't require Open AL installation before use.
First, modify macCarbWindow.cc. Scroll down to around line 188 (in LoadFrameworkBundle). Add this section of code before *bundlePtr = NULL;:
*bundlePtr = NULL; // first, let's look in our app bundle, under frameworks CFURLRef privFrameworksURL = NULL ; CFBundleRef appBundle = NULL; appBundle = CFBundleGetMainBundle(); bool localfind = false ; privFrameworksURL = CFBundleCopyPrivateFrameworksURL (appBundle) ; if (privFrameworksURL) { bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, privFrameworksURL, framework, false); if (bundleURL) { *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL); if (*bundlePtr) { if ( CFBundleLoadExecutable( *bundlePtr ) ) { //found it under the app's private framework localfind = true ; } } } } if (privFrameworksURL) CFRelease (privFrameworksURL) ; if (bundleURL) CFRelease (bundleURL) ; if (*bundlePtr) CFRelease(*bundlePtr); if (localfind) // Yay! We found it, so return with no error.. return noErr ; // Otherwise, fall through to Torque's usual bundle load logicWhat this does is first look in the application's bundle, under frameworks, before it falls through to the standard loading code which will attempt to find it under /Library/Frameworks.
Second, you'll need to modify the Xcode project. You first need to make sure that the OpenAL framework lives in /Library/Frameworks, ie: a standard install of Open AL using the archive from above. I am not exactly sure how to avoid this step as of yet, as Xcode needs to find the framework in order to do an application build. Even though Xcode needs the framework's headers and such, it won't actually bind the framework to your application. (You can verify this with the otool -L command. Open AL should not be listed at all.)
In order to get Open AL inside your app bundle, you will need to add a build step to copy the framework into your bundle. First, under the Project menu, select "New Build Phase." Under the sub-menu, select "New Copy Files Build Phase." When it pops up asking you the destination, select "Frameworks." Leave the sub-path at root.
Now, the final step is to go up to the Frameworks sub-folder under the project and locate the OpenAL.Framework. Using the mouse, drag-and-drop this into the Build target for your project, under the Copy Files target. Now, do a target build.
Under the Detailed Build results, you should see it to do a PBXcp using that framework. To verify that the framework is inside your app bundle, locate the recently built app, right click on it and select "Show Package Contents". Under the directory Contents/Frameworks you should see the OpenAL.Framework directory.
I haven't done rigorous testing, but my Mac-using friends tell me that Cloudburst works fine, which uses the above code. You can test it by temporary renaming or moving the OpenAL.Framework from under Library/Frameworks.
My Oggs are playing at 2x the speed! My music sounds terrible!
It seems that the Vorbis interface with Open AL does not properly up-sample sounds to 44 Khz. Therefore, make sure that all Oggs are at 44 KHz.
I'm not sure if this is a bug in Open AL or with T2D/TGE's code. I suspect the latter, as 22KHz .wavs play just fine. But I haven't tested this out this out in detail.