我试图使用AudioTrack类播放合成声音(基本上是2个正弦波和一些噪音)。它似乎与javax.sound中的SourceDataLine没有任何不同。采样,但合成是真的很慢。即使对于ARM标准,认为32768个样本(16位,立体声,总共65536个)在Nexus 4上渲染超过1秒也是不现实的(用System.nanotime()测量,不包括写入AudioTrack)。合成部分几乎与此http://audioprograming.wordpress.com/2012/10/18/a-simple-synth-in-android-step-by-step-guide-using-the-java-sdk/相同,唯一的区别是我播放立体声(我不能将其减少到单声道,因为它是双耳音)。
任何想法?我能做什么?
Thanks in advance
Marko的回答似乎很好。但如果你的项目仍处于实验/调查阶段,你可能会考虑使用Pure Data,它已经作为Android库/NDK库的组合实现,它允许你合成许多声音,并以相对简单的方式与它们进行交互。
libpd发行版是Pure Data的Android实现。一些好的入门参考可以在SoundOnSound网站和这个网站上找到。
附录:我通过这个讨论链接找到了一个Android Midi驱动程序的基本但功能的实现。相关代码可以在这里找到(github,项目由billthefarmer,命名为 middidriver )。
你可以在我的Android应用程序(imSynt链接引导你到Google Play)或YouTube上查看我是如何使用它的。
ARM上的音频合成性能实际上非常值得尊敬,本机代码充分利用了NEON单元。对于浮点密集型代码,Dalvik的JIT编译器永远无法达到这种性能水平。
只要看看iOS平台上大量的软合成应用,就能充分证明在ARM设备上也能实现类似的性能水平。
但是,您报告的性能比我期望的要低几个数量级。您可以考虑以下内容:
- 双精度浮点运算在ARM Cortex A-x NEON单元上特别昂贵,而单精度运算非常快且高度并行化。
Math.sin()
返回一个double
,因此没有必要精确,而且可能很慢。单精度浮点值提供的24尾数比音频子系统使用的16位整型大得多。 - 你可以预先计算
sin(x)
,然后在渲染循环中执行表查找。 - 之前有一篇关于android上
Math.sin(x)
的SO帖子,建议随着x
变大而降低性能,因为随着时间的推移,这种情况很可能发生。 - 对于更高级的基于表格的合成器,您可以考虑使用DDS振荡器。
最终,您可以考虑使用本地代码进行合成,并使用NDK。
您应该能够呈现多个振荡器与过滤器和信封,仍然有CPU时间剩余。检查你的内部循环,确保没有系统调用。
你用的是很旧的手机吗?您没有提到硬件或操作系统版本。
你可能想尝试使用JSyn。它是一个免费的模块化Java合成器,可以在任何Java平台上运行,包括桌面、树莓派和Android。
https://github.com/philburk/jsyn你试过分析你的代码吗?听起来可能是其他原因导致了您的运行速度变慢,分析将有助于突出原因。
迈克