NativeBoost Questions while wrapping FMOD
I'm wrapping the FMOD cross-platform audio library. The code is MIT and lives at http://smalltalkhub.com/#!/~SeanDeNigris/FMOD ======== Problem #1: ======== I'm calling into the FMOD library with: primStoreIsPlaying: channelHandle in: isPlayingHandle <primitive: #primitiveNativeCall module: #NativeBoostPlugin> "FMOD_RESULT FMOD_Channel_IsPlaying( FMOD_CHANNEL *channel, bool *isplaying);" ^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(NBExternalAddress channel, NBExternalAddress isPlayingHandle)). I call the above with: isPlaying | isPlaying | isPlaying := NBExternalAddress new. self primStoreIsPlaying: channel in: isPlaying. ^ isPlaying value > 0. isPlaying is always 0. The method works directly from C with: int isPlaying = 1; while (isPlaying) { FMOD_Channel_IsPlaying(channel, &isPlaying); } I also tried changing the callout signature to "... bool* isPlayingHandle)" and passing "isPlaying := true." instead of using the NBExternalAddress stuff. I have a few more questions, but this is the most pressing as it's holding up any further development. Thanks! ----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116.ht... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
We'll soon be able to do this in Pharo then :-) My friend David also uses FMOD in there. http://www.youtube.com/watch?v=077sYFHAgTM --- Philippe Back Dramatic Performance Improvements Mob: +32(0) 478 650 140 | Fax: +32 (0) 70 408 027 Mail:phil@highoctane.be | Web: http://philippeback.eu Blog: http://philippeback.be | Twitter: @philippeback Youtube: http://www.youtube.com/user/philippeback/videos High Octane SPRL rue cour Boisacq 101 | 1301 Bierges | Belgium Pharo Consortium Member - http://consortium.pharo.org/ Featured on the Software Process and Measurement Cast - http://spamcast.libsyn.com Sparx Systems Enterprise Architect and Ability Engineering EADocX Value Added Reseller On Thu, Nov 21, 2013 at 10:40 PM, Sean P. DeNigris <sean@clipperadams.com>wrote:
I'm wrapping the FMOD cross-platform audio library. The code is MIT and lives at http://smalltalkhub.com/#!/~SeanDeNigris/FMOD
======== Problem #1: ========
I'm calling into the FMOD library with: primStoreIsPlaying: channelHandle in: isPlayingHandle <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_Channel_IsPlaying( FMOD_CHANNEL *channel, bool *isplaying);"
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(NBExternalAddress channel, NBExternalAddress isPlayingHandle)).
I call the above with: isPlaying | isPlaying | isPlaying := NBExternalAddress new. self primStoreIsPlaying: channel in: isPlaying. ^ isPlaying value > 0.
isPlaying is always 0. The method works directly from C with: int isPlaying = 1; while (isPlaying) { FMOD_Channel_IsPlaying(channel, &isPlaying); }
I also tried changing the callout signature to "... bool* isPlayingHandle)" and passing "isPlaying := true." instead of using the NBExternalAddress stuff.
I have a few more questions, but this is the most pressing as it's holding up any further development.
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116.ht... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
On 21 November 2013 22:40, Sean P. DeNigris <sean@clipperadams.com> wrote:
I'm wrapping the FMOD cross-platform audio library. The code is MIT and lives at http://smalltalkhub.com/#!/~SeanDeNigris/FMOD
======== Problem #1: ========
I'm calling into the FMOD library with: primStoreIsPlaying: channelHandle in: isPlayingHandle <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_Channel_IsPlaying( FMOD_CHANNEL *channel, bool *isplaying);"
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(NBExternalAddress channel, NBExternalAddress isPlayingHandle)).
I call the above with: isPlaying | isPlaying | isPlaying := NBExternalAddress new. self primStoreIsPlaying: channel in: isPlaying. ^ isPlaying value > 0.
isPlaying is always 0. The method works directly from C with: int isPlaying = 1; while (isPlaying) { FMOD_Channel_IsPlaying(channel, &isPlaying); }
I also tried changing the callout signature to "... bool* isPlayingHandle)" and passing "isPlaying := true." instead of using the NBExternalAddress stuff.
err.. again, you must pass an address where value will be stored,
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(
NBExternalAddress channel, NBExternalAddress * isPlayingHandle)).
otherwise you passing NULL pointer, and i quite surprised it not segfaults when you call it like that (looks like they have a check in the library ) you can also use NBExternalTypeValue for that: boolValueClass := NBExternalTypeValue ofType: 'bool'. "sure thing, creating anonymous class for each call is overkill, this should be done once, somewhere else" boolValue := boolValueClass new. self callTheThingWith: boolValue. boolValue value ifTrue: [... blah] (and this will work, assuming you have bool* in signature for this argument). I have a few more questions, but this is the most pressing as it's holding
up any further development.
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116.ht... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
Igor Stasenko wrote
err.. again, you must pass an address where value will be stored,
hee hee... sorry... I don't understand enough of what's going on behind the scenes to adapt well. I reasoned that since last time, the signature was "Whatever**" and you said to make it "NBExternalAddress*", that therefore "Whatever*" (one less *) would be "NBExternalAddress" (also one less *). While we're here, I'll ask my other questions... 1. What's the differenct between <primitive: #primitiveNativeCall module: #NativeBoostPlugin> and the variant with error:? What does the second one buy you? 2. instead of returning useful objects, FMOD returns error codes and you pass a pointer to receive the object. - The first consequence is that I have to wrap all the calls e.g. "self processErrorCode: self primCreate." where processErrorCode: anInteger anInteger = 0 ifFalse: [ self error: 'FMOD returned error code ', anInteger asString ]. Is there a more graceful way to do that? - The second issue is how to create a Smalltalk object from the pointer. What I've been doing is: | soundHandle | soundHandle := NBExternalAddress new. self processErrorCode: (self primCreate: soundHandle on: system handle fromFile: file fullName). sound := FmodSystemSound on: soundHandle. Again, is there a better way? I thought to subclass NBExternalAddress, but evaluating "sound := FmodSystemSound new" to pass to the callout seemed a bit dirty i.e. it is not a invalid instance until initialized by the callout. I also played around with NBExternalObject, but couldn't get that to work either... Thanks for all the support. This is fun!! ----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116p47... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
On 22 November 2013 01:23, Sean P. DeNigris <sean@clipperadams.com> wrote:
Igor Stasenko wrote
err.. again, you must pass an address where value will be stored,
hee hee... sorry... I don't understand enough of what's going on behind the scenes to adapt well. I reasoned that since last time, the signature was "Whatever**" and you said to make it "NBExternalAddress*", that therefore "Whatever*" (one less *) would be "NBExternalAddress" (also one less *).
While we're here, I'll ask my other questions...
1. What's the differenct between <primitive: #primitiveNativeCall module: #NativeBoostPlugin> and the variant with error:? What does the second one buy you?
Historically, NB was first running on Squeak VM, which has no support for primitive error. Using extra #error: keyword in primitive is HIGHLY recommended, unless you want to deal with some quite rare (but possible and thus very hard to track down) wrong error reporting.
2. instead of returning useful objects, FMOD returns error codes and you pass a pointer to receive the object.
- The first consequence is that I have to wrap all the calls e.g. "self processErrorCode: self primCreate." where processErrorCode: anInteger anInteger = 0 ifFalse: [ self error: 'FMOD returned error code ', anInteger asString ]. Is there a more graceful way to do that?
i doubt so.. since it is library API which dictates you to use it in certain way. The proper error handling never hurts (except from causing extra code bloat, of course :)
- The second issue is how to create a Smalltalk object from the pointer. What I've been doing is: | soundHandle | soundHandle := NBExternalAddress new. self processErrorCode: (self primCreate: soundHandle on: system handle fromFile: file fullName). sound := FmodSystemSound on: soundHandle. Again, is there a better way? I thought to subclass NBExternalAddress, but evaluating "sound := FmodSystemSound new" to pass to the callout seemed a bit dirty i.e. it is not a invalid instance until initialized by the callout. I also played around with NBExternalObject, but couldn't get that to work either...
The better way is to subclass from NBExternalObject then which made exactly for such purposes, by holding an opaque handle to something (you don't care what is inside), and simplifies a lot of things.
Thanks for all the support. This is fun!!
You are very welcome.
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116p47... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
Igor Stasenko wrote
The better way is to subclass from NBExternalObject then which made exactly for such purposes, by holding an opaque handle to something (you don't care what is inside), and simplifies a lot of things.
I made "NBExternalObject subclass: #FMOD_SYSTEM". I then tried to use it via: system := FMOD_SYSTEM new. err := self System_CreateNBExternalObject: system. With callout: ^ self nbCall: #(FMOD_RESULT FMOD_System_Create(NBExternalObject system)). For the argument type in the signature, for good measure I tried: 1. NBExternalObject 2. FMOD_SYSTEM 3. NBExternalAddress All three with zero, one, and two *'s after. The only one that didn't report some variety of "An instance of Xyz expected" was "FMOD_System_Create(FMOD_SYSTEM system)" for which the library returns an invalid argument error code. btw if anyone wants to play with it: 1. Gofer it smalltalkhubUser: 'SeanDeNigris' project: 'FMOD'; package: 'FMOD'; load. 2. Download the FMOD library for your platform: - windows - http://www.fmod.org/download/fmodstudio/api/Win/fmodstudioapi10208win-instal... - Mac - http://www.fmod.org/download/fmodstudio/api/Mac/fmodstudioapi10208mac-instal... 3. Copy the library to "FileLocator imageDirectory / 'FMOD Programmers API/api/lowlevel/lib/libfmod.dylib'" The working example is: | sound | sound := FmodSound fromFile: '/path/to/file.mp3' asFileReference. [ sound play ] fork. The broken one described above is: "FMOD exampleNBExternalObject." ----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116p47... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
On 22 November 2013 05:09, Sean P. DeNigris <sean@clipperadams.com> wrote:
Igor Stasenko wrote
The better way is to subclass from NBExternalObject then which made exactly for such purposes, by holding an opaque handle to something (you don't care what is inside), and simplifies a lot of things.
I made "NBExternalObject subclass: #FMOD_SYSTEM". I then tried to use it via: system := FMOD_SYSTEM new. err := self System_CreateNBExternalObject: system. With callout: ^ self nbCall: #(FMOD_RESULT FMOD_System_Create(NBExternalObject system)).
For the argument type in the signature, for good measure I tried: 1. NBExternalObject 2. FMOD_SYSTEM 3. NBExternalAddress All three with zero, one, and two *'s after. The only one that didn't report some variety of "An instance of Xyz expected" was "FMOD_System_Create(FMOD_SYSTEM system)" for which the library returns an invalid argument error code.
yet again, you miss the right solution: you must pass a pointer to where value will be stored (since function doing exactly that).
so you should do it like: 1. "NBExternalObject subclass: #FMOD_SYSTEM". 2. method to call the function will look like following: create: system ^ self nbCall: #(FMOD_RESULT FMOD_System_Create(FMOD_SYSTEM * system)). 3. and call it like following: system := FMOD_SYSTEM new. self handleError: (self create: system) ifOk: [ ^ system ] 3a. optionally, you want want to initialize it just after you know that you obtained correct handle, to do that, you could do following: FMOD_SYSTEM class>>new | system | system := super new. self handleError: (self create: system) ifOk: [ ^ self newWithHandle: system handle ] and newWithHandle: could look something like following: newWithHandle: aHandle system := super basicNew. system handle: aHandle. ^ system initialize (because it is important to set the handle first, like that you can actually initialize something more by using it, which you logically do, just after creating a new handle. and note you must not call 'super initialize' then, because it will reset handle.) and i'm sure you can find more elegant solution :) btw if anyone wants to play with it:
1. Gofer it smalltalkhubUser: 'SeanDeNigris' project: 'FMOD'; package: 'FMOD'; load.
2. Download the FMOD library for your platform: - windows -
http://www.fmod.org/download/fmodstudio/api/Win/fmodstudioapi10208win-instal... - Mac -
http://www.fmod.org/download/fmodstudio/api/Mac/fmodstudioapi10208mac-instal...
3. Copy the library to "FileLocator imageDirectory / 'FMOD Programmers API/api/lowlevel/lib/libfmod.dylib'"
The working example is: | sound | sound := FmodSound fromFile: '/path/to/file.mp3' asFileReference. [ sound play ] fork.
The broken one described above is: "FMOD exampleNBExternalObject."
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116p47... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
So, here the changes which should work (but i didn't tested). And being on your place, i would get rid of FMOD_SYSTEM class, because you can just subclass FmodSystem from NBExternalObject directly (and use it in signatures) and so it will be holding the handle, and naturally work as a representation of external entity. Also note that in this case FmodSystem is alias to C FMOD_SYSTEM* so, for every function which expects FMOD_SYSTEM*, you should just use FmodSystem, and if it expects FMOD_SYSTEM**, you using FmodSystem* basically, same as if you would have: typedef FmodSystem FMOD_SYSTEM*; in C. On 22 November 2013 15:10, Igor Stasenko <siguctua@gmail.com> wrote:
On 22 November 2013 05:09, Sean P. DeNigris <sean@clipperadams.com> wrote:
Igor Stasenko wrote
The better way is to subclass from NBExternalObject then which made exactly for such purposes, by holding an opaque handle to something (you don't care what is inside), and simplifies a lot of things.
I made "NBExternalObject subclass: #FMOD_SYSTEM". I then tried to use it via: system := FMOD_SYSTEM new. err := self System_CreateNBExternalObject: system. With callout: ^ self nbCall: #(FMOD_RESULT FMOD_System_Create(NBExternalObject system)).
For the argument type in the signature, for good measure I tried: 1. NBExternalObject 2. FMOD_SYSTEM 3. NBExternalAddress All three with zero, one, and two *'s after. The only one that didn't report some variety of "An instance of Xyz expected" was "FMOD_System_Create(FMOD_SYSTEM system)" for which the library returns an invalid argument error code.
yet again, you miss the right solution: you must pass a pointer to where value will be stored (since function doing exactly that).
so you should do it like: 1. "NBExternalObject subclass: #FMOD_SYSTEM".
2. method to call the function will look like following: create: system ^ self nbCall: #(FMOD_RESULT FMOD_System_Create(FMOD_SYSTEM * system)).
3. and call it like following:
system := FMOD_SYSTEM new. self handleError: (self create: system) ifOk: [ ^ system ]
3a. optionally, you want want to initialize it just after you know that you obtained correct handle, to do that, you could do following:
FMOD_SYSTEM class>>new | system | system := super new. self handleError: (self create: system) ifOk: [ ^ self newWithHandle: system handle ]
and newWithHandle: could look something like following:
newWithHandle: aHandle
system := super basicNew. system handle: aHandle. ^ system initialize
(because it is important to set the handle first, like that you can actually initialize something more by using it, which you logically do, just after creating a new handle. and note you must not call 'super initialize' then, because it will reset handle.) and i'm sure you can find more elegant solution :)
btw if anyone wants to play with it:
1. Gofer it smalltalkhubUser: 'SeanDeNigris' project: 'FMOD'; package: 'FMOD'; load.
2. Download the FMOD library for your platform: - windows -
http://www.fmod.org/download/fmodstudio/api/Win/fmodstudioapi10208win-instal... - Mac -
http://www.fmod.org/download/fmodstudio/api/Mac/fmodstudioapi10208mac-instal...
3. Copy the library to "FileLocator imageDirectory / 'FMOD Programmers API/api/lowlevel/lib/libfmod.dylib'"
The working example is: | sound | sound := FmodSound fromFile: '/path/to/file.mp3' asFileReference. [ sound play ] fork.
The broken one described above is: "FMOD exampleNBExternalObject."
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116p47... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
Hi 2013/11/22 Igor Stasenko <siguctua@gmail.com>
2. instead of returning useful objects, FMOD returns error codes and you pass a pointer to receive the object.
- The first consequence is that I have to wrap all the calls e.g. "self processErrorCode: self primCreate." where processErrorCode: anInteger anInteger = 0 ifFalse: [ self error: 'FMOD returned error code ', anInteger asString ]. Is there a more graceful way to do that?
i doubt so.. since it is library API which dictates you to use it in certain way. The proper error handling never hurts (except from causing extra code bloat, of course :)
Is it good idea to override (or create new) #nbCall: method to handle library common logic? (when any library function returns error code)
On 23 November 2013 17:42, Denis Kudriashov <dionisiydk@gmail.com> wrote:
Hi
2013/11/22 Igor Stasenko <siguctua@gmail.com>
2. instead of returning useful objects, FMOD returns error codes and you pass a pointer to receive the object.
- The first consequence is that I have to wrap all the calls e.g. "self processErrorCode: self primCreate." where processErrorCode: anInteger anInteger = 0 ifFalse: [ self error: 'FMOD returned error code ', anInteger asString ]. Is there a more graceful way to do that?
i doubt so.. since it is library API which dictates you to use it in certain way. The proper error handling never hurts (except from causing extra code bloat, of course :)
Is it good idea to override (or create new) #nbCall: method to handle library common logic? (when any library function returns error code)
of course, the #nbCall: is just a convenience method and meant to be overridden if necessary. nbCall: fnSpec " you can override this method if you need to" ^ (self nbCalloutIn: thisContext sender) convention: self nbCallingConvention; function: fnSpec module: self nbLibraryNameOrHandle And nbCallingConvention, nbLibraryNameOrHandle is there for override as well. A more verbose form is: self nbCallout stdcall; options: #( - optDirectProxyFnAddress optAllowExternalAddressPtr); function: #( NBBootstrapUlong HeapAlloc (ulong heapHandle , 0 , SIZE_T size) ) module: #Kernel32 But be aware though, that this code usually invoked once during code generation, and later no method code is invoked because it just runs a primitive (primitiveNativeCall), and if it succeeds, it just returns with result, without running a method's body. So, nbcall can be changed/extended if you need extra thing at code generation stage, or you want to handle primitive error(s) differently. But not for handling things like function return values (which happens to be a library's error/success code). -- Best regards, Igor Stasenko.
I really think that NativeBoost MUST HAVE a decent documentation. It is a central part of Pharo and Igor you should do something about it. If I would know I would have written a chapter on it but I cannot because I DO NOT KNOW. Stef
On 21 November 2013 22:40, Sean P. DeNigris <sean@clipperadams.com> wrote: I'm wrapping the FMOD cross-platform audio library. The code is MIT and lives at http://smalltalkhub.com/#!/~SeanDeNigris/FMOD
======== Problem #1: ========
I'm calling into the FMOD library with: primStoreIsPlaying: channelHandle in: isPlayingHandle <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_Channel_IsPlaying( FMOD_CHANNEL *channel, bool *isplaying);"
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(NBExternalAddress channel, NBExternalAddress isPlayingHandle)).
I call the above with: isPlaying | isPlaying | isPlaying := NBExternalAddress new. self primStoreIsPlaying: channel in: isPlaying. ^ isPlaying value > 0.
isPlaying is always 0. The method works directly from C with: int isPlaying = 1; while (isPlaying) { FMOD_Channel_IsPlaying(channel, &isPlaying); }
I also tried changing the callout signature to "... bool* isPlayingHandle)" and passing "isPlaying := true." instead of using the NBExternalAddress stuff.
err.. again, you must pass an address where value will be stored,
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying( NBExternalAddress channel, NBExternalAddress * isPlayingHandle)). otherwise you passing NULL pointer, and i quite surprised it not segfaults when you call it like that (looks like they have a check in the library )
you can also use NBExternalTypeValue for that:
boolValueClass := NBExternalTypeValue ofType: 'bool'. "sure thing, creating anonymous class for each call is overkill, this should be done once, somewhere else"
boolValue := boolValueClass new.
self callTheThingWith: boolValue.
boolValue value ifTrue: [... blah]
(and this will work, assuming you have bool* in signature for this argument).
I have a few more questions, but this is the most pressing as it's holding up any further development.
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116.ht... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
On Nov 23, 2013, at 9:07 AM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
I really think that NativeBoost MUST HAVE a decent documentation. It is a central part of Pharo and Igor you should do something about it. If I would know I would have written a chapter on it but I cannot because I DO NOT KNOW.
And igor do not tell me that only C programmer should use NativeBoost. We should focus on our clients and our clients are smart Pharoers that can learn fast.
Stef
On 21 November 2013 22:40, Sean P. DeNigris <sean@clipperadams.com> wrote: I'm wrapping the FMOD cross-platform audio library. The code is MIT and lives at http://smalltalkhub.com/#!/~SeanDeNigris/FMOD
======== Problem #1: ========
I'm calling into the FMOD library with: primStoreIsPlaying: channelHandle in: isPlayingHandle <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_Channel_IsPlaying( FMOD_CHANNEL *channel, bool *isplaying);"
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(NBExternalAddress channel, NBExternalAddress isPlayingHandle)).
I call the above with: isPlaying | isPlaying | isPlaying := NBExternalAddress new. self primStoreIsPlaying: channel in: isPlaying. ^ isPlaying value > 0.
isPlaying is always 0. The method works directly from C with: int isPlaying = 1; while (isPlaying) { FMOD_Channel_IsPlaying(channel, &isPlaying); }
I also tried changing the callout signature to "... bool* isPlayingHandle)" and passing "isPlaying := true." instead of using the NBExternalAddress stuff.
err.. again, you must pass an address where value will be stored,
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying( NBExternalAddress channel, NBExternalAddress * isPlayingHandle)). otherwise you passing NULL pointer, and i quite surprised it not segfaults when you call it like that (looks like they have a check in the library )
you can also use NBExternalTypeValue for that:
boolValueClass := NBExternalTypeValue ofType: 'bool'. "sure thing, creating anonymous class for each call is overkill, this should be done once, somewhere else"
boolValue := boolValueClass new.
self callTheThingWith: boolValue.
boolValue value ifTrue: [... blah]
(and this will work, assuming you have bool* in signature for this argument).
I have a few more questions, but this is the most pressing as it's holding up any further development.
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116.ht... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
However we should acknowledge here that using a FFI, any FFI , in any programming language has the mandatory requirement of knowing C. I certainly do believe that documenting Nativeboost is extremely important for helping people to port C libraries to pharo and making Pharo far more useful but we should not kid ourselves. Coding with Nativeboost even though its inside Pharo , even though its smalltalk syntax, even though it has the tools to make your life easier, its still C coding or even Assembly coding if you are brave enough to use the inline assembler. I want to help with documentation the problem is that I dont know a lot of stuff about Nativeboost besides the basic pointer things I did with NBOpenGL. On Sat, Nov 23, 2013 at 10:10 AM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
On Nov 23, 2013, at 9:07 AM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
I really think that NativeBoost MUST HAVE a decent documentation. It is a central part of Pharo and Igor you should do something about it. If I would know I would have written a chapter on it but I cannot because I DO NOT KNOW.
And igor do not tell me that only C programmer should use NativeBoost. We should focus on our clients and our clients are smart Pharoers that can learn fast.
Stef
On 21 November 2013 22:40, Sean P. DeNigris <sean@clipperadams.com> wrote:
I'm wrapping the FMOD cross-platform audio library. The code is MIT and lives at http://smalltalkhub.com/#!/~SeanDeNigris/FMOD
======== Problem #1: ========
I'm calling into the FMOD library with: primStoreIsPlaying: channelHandle in: isPlayingHandle <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_Channel_IsPlaying( FMOD_CHANNEL *channel, bool *isplaying);"
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(NBExternalAddress channel, NBExternalAddress isPlayingHandle)).
I call the above with: isPlaying | isPlaying | isPlaying := NBExternalAddress new. self primStoreIsPlaying: channel in: isPlaying. ^ isPlaying value > 0.
isPlaying is always 0. The method works directly from C with: int isPlaying = 1; while (isPlaying) { FMOD_Channel_IsPlaying(channel, &isPlaying); }
I also tried changing the callout signature to "... bool* isPlayingHandle)" and passing "isPlaying := true." instead of using the NBExternalAddress stuff.
err.. again, you must pass an address where value will be stored,
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(
NBExternalAddress channel, NBExternalAddress * isPlayingHandle)).
otherwise you passing NULL pointer, and i quite surprised it not segfaults when you call it like that (looks like they have a check in the library )
you can also use NBExternalTypeValue for that:
boolValueClass := NBExternalTypeValue ofType: 'bool'. "sure thing, creating anonymous class for each call is overkill, this should be done once, somewhere else"
boolValue := boolValueClass new.
self callTheThingWith: boolValue.
boolValue value ifTrue: [... blah]
(and this will work, assuming you have bool* in signature for this argument).
I have a few more questions, but this is the most pressing as it's holding
up any further development.
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116.ht... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com<http://nabble.com/> .
-- Best regards, Igor Stasenko.
On 23 November 2013 09:07, Stéphane Ducasse <stephane.ducasse@inria.fr>wrote:
I really think that NativeBoost MUST HAVE a decent documentation.
i agree. i need to invest into it.
It is a central part of Pharo and Igor you should do something about it. If I would know I would have written a chapter on it but I cannot because I DO NOT KNOW.
Stef
On 21 November 2013 22:40, Sean P. DeNigris <sean@clipperadams.com> wrote:
I'm wrapping the FMOD cross-platform audio library. The code is MIT and lives at http://smalltalkhub.com/#!/~SeanDeNigris/FMOD
======== Problem #1: ========
I'm calling into the FMOD library with: primStoreIsPlaying: channelHandle in: isPlayingHandle <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_Channel_IsPlaying( FMOD_CHANNEL *channel, bool *isplaying);"
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(NBExternalAddress channel, NBExternalAddress isPlayingHandle)).
I call the above with: isPlaying | isPlaying | isPlaying := NBExternalAddress new. self primStoreIsPlaying: channel in: isPlaying. ^ isPlaying value > 0.
isPlaying is always 0. The method works directly from C with: int isPlaying = 1; while (isPlaying) { FMOD_Channel_IsPlaying(channel, &isPlaying); }
I also tried changing the callout signature to "... bool* isPlayingHandle)" and passing "isPlaying := true." instead of using the NBExternalAddress stuff.
err.. again, you must pass an address where value will be stored,
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(
NBExternalAddress channel, NBExternalAddress * isPlayingHandle)).
otherwise you passing NULL pointer, and i quite surprised it not segfaults when you call it like that (looks like they have a check in the library )
you can also use NBExternalTypeValue for that:
boolValueClass := NBExternalTypeValue ofType: 'bool'. "sure thing, creating anonymous class for each call is overkill, this should be done once, somewhere else"
boolValue := boolValueClass new.
self callTheThingWith: boolValue.
boolValue value ifTrue: [... blah]
(and this will work, assuming you have bool* in signature for this argument).
I have a few more questions, but this is the most pressing as it's holding
up any further development.
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116.ht... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
On 23 November 2013 09:07, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote: I really think that NativeBoost MUST HAVE a decent documentation.
i agree. i need to invest into it.
we should build a working group with pomodoro around it. JB and Damien could help. I can play the naive idiot and editor but I cannot be the driven force because the gap to learn will cost me too much energy. But this is on my todo to read the tutorial of laurent. Stef
It is a central part of Pharo and Igor you should do something about it. If I would know I would have written a chapter on it but I cannot because I DO NOT KNOW.
Stef
On 21 November 2013 22:40, Sean P. DeNigris <sean@clipperadams.com> wrote: I'm wrapping the FMOD cross-platform audio library. The code is MIT and lives at http://smalltalkhub.com/#!/~SeanDeNigris/FMOD
======== Problem #1: ========
I'm calling into the FMOD library with: primStoreIsPlaying: channelHandle in: isPlayingHandle <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_Channel_IsPlaying( FMOD_CHANNEL *channel, bool *isplaying);"
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying(NBExternalAddress channel, NBExternalAddress isPlayingHandle)).
I call the above with: isPlaying | isPlaying | isPlaying := NBExternalAddress new. self primStoreIsPlaying: channel in: isPlaying. ^ isPlaying value > 0.
isPlaying is always 0. The method works directly from C with: int isPlaying = 1; while (isPlaying) { FMOD_Channel_IsPlaying(channel, &isPlaying); }
I also tried changing the callout signature to "... bool* isPlayingHandle)" and passing "isPlaying := true." instead of using the NBExternalAddress stuff.
err.. again, you must pass an address where value will be stored,
^ self nbCall: #(FMOD_RESULT FMOD_Channel_IsPlaying( NBExternalAddress channel, NBExternalAddress * isPlayingHandle)). otherwise you passing NULL pointer, and i quite surprised it not segfaults when you call it like that (looks like they have a check in the library )
you can also use NBExternalTypeValue for that:
boolValueClass := NBExternalTypeValue ofType: 'bool'. "sure thing, creating anonymous class for each call is overkill, this should be done once, somewhere else"
boolValue := boolValueClass new.
self callTheThingWith: boolValue.
boolValue value ifTrue: [... blah]
(and this will work, assuming you have bool* in signature for this argument).
I have a few more questions, but this is the most pressing as it's holding up any further development.
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116.ht... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
Sean P. DeNigris wrote
I'm wrapping the FMOD cross-platform audio library [snip] I have a few more questions
======== Problem #1: ======== I have the following callout: <primitive: #primitiveNativeCall module: #NativeBoostPlugin> "FMOD_RESULT FMOD_System_Init( FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata);" ^ self nbCall: #(FMOD_RESULT System_Init(NBExternalAddress system, 32, 0, nil)). It works fine on Mac. On Windows, it returns some crazy error code that is not listed in the API. However, if I wrap the FMOD DLL in another DLL that just forwards all calls: FMOD_RESULT System_Init(FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata) { return FMOD_System_Init(system, maxchannels, flags, extradriverdata); } When I call out to the wrapper DLL, it works! Does that provide a clue as to what's going wrong when calling from NB? Other info: - Other dll functions succeed, so there is communication with the library. In fact, if I proceed past that first error, a sound starts to play... but then the VM crashes... ======== Problem #2: ======== (much less important) I wanted to be able to bundle the DLL with the image so one doesn't have to copy it into the VM folder. If I use the full path for the wrapper DLL described above, it is found, but when it calls fmodL.dll, which is in the same directory, it can't be found. I could only get it to work if at least fmodL.dll is in the VM plugins folder. Is there a way to specify more search locations for dynamic libraries from the image side? Thanks! ----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116p47... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
On 25 November 2013 21:53, Sean P. DeNigris <sean@clipperadams.com> wrote:
Sean P. DeNigris wrote
I'm wrapping the FMOD cross-platform audio library [snip] I have a few more questions
======== Problem #1: ========
I have the following callout: <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_System_Init( FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata);"
^ self nbCall: #(FMOD_RESULT System_Init(NBExternalAddress system, 32, 0, nil)).
It works fine on Mac. On Windows, it returns some crazy error code that is not listed in the API.
However, if I wrap the FMOD DLL in another DLL that just forwards all calls: FMOD_RESULT System_Init(FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata) { return FMOD_System_Init(system, maxchannels, flags, extradriverdata); } When I call out to the wrapper DLL, it works! Does that provide a clue as to what's going wrong when calling from NB?
This seems like a calling convention issue. By default, unless you specify, NB using cdecl calling convention, but on windows, many libs (especially kernel) using stdcall convention. Check how the library is built and which call convention it uses. Or just try changing it and see if it solves the problem.
Other info: - Other dll functions succeed, so there is communication with the library. In fact, if I proceed past that first error, a sound starts to play... but then the VM crashes...
======== Problem #2: ======== (much less important)
I wanted to be able to bundle the DLL with the image so one doesn't have to copy it into the VM folder. If I use the full path for the wrapper DLL described above, it is found, but when it calls fmodL.dll, which is in the same directory, it can't be found. I could only get it to work if at least fmodL.dll is in the VM plugins folder. Is there a way to specify more search locations for dynamic libraries from the image side?
No, you can do it yourself in a form of: self nbCall: ... module: (self searchAndLoadLibrary)
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116p47... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
-- Best regards, Igor Stasenko.
Hi Sean, 2013/11/25 Sean P. DeNigris <sean@clipperadams.com>
Sean P. DeNigris wrote
I'm wrapping the FMOD cross-platform audio library [snip] I have a few more questions
======== Problem #1: ========
I have the following callout: <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
"FMOD_RESULT FMOD_System_Init( FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata);"
^ self nbCall: #(FMOD_RESULT System_Init(NBExternalAddress system, 32, 0, nil)).
It works fine on Mac. On Windows, it returns some crazy error code that is not listed in the API.
However, if I wrap the FMOD DLL in another DLL that just forwards all calls: FMOD_RESULT System_Init(FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata) { return FMOD_System_Init(system, maxchannels, flags, extradriverdata); } When I call out to the wrapper DLL, it works! Does that provide a clue as to what's going wrong when calling from NB?
Other info: - Other dll functions succeed, so there is communication with the library. In fact, if I proceed past that first error, a sound starts to play... but then the VM crashes...
could it be a calling convention problem? cdecl, ...
======== Problem #2: ======== (much less important)
I wanted to be able to bundle the DLL with the image so one doesn't have to copy it into the VM folder. If I use the full path for the wrapper DLL described above, it is found, but when it calls fmodL.dll, which is in the same directory, it can't be found. I could only get it to work if at least fmodL.dll is in the VM plugins folder. Is there a way to specify more search locations for dynamic libraries from the image side?
I do not know if one can add more search locations. But, you can rebuild the full path from image side: Smalltalk imageDirectory / 'lib.dll' Cheers, Luc
Thanks!
----- Cheers, Sean -- View this message in context: http://forum.world.st/NativeBoost-Questions-while-wrapping-FMOD-tp4724116p47... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
participants (7)
-
Denis Kudriashov -
Igor Stasenko -
kilon alios -
Luc Fabresse -
phil@highoctane.be -
Sean P. DeNigris -
Stéphane Ducasse