Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-25 Thread Igor Stasenko
On 25 November 2013 21:53, Sean P. DeNigris s...@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-tp4724116p4725188.html
 Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




-- 
Best regards,
Igor Stasenko.


Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-25 Thread Luc Fabresse
Hi Sean,

2013/11/25 Sean P. DeNigris s...@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-tp4724116p4725188.html
 Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-23 Thread Stéphane Ducasse
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 s...@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.html
 Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
 
 
 
 
 -- 
 Best regards,
 Igor Stasenko.



Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-23 Thread Denis Kudriashov
Hi

2013/11/22 Igor Stasenko siguc...@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)


Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-23 Thread Igor Stasenko
On 23 November 2013 09:07, Stéphane Ducasse stephane.duca...@inria.frwrote:

 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 s...@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.html
 Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




 --
 Best regards,
 Igor Stasenko.





-- 
Best regards,
Igor Stasenko.


Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-22 Thread Igor Stasenko
On 22 November 2013 05:09, Sean P. DeNigris s...@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 classnew
  | 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-installer.exe
 - Mac -

 http://www.fmod.org/download/fmodstudio/api/Mac/fmodstudioapi10208mac-installer.dmg

 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-tp4724116p4724192.html
 Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




-- 
Best regards,
Igor Stasenko.


Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-21 Thread p...@highoctane.be
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:p...@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 s...@clipperadams.comwrote:

 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.html
 Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.





Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-21 Thread Igor Stasenko
On 21 November 2013 22:40, Sean P. DeNigris s...@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.html
 Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




-- 
Best regards,
Igor Stasenko.


Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-21 Thread Igor Stasenko
On 22 November 2013 01:23, Sean P. DeNigris s...@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-tp4724116p4724158.html
 Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




-- 
Best regards,
Igor Stasenko.


Re: [Pharo-users] NativeBoost Questions while wrapping FMOD

2013-11-21 Thread Sean P. DeNigris
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-tp4724116p4724158.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.