B4A Class Audio Visualizer

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.

B4X:
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

B4X:
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

B4X:
#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

  • Visualizer.zip
    8.1 KB · Views: 373
  • Visualizer-WaveForm.zip
    11.6 KB · Views: 390
Last edited:

stevel05

Expert
Licensed User
What device are you running it on? It needs Android 2.3+
 

Agnetha

Member
Licensed User
It's a Tablet "Endeavour 1000HD" with Android 4.1.1.
I've updatet to API-Level 21 - without success.
 

jeng

Member
Licensed User
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 ;-)
B4X:
    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

  • VrM.zip
    20.1 KB · Views: 116

Pavka

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

Zerberus

Member
Licensed User
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
B4X:
Dim test As Int
test=(Viz.getMeasurementPeakRms.mPeak)

What is my mistake?

Greetings

Zerberus
 

stevel05

Expert
Licensed User
Hi Zerberus,

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

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

or

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

If you are using an older version of B4a.
 

Zerberus

Member
Licensed User
Thanks,

I will try it.

EDIT: Hmmm...
I wrote
B4X:
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:

Zerberus

Member
Licensed User
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

  • test-peak.zip
    14 KB · Views: 156

stevel05

Expert
Licensed User
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.
 

Zerberus

Member
Licensed User
Hmmm...

It seems the peak-level is dependent on the VOLUME_MUSIC. Can i get an undependent peak-level?
 

moster67

Expert
Licensed User
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:

Douglas Farias

Expert
Licensed User
Hi @stevel05 .
i m tryed to use your example class, and i got this error.

B4X:
** 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:

stevel05

Expert
Licensed User
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.
 
Top