Please confirm this: OpenAl Problem on MAC

BlitzMax Forums/BlitzMax Programming/Please confirm this: OpenAl Problem on MAC

Midimaster(Posted 2009) [#1]
Can you please help me and test a bug i have found in BlitzMax for Mac OsX 10.5?

I wrote a recording software which takes the signal from microphone and works with the samples afterwards (fft etc...)

On Windows it is working perfect, but on Mac it crashed. Now I reduced the code to a minimum to find the error and noticed that a OpenAl Function is working different to the PC-Version.

On the PC the function "alcCaptureSamples" fetches some samples from the device and reduces the number of remaining samples. On the MAC the function does not reduce the number of remaining samples.

What Do I do wrong or is ot a bug?

the code demontrates the behavior without crashing. Normaly "alcCaptureSamples" should reduce the amount of remaining samples:

*** EDIT #1 : made this code superstrict ****

SuperStrict
Global StartZeit%, Zeit%, NumSamples%, Before%
Global Device%, CaptureDevice%
Global VoidSample:TAudioSample=CreateAudioSample(44100*2,44100,SF_MONO16LE)


Device=alcOpenDevice(Null)
If Device=Null Then RuntimeError "No access to OpenAL Device !"
InitCapture()

Graphics 800,600,0
StartZeit=MilliSecs()+600

alcCaptureStart(CaptureDevice)

Repeat
	If zeit<MilliSecs() Then
		zeit=MilliSecs()+500
		Cls
		DrawText" i am ok             time: " + Int((MilliSecs()-StartZeit)/1000) + " sec", 100,100
		alcGetIntegerv(CaptureDevice, ALC_CAPTURE_SAMPLES, 4, Varptr(NumSamples))	
		before=numsamples
		DrawText"amount of samples : " + Int(numsamples/1000)+"k", 100,120
		If numsamples>40000 Then
			numsamples=40000
			 DrawText "         fetching : " + Int(numsamples/1000)+"k", 100,140
			 alcCaptureSamples(CaptureDevice, VoidSample.Samples, NumSamples)
			' check how much remai samples

		Else
			 DrawText "         fetching : " + "00k", 100,140
		
		EndIf
		      DrawText"-------------------------------------- ", 100,160
 			alcGetIntegerv(CaptureDevice, ALC_CAPTURE_SAMPLES, 4, Varptr(NumSamples))	
		      DrawText"remaining samples : " + Int(numsamples/1000)+"k", 100,180
		      DrawText"       difference : " + Int((before-numsamples)/1000)+"k", 100,220
		Flip
	EndIf
Until KeyHit(key_escape)
ShutdownOpenAL
End



Function InitCapture%()
   	If (alcIsExtensionPresent(Device, "ALC_EXT_CAPTURE") = AL_FALSE) Then 
		RuntimeError "Your OpenAL Version is not extended for Capture"
	EndIf
	CaptureDevice = alcCaptureOpenDevice(Null, 44100, AL_FORMAT_MONO16, 44100*5*2);
   	
	If Not(CaptureDevice) Then
		RuntimeError "No access to OpenAL capture Device !"
	EndIf
	Return True
EndFunction



Function ShutdownOpenAL()
	alcCaptureStop(CaptureDevice)
    	alcCloseDevice(CaptureDevice)
    	alcCloseDevice(Device)
EndFunction




The buffer has a size for 441k of samples.
If you run the program you can see on the screen:
In the first line you see, how many bytes are in the buffer
In the third line you see the remaining bytes after fetching them.

I fetch 40.000 when they are avaiable. So the remaining bytes should be smaller and the total avaiable bytes (in the next round) should decrease.

but the amount runs to 441k. this is wrong! On the windows it is working perfect.

Could please somebody test this on a mac and confirm my, that he cannot see this behavior.


Midimaster(Posted 2009) [#2]
Hi Mark,

did you have a look on this bug? Is it solved in new 1.36 version?


marksibly(Posted 2009) [#3]
Hi,

Just having a look now, but it doesn't compile due to 'VoidSample.Samples'?

Adding my own 'Samples' buffer, I then get "No access to OpenAL capture Device !" - guess I need a microphone?!?

But I'm not sure if there's much I could do anyway - it looks like it's pretty much 'pure' OpenAL, so it may be a bug in Apple's OpenAL implementation in which case there's nothing I can do.

Have you tried looking for an update to OpenAL on the Mac?

Also, InitDevice is in fact using a 'Null' device, which perhaps relates to this...

http://lwjgl.org/forum/index.php?topic=2749.0

I strongly suggest you rewrite the sample so it compiles/runs and uses 'Strict' mode.


Midimaster(Posted 2009) [#4]
Hi Mark

My stupid mistake. I took some snipplets from my code for this sample and forgot to make it SUPERSTRICT. Now I made the code better.

Normaly there is no need for a microphon, the inpute device should work always, it captures "what you hear". I do not understand, why your version has an error in InitCapture. On Mac OpenAL is already installed and alcIsExtensionPresent should say true since years on every MAC.

At my (new) MAC MINI it starts perfect, but has this behavior of not reducing the amount of remaining samples.

I do not believe in an OpenAL-Problem. This feature is too basic! Somebody would have recognized this error before. I believe in an error in alcCaptureSamples()-function of blitzmax. Or is this function already calling the OpenAL-Driver?

I can make a better commented code, if it would help you...

Please help me, this feature is very important for us.


marksibly(Posted 2009) [#5]
Hi,

> I believe in an error in alcCaptureSamples()-function of blitzmax. Or is this function already calling the OpenAL-Driver?

OpenAl commands are direct calls into static libs provided by X-Code (the Apple development kit) - they're not provided by me/BlitzMax etc.

Same goes with glBegin, glEnd etc. in OpenGL, these are direct calls into the OpenGL libraries and are also not written be me!

And I wouldn't discount the idea there's a bug in Mac OpenAL - existing audio capture software on the Mac probably uses CoreAudio, a completely different API (probably the one Mac OpenAL uses). OpenAL isn't really that 'big' yet...

But post working code and I'll have a look anyway.


Midimaster(Posted 2009) [#6]
the working code is already there. I did an EDIT in #1. see above


marksibly(Posted 2009) [#7]
Hi,

Ok, interesting!

It works on 10.4 (I think - see results below), but on 10.6 it fails the check for ALC_EXT_CAPTURE.

If I remove the check, it manages to open the capture device anyway, but doesn't seem to be removing any samples - ie: samples remaining just keeps going up until it hits 441K.

Sorry, but to me it really looks like a bug (or 2) in the OpenAL implementation for MacOS 10.5/10.6.




Midimaster(Posted 2009) [#8]
That's interesting:

In 10.4 it does exactly, what it should...

In 10.5 it does not reduce the counter. Remove is not the right word, I think the ring buffer is working, so there are always "new" samples to fetch, and because the function believes, that "nothing" was fetched before, it offers the last 441k (all). I will test, whether the samples differ each Capture...

And in 10.6 the ALC_EXT_CAPTURE fails? Strange!

And you are 100% sure, that BlitzBasic passes the variales VoidSample.Samples and NumSamples in a correct way to the function...

alcCaptureSamples(CaptureDevice, VoidSample.Samples, NumSamples)?

..Because this would cause the same effect! You would get the same effect, if NumSamples=0 or NULL or VoidSample.Samples=NULL, or?

Can you contact the OpenAL-Developers? I think a request from "Blitz Research" is much more serious, than from anybody (Midimaster).

For me it looked like the OpenAl-Implementation is a kernel part of the
BlitzMax, because it comes with the fundamental Install. No third party mod necessary. So Blitz Research should have a fundamental interest to keep this part running, or?

please care about it, thank you


peter

p.s.
sorry for my bad english, sometime it may sound a little bit "bumbling".


Brucey(Posted 2009) [#9]
And in 10.6 the ALC_EXT_CAPTURE fails? Strange!

Yes. It fails for me too.

On further investigation, here is a list of valid extension names (as lifted from OpenALDiagnostics.cs):
            "ALC_ENUMERATE_ALL_EXT",
            "ALC_ENUMERATION_EXT",
            "ALC_EXT_ASA",
            "ALC_EXT_ASA_DISTORTION",
            "ALC_EXT_ASA_ROGER_BEEP",
            "ALC_EXT_BRS_GAME_LICENSE_REQUIRED",
            "ALC_EXT_capture",
            "ALC_EXT_DEDICATED",
            "ALC_EXT_EFX",

Note the lowercase "capture".
Swapping that string into your example, it runs.

In the example, I see it running until it hits the 441k ... without apparently removing any samples.


Midimaster(Posted 2009) [#10]
Hy Mark,

did you get any message from OpenAL-Team to this bug?


marksibly(Posted 2009) [#11]
Hi,

I got openal to build on 10.6, and think I may have actually fixed this. I posted the fix to the openal mailing list, but the apple guy there hasn't replied yet.

So I have a new openal.dylib ready to go, but I'm not sure how you'd go about redistributing it with your app.

The current module openal.c code looks for the entire .framework in a couple of blah/Library locations, so this'd have to be changed if you wanted to loaded a version in the currentdir or something.

Any ideas Brucey?


Brucey(Posted 2009) [#12]
So I have a new openal.dylib ready to go, but I'm not sure how you'd go about redistributing it with your app.


You can optionally include a "framework" proper with your application bundle.
I've done this with my Bah.Growl module, which is designed to include a copy of the Growl framework in the app bundle. The idea with that case is that it can install Growl into the system if you do not have it installed.

On the other hand, you should easily be able to drop the .dylib in the resources folder of your app bundle, and have it load from there.
But, you may want to run this against the .dylib first :
install_name_tool -id @executable_path/libopenal.dylib libopenal.dylib

By default (unless you specify otherwise during the compilation of the lib), the .dylib file will have the wrong internal locator (or whatever it is called).

Running this will show you :
otool -D libopenal.dylib


The result wants to look something like this :
libopenal.dylib:
@executable_path/libopenal.dylib

and can be fixed using the command-line mentioned earlier.


Mark, do you have a plan for making it easy for users to distribute the .dylib in their app bundle? ;-)
(my modified bmk handles this by allowing a post build script, which can copy stuff into the bundle automagically as part of a normal build)


Midimaster(Posted 2010) [#13]
@mark

did you hear anything from OpenAL-Team meanwhile? I'm still waiting for a resolution for that ALC_EXT_capture-Problem on MAC.

I did not really understand, what Brucey and want you tell me with the openal.dylib? Could this be a workaround for me (and my customers)?

The customers are stil waiting and some of them become angry now. So I slowly get really problems...

What would you suggest, I should do? Please help me.


marksibly(Posted 2010) [#14]
Hi,

No, haven't heard back from the Mac guy and don't honestly expect to.

Anyway, here's one possible solution: a replacement OpenAL.framework.This works for me, but I make absolutely NO guarantees that it'll work for anyone else.

1) Down and unzip http://www.blitzbasic.com/tmp/OpenAL.framework.zip

2) Backup your existing /System/Library/Frameworks/OpenAL.framework.

3) Replace it with the downloaded framework. You''ll need to enter your admin password to do this.

NOTE: This should ONLY be used with MacOS 10.5 or 10.6, but the problem doesn't occur on 10.4 so that's cool.

It was built on 10.6 so *should* work on 10.5 - can someone please confirm?

If this doesn't work for your users - or they are not willing to try - then you've got no choice really but to offer a refund.

And please test more thoroughly in future before releasing software! I know it's a pain to have copies of all platforms AND OS's on hand but you can at least get a friend or acquaintance from blitzbasic.com to test things out.


Midimaster(Posted 2010) [#15]
Thank you.
I will test it on my MAC OsX 10.5 and see, what happens....then write you back tomorrow...


Roger(Posted 2010) [#16]
Midimaster

Also with Mark's replacement, re-read Brucey's message on how you could ship and use the fixed openal dylib just with your application by including it in the resouce folder of your application package.

Then you have the best of both worlds, a shipping product where everything to do with your product is encapsulated in your app package. And your not changing from the apple-approved vanilla openAL (even though it's broken) for the rest of your users system.

I've read Brucey's instructions and I can follow it, but I suspect English might not be your first language?

If marks built version fixes it and you want to be able to distribute it more simply then replacing a file in /System/Library/Frameworks on your customers machines, then write back if you want futher assistance.

Regards,

Roger.


Midimaster(Posted 2010) [#17]
@Roger,

thank you for your assistence. You are right:

1.
I am from germany and my english is not very good. So I have problems to communicate about this problems with board members.

2.
I am also not very confirmed with MAC and OsX. So I do not know how to change something system-related really carefully.

3.
Our customers are teachers and musicians, parents and pupils. And they do not know how to change something in system. And they would not do it (to prevent making a mistake)


The best way would be to send to the customers an installation-File which changes, what is necessary. Or to bundle it to my executable, so each time, when they start the software, it uses a workaround of the OpenAL.

But i do not know, what to pack and how to pack this to the executable. Can I do this with standard tools of Mac and BMax?

Is it possible to build a special BlitzMax which contains the changes and the compiler produces special executables? Or will it be a solution, where I pack some additional files together with the executable?

This are our first steps in MAC programming and already such a problem.

How would you do it? What is your suggestion?

Thanks a lot!

Midimaster


Brucey(Posted 2010) [#18]
If you can wait until tonight, I'll have a look at testing this out on my Mac - which also wasn't working with the original example.

I also have a method of placing a framework INSIDE the app bundle, which would mean not having to replace the system framework.

I'll post back with more details (of success or failure) this evening. :-)


Brucey(Posted 2010) [#19]
I can confirm that Mark's fix works :-)
Rather than the buffer filling up to 441k, it now fills a little, and flushes as the program runs. Yay!


I also have a "patch" for Pub.OpenAL - openal.c - which allows the module to first search the application bundle for the framework before falling back to the system :
int LoadOpenAL(){

	int s = 2048;
	char c[s];
	
	_NSGetExecutablePath(c, &s);
	
	char * pos = strrchr(c, '/');
	*pos = 0;
	strcat(c, "/../Frameworks/OpenAL.framework");

	openAL=OpenBundle( c );
	if( !openAL ) openAL=OpenBundle( "/System/Library/Frameworks/OpenAL.framework" );
	if( !openAL ) openAL=OpenBundle( "/Library/Frameworks/OpenAL.framework" );
	
	return openAL!=0;
}

The change is to lookup the location of the binary, and look up the framework in the folder relative to it.
I'm sure there's a better way to do that, but it seems to work here.

With this patch, the folder "OpenAL.framework" can be dropped into the Contents folder inside the application bundle.

This process can be automated by my custom BMK... or you need to do it by hand otherwise in Finder : right click on the app in Finder -> Show Package Contents. In Contents folder, create one called Frameworks. Copy into the new folder. The full path inside the Bundle would then look like : Contents/Frameworks/OpenAL.framework

Mark, Any chance of this little patch being added? (or something better). Then we at least have another choice as to where the framework is available from.

:o)


Midimaster(Posted 2010) [#20]
Brucey, thank you for your assitance, but this seems not to work!

Ok..please confirm, that I did everything right:

1.
I did download the ZIP-File of Mark. It was a folder named "OpenAL.framework"

2.
I found the folder "Sing-A-Pur.app/Contents/". Inside I created an new folder named "Frameworks". At the End I copied the folder "OpenAL.framework" into the folder "Sing-A-Pur.app/Contents/"

3.
I found the file "openal.c" in the folder "blitzmax/mod/pub.mod/openal.mod/"

4.
With an editor I opened the file and changed the function "int LoadOpenAL()" in section "#if __APPLE__" to the code you wrote me. At the end I saved it.



Some questions:

1.
Do I now have to "rebuild" anything of BMax, before building my Sing-A-Pur.App?

2.
Can I distribute the "Open AL framework" included in my Sing-A-Pur.App with INCBIN? I always use Korriolis-ZipStream. My planned procedure: During the first start of Sing-A-Pur on user's computer the software has to create (in folder "Contents") a folder "Framework" and inside a folder "OpenAl.frameworks." and has to copy all files from INCBIN to this folder.
forder "Contents/". Is it allowed? Apple-conform?

3.
Where to place the new "Open AL framework"-files, if I want to test the code from inside MaxIDE?

4.
As I understood it, the fix in openal.c can remain also after finishing the project, because with not finding the new framework the code will takes the regular one.


Ok, I did the "build modules" of Bmax. But the OpenAL seems not to work proper. not in IDE and not as StandAlone. It shows the same behavior like before

What did I do wrong?


Mac OsX 10.5.8 (9L31a) Kernel Darwin 9.8.0
CoreAudio 3.1.2 OpenAl 1.2
BlitzMax 1.32


here ist my version of openal.c:
int LoadOpenAL(){
	
	int s = 2048;
	char c[s];
	
	_NSGetExecutablePath(c, &s);
	
	char * pos = strrchr(c, '/');
	*pos = 0;
	strcat(c, "/../Frameworks/OpenAL.framework");
	
	openAL=OpenBundle( c );
	if( !openAL ) openAL=OpenBundle( "/System/Library/Frameworks/OpenAL.framework" );
	if( !openAL ) openAL=OpenBundle( "/Library/Frameworks/OpenAL.framework" );

	
	return openAL!=0;
}


Can I test, whether the new framework will be found?


Brucey(Posted 2010) [#21]
1) After you change a module, you must run "Build Modules" from the IDE. If you have never run this before, it will build ALL modules. Otherwise, it will only build modules that have changed recently.

You will also then need to rebuild your application.

2) The framework should be copied into the application bundle by you. You would ship your application with this step already completed.
On Mac, an application usually consists of this Bundle structure, so it is normal that you might also have Frameworks included with it.

3) To test within the IDE, build your application once. Go to Finder, and Show Package Contents of the app you have just built. Follow your step 2. if the Frameworks folder does not exist yet.
You can now RUN the app from the IDE if you want to.
If you have a debug version, of course you must copy the files into the debug version of the app.
Unless you delete the app, the framework should remain there between builds.

4) That is correct.

Can I test, whether the new framework will be found?

After the strcat() line, you can add this debug :
printf("PATH = %s\n", c);fflush(stdout);

It would output the full path of where it thinks the framework should be, onto the console - if you run from the IDE you will see this in the Output window.

If you have followed all the steps correctly and it is still not working, I am not sure why that is the case. Other than perhaps you are on 10.5. But that should not really be a problem.
The only other case where there might be an issue is if the system has already loaded the system OpenAL into memory. As I understand that it is possible for the system to cache Frameworks. But I am not sure if this will ever apply.


Midimaster(Posted 2010) [#22]
@Brucey
I thought you checked it on Mac OsX10.5? Do you have 10.6?

@Mark
Maybe it is, because i use old BMax 1.32. So now I try a test with 1.36. Did you change anything since 1.32 in the OpenAL-related files?

i now changed the code in Openal.c to see what happens to:

...
	strcat(c, "/../Frameworks/OpenAL.framework");
	printf("PATH = %s\n", c);fflush(stdout);

	openAL=OpenBundle( c );
	printf("Is it True = %s\n", !openAL);fflush(stdout);	
	return openAL!=0;
....


to be sure, that it cannot use the system openal. and this was the result:

it is running and the message is:

Building testcap
Compiling:testcap.bmx
Linking:testcap
Executing:testcap
PATH = /Users/peter/Basic/Mikrofon/testcap.app/Contents/MacOS/../Frameworks/OpenAL.framework
Is it True = (null)


Is this as expected? After this the functions runs and shows the same behavior like before


Another thing I could not understand:

You told me, that the correct name of the Cature is "ALC_EXT_capture". But when i ty this i always get this (my) error message:
"Your OpenAL Version is not extended for Capture"

Next question:

The original system OpenAL.framework folder has 16 files. Mark's only 13. Is this a problem?


I now will test to replace the original files in system and tell you what happend.


EDIT:

Now i replaced the 16 files in system with marks 13 and this error message appears:

Building testcap
Compiling:testcap.bmx
Linking:testcap
Executing:testcap
PATH = /Users/peter/Basic/Mikrofon/testcap.app/Contents/MacOS/../Frameworks/OpenAL.framework
Is it True = (null)
2010-01-22 10:32:19.492 testcap[117:717] Error loading /Users/peter/Basic/Mikrofon/testcap.app/Contents/Frameworks/OpenAL.framework/OpenAL: dlopen(/Users/peter/Basic/Mikrofon/testcap.app/Contents/Frameworks/OpenAL.framework/OpenAL, 265): no suitable image found. Did find:
/Users/peter/Basic/Mikrofon/testcap.app/Contents/Frameworks/OpenAL.framework/OpenAL: unknown required load command 0x80000022
/System/Library/Frameworks/OpenAL.framework/OpenAL: unknown required load command 0x80000022



Brucey(Posted 2010) [#23]
unknown required load command 0x80000022

I see... Before, when it failed to load from your app bundle, it fell back and loaded the system framework.

Now that you have changed system, it is showing the error message.
That appears to be a problem with Mark having built on 10.6 ?
Perhaps Mark needed to specify a minimum version when he is building it.

But it does work on my Mac Mini with 10.6, so that proves that whatever Mark has changed in the framework has fixed a bug with OpenAL on my system.

OpenAL is provided by APPLE, so if there is a bug that needs fixed, one would expect them to fix it and provide the patch in an update to OS X.


You told me, that the correct name of the Cature is "ALC_EXT_capture"

It is on 10.6
You may want to test for BOTH names. It looks to have changed in 10.6.


Midimaster(Posted 2010) [#24]
Yes, thats it. Also when I put Mark's patch in the system-directory it fails too.

It is a first solution for me: I have to tell my customers to upgrade to 10.6 or to stay at 10.4.


Today I ordered Upgrade to 10.6 and the next days I will test Mark's code under 10.6.

@brucey
Thank you for the help and the exact explanations. I see, you did find the other post from me related to MIDI.


@mark
are you able to find out, what would be a solution for 10.5? Of course I would pay for your help (if it is affordable...)


Brucey(Posted 2010) [#25]
are you able to find out, what would be a solution for 10.5

It should be relatively easy to build a 10.5 compatible version of the library.

If I knew what changes he made, I could try it myself.


marksibly(Posted 2010) [#26]
Ok,

I've modified xcode project to use the 10.5 SDK, rebuilt OpenAL.framework and uploaded it to the same place above: http://www.blitzbasic.com/tmp/OpenAL.framework.zip

Brucey, if that doesn't work, changes to make to SVN version from svn://connect.creativelabs.com/OpenAL are:

* Change decl of OALRingBuffer::Fetch in trunk/OpenAL-MacOSX/oalOSX.h to:
	OSStatus	Fetch(Byte *data, UInt32 nFrames, SInt64 frameNumber);


* Change defn of OALRingBuffer::Fetch in trunk/OpenAL-MacOSX/oalOSX.cpp to:
OSStatus	OALRingBuffer::Fetch(Byte *data, UInt32 nFrames, SInt64 startFrame)
{
	SInt64 endFrame = startFrame + nFrames;
	if (startFrame < mStartFrame || endFrame > mEndFrame) {
//		printf("error - buffer times: %.0f - %.0f, reading for %.0f - %.0f\n", double(mStartFrame), double(mEndFrame), double(startFrame), double(endFrame));
//		fflush( stdout );
		return -1;
	}

	UInt32 offset0 = FrameOffset(startFrame);
	UInt32 offset1 = FrameOffset(endFrame);
	
	if (offset0 < offset1)
		memcpy(data, mBuffer + offset0, offset1 - offset0);
	else {
		UInt32 nBytes = mCapacityBytes - offset0;
		memcpy(data, mBuffer + offset0, nBytes);
		memcpy(data + nBytes, mBuffer, offset1);
	}
	return 0;
}

From memory, I had a hard time getting it building - it depends on some sample files that seem to have moved in Leopard xcode (or maybe just Snow Leopard).


Midimaster(Posted 2010) [#27]
Hello Mark,

you are the best! I installed the new Framework and (in first tests) it seems to work as expected on 10.5 now!

I am so happy! Thanks to Brucey too, you both are a genius team!!!

Yesterday I had the impression, you have been a little bit nerved after your last post. Excuse me, if I have been a strain on you. But now you deleted the last sentence of your post, I hope, we stay in good contact.

Let me offer you to buy another Blitz-Research product as an allowance for your efforts.

Thank you

peter

@brucey
Unless I'm very much mistaken, an app for 10.5 would fail in 10.6 because of the different spelling of "ALC_EXT_capture"? And could it be, that also the framework 10.5 will now fail on a 10.6 system? So I have to puplish three versions of my program: 10.4, 10.5, 10.6.


Brucey(Posted 2010) [#28]
So I have to puplish three versions of my program

Not really... and there's nothing stopping you from testing against BOTH spellings... you will surely know that if it fails against both that it does not support it.