Java Question BA.raiseEvent and bass library

wbtcpip

Member
Licensed User
Longtime User
Hello,
having this java code:
B4X:
/ Record callback
    @Events(values={"RecordProc(int handle, ByteBuffer buffer, int length, Object user)"})
    @ShortName("BASS_RecordProc")
    public static class RecordProcedure {
        private BA ba;
        private String eventName;
        private boolean ret;
        public void Initialize(BA ba, String EventName) {
             this.ba = ba;
             this.eventName = EventName.toLowerCase(BA.cul);
        }
        public BASS.RECORDPROC recordproc = new BASS.RECORDPROC() {    
                 public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
                         ba.raiseEvent(null, eventName + "_recordproc", handle, buffer, length, user);            
                }
       };
    }

i get error: missing return statement

i don't know how to return the value from the sub

Java:
B4X:
public interface RECORDPROC
   {
     boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user);
 
     /*RETURN : true = continue recording, false = stop */
   }

B4A:
B4X:
Sub myrec_recordproc(handle As Int, buffer() As Byte, length As Int, User As Object) As Boolean

How i get the return value of the sub?
 
Last edited:

wbtcpip

Member
Licensed User
Longtime User
a second question, the same code cause the following exception:

B4X:
java.lang.IllegalArgumentException: argument 2 should have type byte[], got java.nio.ReadWriteDirectByteBuffer

my sub is
B4X:
Sub myrec_recordproc(handle As Int, buffer() As Byte, length As Int, User As Object) As Boolean

how to pass the type java.nio.ByteBuffer to b4a?
Is buffer() as Byte correct?
 

wbtcpip

Member
Licensed User
Longtime User
No.

bb.array() will return the base array (if there is one).

I changed like this:

B4X:
// Record callback
  @Events(values={"RecordProc(int handle, ByteBuffer buffer, int length, Object user)"})
   @ShortName("BASS_RecordProc")
   public static class RecordProcedure {
     public boolean IsRec = true;
     private BA ba;
     private String eventName;
     public void Initialize(BA ba, String EventName) {
         this.ba = ba;
       this.eventName = EventName.toLowerCase(BA.cul);
     }
     public BASS.RECORDPROC recordproc = new BASS.RECORDPROC() {   
  public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
  ba.raiseEvent(null, eventName + "_recproc", handle, buffer.array(), length, user);   
  return IsRec;   
  }
  };
  }

but now ba do not raise the event anymore
 

wbtcpip

Member
Licensed User
Longtime User
It seems i solved converting ByteBuffer to Byte Array like this:

B4X:
public BASS.RECORDPROC recordproc = new BASS.RECORDPROC() {  
  public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
       byte[] b = new byte[length];
                   buffer.get(b);
                   ba.raiseEvent(null, eventName + "_recproc", handle, b, length, user);  
       return IsRec;  
  }
  };

One more question please:

my sub has a boolean return value

B4X:
Sub myrec_recordproc(handle As Int, buffer() As Byte, length As Int, User As Object) As Boolean

In Java ba.raiseEvent return an object ... how i can return the boolean value from sub to java?

B4X:
ba.raiseEvent(null, eventName + "_recproc", handle, buffer.array(), length, user);
return ??? <--------------- how i return the boolean from my B4A sub?
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
you are raising an event. Add a parameter in the event to give a boolean too
 

wbtcpip

Member
Licensed User
Longtime User
you are raising an event. Add a parameter in the event to give a boolean too

ok

Java:
B4X:
ba.raiseEvent(null, eventName + "_recproc", handle, b, length, user, IsRec);
ba.Log(IsRec);   <------------------- it's still false ...me i set True in the B4A Sub

B4A:
B4X:
Sub myrec_recproc(handle As Int, mybuffer() As Byte, length As Int, User As Object, IsRec As Boolean)
  IsRec = True  <------------------- i set True my boolean
End Sub

dont' work .... so ....

How to pass a sub return value from B4A -> to java?
 

DonManfred

Expert
Licensed User
Longtime User
I´ve difficulties to understand the problem without knowing what exactly you want archieve. And especially without knowing the libs code you want to wrap it ishard for me to answer.

What is the lib you want to wrap? github-url, upload the lib, whatever ;)
 

wbtcpip

Member
Licensed User
Longtime User
I´ve difficulties to understand the problem without knowing what exactly you want archieve. And especially without knowing the libs code you want to wrap it ishard for me to answer.

What is the lib you want to wrap? github-url, upload the lib, whatever ;)

again thank you for the help.

I will give you all the details about the library at the bottom of this message but my question is not related to a specific library, it is a generale question about the ba.raisevent and a sub of Basic4Android.

Imagine to have a sub in Basic4Android like this:

B4X:
sub myadd_myproc(a as int, b as int) as Int
       return a+b
end sub

and now imagine that a java library wants to use that sub passing 2 values and getting a result:

B4X:
a=4;
b=6;
ba.raiseEvent(null, eventName + "_myproc", a, b);

In java code how i get the result 10?

I'm wrapping this library: http://www.un4seen.com/forum/?topic=13225.0 anyway as you can see my question is not related to the library.
 

DonManfred

Expert
Licensed User
Longtime User
This is how i would write it i guess.

B4X:
package de.donmanfred;

import java.nio.ByteBuffer;
import com.un4seen.bass.BASS;
import com.un4seen.bass.BASS.RECORDPROC;
import anywheresoftware.b4a.AbsObjectWrapper;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.Author;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;

@Version(1.00f)
@ShortName("BASS")
@Author(value = "DonManfred (wrapper)")
//@Permissions(values={"android.permission.INTERNET", "android.permission.ACCESS_NETWORK_STATE"})
@Events(values={"recordproc(handle As int, buffer As byte(), lengh As int, user As Object)"})

public class BASSWrapper extends AbsObjectWrapper<BASS> {
    private BA ba;
    private String eventName;

    public void Initialize(final BA ba, String EventName) {
        this.eventName = EventName.toLowerCase(BA.cul);
        this.ba = ba;

        final BASS _obj = new BASS();
        final String eventName = EventName.toLowerCase(BA.cul);
        setObject(_obj);
    }

    public void RecordStart(int freq, int chans, int flags, Object user){
        getObject();
        BASS.BASS_RecordStart(freq, chans, flags, new RECORDPROC(){

            @Override
            public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
                // TODO Auto-generated method stub
                if (ba.subExists(eventName + "_recordproc")) {
                    BA.Log("lib:Raising.. "+eventName + "_recordproc()");                               
                  //app.raiseEvent(app.context, eventName+"_pagerendered", i, pageCount, filename+"-" + i + ".png");
                  return (boolean) ba.raiseEventFromDifferentThread(this, null, 0, eventName + "_recordproc", true, new Object[] {handle, buffer.array(), length, user});
              }else {
                  BA.Log("lib: NOTFOUND '"+eventName + "_recordproc");
              }
                return false;
            }
        }, user);
    }
       
}

Please note that i onlywrapped one of the methodsof the native .so

Only one of these

public static native boolean BASS_SetConfig(int option, int value);
public static native int BASS_GetConfig(int option);
public static native boolean BASS_SetConfigPtr(int option, Object value);
public static native Object BASS_GetConfigPtr(int option);
public static native int BASS_GetVersion();
public static native int BASS_ErrorGetCode();
public static native boolean BASS_GetDeviceInfo(int device, BASS_DEVICEINFO info);
public static native boolean BASS_Init(int device, int freq, int flags);
public static native boolean BASS_SetDevice(int device);
public static native int BASS_GetDevice();
public static native boolean BASS_Free();
public static native boolean BASS_GetInfo(BASS_INFO info);
public static native boolean BASS_Update(int length);
public static native float BASS_GetCPU();
public static native boolean BASS_Start();
public static native boolean BASS_Stop();
public static native boolean BASS_Pause();
public static native boolean BASS_SetVolume(float volume);
public static native float BASS_GetVolume();

public static native int BASS_PluginLoad(String file, int flags);
public static native boolean BASS_PluginFree(int handle);
public static native BASS_PLUGININFO BASS_PluginGetInfo(int handle);

public static native boolean BASS_Set3DFactors(float distf, float rollf, float doppf);
public static native boolean BASS_Get3DFactors(Float distf, Float rollf, Float doppf);
public static native boolean BASS_Set3DPosition(BASS_3DVECTOR pos, BASS_3DVECTOR vel, BASS_3DVECTOR front, BASS_3DVECTOR top);
public static native boolean BASS_Get3DPosition(BASS_3DVECTOR pos, BASS_3DVECTOR vel, BASS_3DVECTOR front, BASS_3DVECTOR top);
public static native void BASS_Apply3D();

public static native int BASS_SampleLoad(String file, long offset, int length, int max, int flags);
public static native int BASS_SampleLoad(ByteBuffer file, long offset, int length, int max, int flags);
public static native int BASS_SampleLoad(Asset file, long offset, int length, int max, int flags);
public static native int BASS_SampleCreate(int length, int freq, int chans, int max, int flags);
public static native boolean BASS_SampleFree(int handle);
public static native boolean BASS_SampleSetData(int handle, ByteBuffer buffer);
public static native boolean BASS_SampleGetData(int handle, ByteBuffer buffer);
public static native boolean BASS_SampleGetInfo(int handle, BASS_SAMPLE info);
public static native boolean BASS_SampleSetInfo(int handle, BASS_SAMPLE info);
public static native int BASS_SampleGetChannel(int handle, boolean onlynew);
public static native int BASS_SampleGetChannels(int handle, int[] channels);
public static native boolean BASS_SampleStop(int handle);

public static native int BASS_MusicLoad(String file, long offset, int length, int flags, int freq);
public static native int BASS_MusicLoad(ByteBuffer file, long offset, int length, int flags, int freq);
public static native int BASS_MusicLoad(Asset asset, long offset, int length, int flags, int freq);
public static native boolean BASS_MusicFree(int handle);

public static native int BASS_StreamCreate(int freq, int chans, int flags, STREAMPROC proc, Object user);
public static native int BASS_StreamCreate(int freq, int chans, int flags, int proc, Object user);
public static native int BASS_StreamCreateFile(String file, long offset, long length, int flags);
public static native int BASS_StreamCreateFile(ByteBuffer file, long offset, long length, int flags);
public static native int BASS_StreamCreateFile(Asset asset, long offset, long length, int flags);
public static native int BASS_StreamCreateURL(String url, int offset, int flags, DOWNLOADPROC proc, Object user);
public static native int BASS_StreamCreateFileUser(int system, int flags, BASS_FILEPROCS procs, Object user);
public static native boolean BASS_StreamFree(int handle);
public static native long BASS_StreamGetFilePosition(int handle, int mode);
public static native int BASS_StreamPutData(int handle, ByteBuffer buffer, int length);
public static native int BASS_StreamPutFileData(int handle, ByteBuffer buffer, int length);

public static native boolean BASS_RecordGetDeviceInfo(int device, BASS_DEVICEINFO info);
public static native boolean BASS_RecordInit(int device);
public static native boolean BASS_RecordSetDevice(int device);
public static native int BASS_RecordGetDevice();
public static native boolean BASS_RecordFree();
public static native boolean BASS_RecordGetInfo(BASS_RECORDINFO info);
public static native String BASS_RecordGetInputName(int input);
public static native boolean BASS_RecordSetInput(int input, int flags, float volume);
public static native int BASS_RecordGetInput(int input, Float volume);
public static native int BASS_RecordStart(int freq, int chans, int flags, RECORDPROC proc, Object user);
public static native double BASS_ChannelBytes2Seconds(int handle, long pos);
public static native long BASS_ChannelSeconds2Bytes(int handle, double pos);
public static native int BASS_ChannelGetDevice(int handle);
public static native boolean BASS_ChannelSetDevice(int handle, int device);
public static native int BASS_ChannelIsActive(int handle);
public static native boolean BASS_ChannelGetInfo(int handle, BASS_CHANNELINFO info);
public static native Object BASS_ChannelGetTags(int handle, int tags);
public static native long BASS_ChannelFlags(int handle, int flags, int mask);
public static native boolean BASS_ChannelUpdate(int handle, int length);
public static native boolean BASS_ChannelLock(int handle, boolean lock);
public static native boolean BASS_ChannelPlay(int handle, boolean restart);
public static native boolean BASS_ChannelStop(int handle);
public static native boolean BASS_ChannelPause(int handle);
public static native boolean BASS_ChannelSetAttribute(int handle, int attrib, float value);
public static native boolean BASS_ChannelGetAttribute(int handle, int attrib, Float value);
public static native boolean BASS_ChannelSlideAttribute(int handle, int attrib, float value, int time);
public static native boolean BASS_ChannelIsSliding(int handle, int attrib);
public static native boolean BASS_ChannelSetAttributeEx(int handle, int attrib, ByteBuffer value, int size);
public static native int BASS_ChannelGetAttributeEx(int handle, int attrib, ByteBuffer value, int size);
public static native boolean BASS_ChannelSet3DAttributes(int handle, int mode, float min, float max, int iangle, int oangle, float outvol);
public static native boolean BASS_ChannelGet3DAttributes(int handle, Integer mode, Float min, Float max, Integer iangle, Integer oangle, Float outvol);
public static native boolean BASS_ChannelSet3DPosition(int handle, BASS_3DVECTOR pos, BASS_3DVECTOR orient, BASS_3DVECTOR vel);
public static native boolean BASS_ChannelGet3DPosition(int handle, BASS_3DVECTOR pos, BASS_3DVECTOR orient, BASS_3DVECTOR vel);
public static native long BASS_ChannelGetLength(int handle, int mode);
public static native boolean BASS_ChannelSetPosition(int handle, long pos, int mode);
public static native long BASS_ChannelGetPosition(int handle, int mode);
public static native int BASS_ChannelGetLevel(int handle);
public static native boolean BASS_ChannelGetLevelEx(int handle, float[] levels, float length, int flags);
public static native int BASS_ChannelGetData(int handle, ByteBuffer buffer, int length);
public static native int BASS_ChannelSetSync(int handle, int type, long param, SYNCPROC proc, Object user);
public static native boolean BASS_ChannelRemoveSync(int handle, int sync);
public static native int BASS_ChannelSetDSP(int handle, DSPPROC proc, Object user, int priority);
public static native boolean BASS_ChannelRemoveDSP(int handle, int dsp);
public static native boolean BASS_ChannelSetLink(int handle, int chan);
public static native boolean BASS_ChannelRemoveLink(int handle, int chan);
public static native int BASS_ChannelSetFX(int handle, int type, int priority);
public static native boolean BASS_ChannelRemoveFX(int handle, int fx);

public static native boolean BASS_FXSetParameters(int handle, Object params);
public static native boolean BASS_FXGetParameters(int handle, Object params);
public static native boolean BASS_FXReset(int handle);
public static native boolean BASS_FXSetPriority(int handle, int priority);

In this case it was
public static native int BASS_RecordStart(int freq, int chans, int flags, RECORDPROC proc, Object user);
to demonstrate on how to implement the callbacks.

But honestly i´m not sure if that
B4X:
  return (boolean) ba.raiseEventFromDifferentThread(this, null, 0, eventName + "_recordproc", true, new Object[] {handle, buffer.array(), length, user});
works as epected.
 

wbtcpip

Member
Licensed User
Longtime User
Thank you very much for the sample wrapper. Indeed it's very useful for me to learn how to wrap this BASS library. The only difficult part are the callback.

Unfortunately also in your code ba.raiseEventFromDifferentThread do not return the value of the B4A sub.

It seems the BA.raise family of commands only raise the event but they don't wait for the sub to be executed on B4A side, so they don't get the return value.

They work async, so only Void sub can be used ... in BASS there are some callback that need a return value form the sub ... i don't know how to do
 

DonManfred

Expert
Licensed User
Longtime User
he only difficult part are the callback.
Unfortunately also in your code ba.raiseEventFromDifferentThread do not return the value of the B4A sub.

ba.raiseEvent is not asynchronous and you can use it to return a value from B4A code. However you cannot use it if the event is raised from a different thread.

Based on @Erel answer this should work giving a result back from b4a to the libs event method

B4X:
    public void RecordStart(int freq, int chans, int flags, Object user){
        getObject();
        BASS.BASS_RecordStart(freq, chans, flags, new RECORDPROC(){

            @Override
            public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
                // TODO Auto-generated method stub
                if (ba.subExists(eventName + "_recordproc")) {
                    BA.Log("lib:Raising.. "+eventName + "_recordproc()");                               
                  //app.raiseEvent(app.context, eventName+"_pagerendered", i, pageCount, filename+"-" + i + ".png");
                  return (boolean) ba.raiseEvent(this, eventName + "_recordproc", handle, buffer.array(), length, user);
              }else {
                  BA.Log("lib: NOTFOUND '"+eventName + "_recordproc");
              }
                return false;
            }
        }, user);
    }
 

wbtcpip

Member
Licensed User
Longtime User
Hi Manfred, you was so kind wrapping one function of the bass library. Can i ask you a last help? I need to wrap this part of the library:

Java:
B4X:
public static native int BASS_StreamCreateFileUser(int system, int flags, BASS_FILEPROCS procs, Object user);

public interface BASS_FILEPROCS
   {
     // User file stream callback functions
     void FILECLOSEPROC(Object user);
     long FILELENPROC(Object user);
     int FILEREADPROC(ByteBuffer buffer, int length, Object user);
     boolean FILESEEKPROC(long offset, Object user);
   }

In Basic4Android i will have 4 callback:

B4X:
sub fileclose_myfileuserproc(user as Object)

sub filelen_myfileuserproc(user as Object) as long

sub fileread_myfileuserproc(buffer() as byte, length as int, user as object) as Int

sub fileseek_myfileuserproc(offset as long, user as object) as Boolean

Do i have to create 4 different callbacks like your exemple?

and how i pass the 4 callbacks to the function?
 

wbtcpip

Member
Licensed User
Longtime User
Note that it is safer to write it this way:
B4X:
Boolean res = ba.raiseEvent(...); //Boolean instead of boolean
return res != null && res == true;
ba.raiseEvent can return null in some cases (for example if the activity is paused).

Hi Erel,
your code return this error:

incompatible types: Object cannot be converted to Boolean
Boolean res = ba.raiseEvent(this, eventName + "_recordproc", handle, buffer.array(), length, user);
 
Top