5

I am trying to play a synthesized sound (basically 2 sine waves and some noise) using the AudioTrack class. It doesn't seem to be any different than the SourceDataLine in javax.sound.sampled, BUT the synthesis is REALLY SLOW. Even for ARM standards, it's unrealistic to think that 32768 samples (16 bit, stereo, for a total of 65536) take over 1 second to render on a Nexus 4 (measured with System.nanotime(), write to AudioTrack excluded). The synthesis part is almost identical to this http://audioprograming.wordpress.com/2012/10/18/a-simple-synth-in-android-step-by-step-guide-using-the-java-sdk/, the only difference is that I play stereo sound (I can't reduce it to mono because it's a binaural tone).

Any ideas? what can I do?

Thanks in advance

dosse91214
  • 551
  • 1
  • 5
  • 17

4 Answers4

6

Marko's answer seems very good. But if you're still in the experimental/investigational phase of your project, you might want to consider using Pure Data, which already is implemented as a combination Android library/NDK library and which would allow you to synthesize many sounds and interact with them in a relatively simple manner.

The libpd distribution is the Android implementation of Pure Data. Some good starting references can be found at the SoundOnSound site and also at this site.

Addendum: I found a basic but functional implementation of an Android Midi Driver through this discussion link. The relevant code can be found here (github, project by billthefarmer, named mididriver).

You can view how I use it in my Android app (imSynt link leads you to Google Play), or on YouTube.

DigCamara
  • 5,352
  • 4
  • 33
  • 45
4

The performance of audio synthesis on ARM is actually very respectable with native code that makes good use of the NEON unit. The Dalvik's JIT compiler is never going to get close to this level of performance for floating-point intensive code.
A look at the enormous number of soft-synth apps for iOS provides ample evidence of what should be possible on ARM devices with similar levels of performance.

However, the performance you are reporting is several orders of magnitude short of what I would expect. You might consider the following:

  1. Double precision float-point arithmetic is particularly expensive on ARM Cortex A-x NEON units, where as single precision is very fast and highly parallelizable. Math.sin() returns a double, so is unnecessarily precise, and liable to be slow. The 24-mantissa provided by single precision floating point value is substantially larger than the 16-bit int used by the audio subsystem.
  2. You could precompute sin(x) and then perform a table-lookup in your render loop.
  3. There is a previous post on SO concerning Math.sin(x) on android suggesting degrading performance as x becomes large, as it's likely to in this case over time.
  4. For a more advanced table-based synthesiser, you might consider using a DDS Oscillator.

Ultimately, you might consider using native code for synthesis, with the NDK.

marko
  • 8,640
  • 4
  • 28
  • 43
  • thanks for the suggestions: i'm already using a LUT for the sin function and i am aware of the Math.sin performance issue for large numbers. i have just tried replacing double with float where possible but it's still way too slow. i have made a comparison with the same code running on my pc and i can't see a reason why it is 150 times slower (measured) on my phone. i can understand maybe 10 time slower but 150 is absurd. a pentium 1 would be faster. – dosse91214 Apr 29 '13 at 16:26
  • To put it in perspective, I got 32 voices out of a fairly heavy-weight sample subtractive synth engine running solidly on one of the two cores of a 1GHz TI OMAP4430. The code was C++, the only optimisations being hints to the compiler to parallelize some code paths - which it did very effectively. – marko Apr 29 '13 at 20:55
1

You should be able render multiple oscillators with filters and envelopes and still have CPU time left over. Check your inner loops to make sure that there are no system calls.

Are you on a very old phone? You did not mention the hardware or OS version.

You might want to try using JSyn. It is a free modular Java synthesizer that runs on any Java platform including desktops, Raspberry Pi and Android.

https://github.com/philburk/jsyn

philburk
  • 653
  • 4
  • 13
  • Thank you for pointing yo jsyn. I was wondering if there was something similar to tone.js for android / desktop or javascript createOscillator() for android. and i've found a java library <3 – ValdaXD Sep 05 '20 at 15:11
0

Have you tried profiling your code? It sounds like something else is possibly causing your slow down, profiling would help to highlight the cause.

Mike

Mike Jones
  • 101
  • 2