B4A Class Audio Visualizer

This demo does not implement the RuntimePermissions required for Android 6+ (that's how old it is). You will need to add RuntimePermissions to the demo in order for it to run.

As a response to a request on the forums, and to try out the new JavaObject functionality, I decided to take a diversion and write a wrapper for the http://developer.android.com/reference/android/media/audiofx/Visualizer.html.

It's written as a B4a class using JavaObject, and provides the DataCaptureListener and callbacks for wave and fft data.

Just add an audio file, and some processing code.

The Class depends on JavaObject and the Demo App depends on Reflection and JavaObject.

You need to add permission: RECORD_AUDIO to the Manifest.

Code:
AddPermission("android.permission.RECORD_AUDIO")

If you want to apply the visualizer to the main outputs (AudioSession = 0) you also need permission: MODIFY_AUDIO_SETTINGS

Code:
AddPermission("android.permission.MODIFY_AUDIO_SETTINGS")

Requires B4A 3.80+

The Class depends on JavaObject and the Demo App depends on Reflection and JavaObject.

Enjoy

Update: Added a new version with WavForm drawing to a user provided panel. While I have tested it on various configurations, it needs to be tested further before production use. Please let me know if you come across any issues.

This version has additional dependencies:

SLByteArrayBuffer and Threading Libraries.

Edit: I forgot to mention that as the Wav drawing is done in a separate thread, it won't run in Debug mode. You can disable it by temporarily removing the TH.Start call to the draw routine, better still use conditional compilation.

If you want to debug the rest of the app, add

Code:
#ExcludeFromDebugger: True

to the top of the WavDraw class, then you can run the app in debug mode, but you can't debug the class. In legacy debug mode the wav will be drawn, in Rapid debug mode it won't, but the app will still run.

As an aside, I know nothing about using fft, if someone would care to provide an example using that, it would be most appreciated.

Edit: 20/1/16 Uploaded new Vizualizer.bas Class which fixes the bug from post #29
26/3/18 Update to fix the bug in post #29
 

Attachments

Last edited:
It's a Tablet "Endeavour 1000HD" with Android 4.1.1.
I've updatet to API-Level 21 - without success.
 
Hello,

I get a strange error, IndexOutOfBoundsException: index 7 if i try to playback my recording.
Can some one help me out with this? or push me to the right direction ;-)
Code:
    at java.util.concurrent.atomic.AtomicIntegerArray.checkedByteOffset(AtomicIntegerArray.java:35)
    at java.util.concurrent.atomic.AtomicIntegerArray.get(AtomicIntegerArray.java:82)
    at anywheresoftware.b4a.debug.Debug.ShouldStop(Debug.java:230)
    at VrM.Jeng.main._mp_complete(main.java:1278)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:159)
    at anywheresoftware.b4a.objects.MediaPlayerWrapper$1.onCompletion(MediaPlayerWrapper.java:52)
    at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:2437)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at anywheresoftware.b4a.Msgbox.waitForMessage(Msgbox.java:198)
    at anywheresoftware.b4a.Msgbox.debugWait(Msgbox.java:157)
    at anywheresoftware.b4a.debug.Debug.wait(Debug.java:213)
    at anywheresoftware.b4a.debug.Debug.reachBP(Debug.java:260)
    at anywheresoftware.b4a.debug.Debug.ErrorCaught(Debug.java:145)
    at VrM.Jeng.main._button_click(main.java:569)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:163)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:159)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:77)
    at android.view.View.performClick(View.java:4475)
    at android.view.View$PerformClick.run(View.java:18786)
    at android.os.Handler.handleCallback(Handler.java:730)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
    at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
    at dalvik.system.NativeStart.main(Native Method)
java.lang.IndexOutOfBoundsException: index 7
Here my test project:
 

Attachments

Hi, is it possible to use visualizer module in live wallpapers? When I tried I had en error.
 
Hello stevel05,

I want to use your Audio Visualizer to build a little lighting console for my little mp3-player-app.

My question: How can i log the peak with the getMeasurementPeakRms-method? I try "log(Viz.getMeasurementPeakRms.mPeak)" after "MP.Play", but i get error "MeasurementPeakRms cannot be cast to java.lang.Object[]". Also when i try
Code:
Dim test As Int
test=(Viz.getMeasurementPeakRms.mPeak)

What is my mistake?

Greetings

Zerberus
 
Hi Zerberus,

You've found a Bug, Change Line 73 in the Vizualizer class to:

Code:
Viz.RunMethod("getMeasurementPeakRms",Array(PRMS))

or

Code:
Viz.RunMethod("getMeasurementPeakRms",Array As Object(PRMS))

If you are using an older version of B4a.
 
Thanks,

I will try it.

EDIT: Hmmm...
I wrote
Code:
Dim Timer As Timer
...
Timer.Initialize("Timer", 100)
Timer.Enabled=True
...
Sub Timer_Tick
Log(Viz.getMeasurementPeakRms.mPeak)
End Sub
but the Log shows always "0". I want to use the peak-level of the played song to recognize the "beat" (for some visual effects).
 
Last edited:
Now I have a little "peakmeter" (in attachment).

Is it possible to receive a range of frequencies (like "bass", "middle", "high") and combine this with the actual peak (the bass-drum hits the beat...)?

Greetings

Zerberus
 

Attachments

I think for that you would need to analyse the FFT data, I'm afraid I don't have a working knowledge of doing this.
 
Hmmm...

It seems the peak-level is dependent on the VOLUME_MUSIC. Can i get an undependent peak-level?
 
Nice class/project @stevel05. Thank you!

I had a play with it and it worked nicely on all my devices I tried it with.

Decided to try it with some of the other mediaplayers available and see if I could get it working with audio-sources not supported by the standard MediaPlayer. With Vitamio5 and FFmpeg_b4a it works fine although not on all devices (there is apparently a workaround for that so I am going to check it out). Unfortunately it won't work at all with vlcb4a.

Using the demo-project provided by @stevel05, the important thing is to set the AudioSession to 0 (zero) and of course use your mediaplayer as an instance instead of the standard MediaPlayer. Some other minor changes are also needed such as method names to start playing, stopping etc but they are rather obvious.
 
Last edited:
Hi @stevel05 .
i m tryed to use your example class, and i got this error.

Code:
** Activity (main) Create, isFirst = true **
AS 12313
Error occurred on line: 12 (Vizualizer)
java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Constructor.newInstance0(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
    at anywheresoftware.b4j.object.JavaObject.InitializeNewInstance(JavaObject.java:90)
    at exemplo.batida.vizualizer._initialize(vizualizer.java:63)
    at exemplo.batida.main._activity_create(main.java:407)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at exemplo.batida.main.afterFirstLayout(main.java:104)
    at exemplo.batida.main.access$000(main.java:17)
    at exemplo.batida.main$WaitForLayout.run(main.java:82)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:201)
    at android.app.ActivityThread.main(ActivityThread.java:6810)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Caused by: java.lang.RuntimeException: Cannot initialize Visualizer engine, error: -3
    at android.media.audiofx.Visualizer.<init>(Visualizer.java:218)
    ... 21 more
** Activity (main) Resume **

its your example, without changes.

B4A 9.30 (XIAOMI with Android 9), java 11 (compiled with sdk 26)
I have the same error in debug AND release.

what can cause this? and its possible fix?

thank you.
 
Last edited:
Hi Douglas, sorry I won't be able to look at it for a couple of days, maybe someone already knows the answer, if not I'll take a look when I can.
 
Hi Douglas, sorry I won't be able to look at it for a couple of days, maybe someone already knows the answer, if not I'll take a look when I can.
i found this, only use runtime permissions and it is fixed. thank you for the lib.
 
Back
Top