如何更改 SoundPool
Posted
技术标签:
【中文标题】如何更改 SoundPool【英文标题】:How to change a SoundPool 【发布时间】:2019-06-28 06:09:51 【问题描述】:我正在开发一个听力训练应用程序,并希望让用户决定想要识别什么样的声音(不同的乐器、合成器声音等)
因此,作为“虚拟声音”,我有一个类似声纳的 ping,我将其加载到 SoundPool 中:
open class PingSoundPool(context: Context)
open var mAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_GAME)
.build()
open var mSoundPool = SoundPool.Builder()
.setMaxStreams(9)
.setAudioAttributes(mAttributes)
.build()
open var babping = mSoundPool.load(context, R.raw.ab830ping, 1)
open var aaping = mSoundPool.load(context, R.raw.a220ping, 1)
open var abbping = mSoundPool.load(context, R.raw.bb233ping, 1)
open var abping = mSoundPool.load(context, R.raw.b247ping, 1)
[and others]
open fun loadPings(note: Int)
println(note.toString())
if (note == 0)
if(note == 1)
mSoundPool.play(acping, 2.55f, 2.55f, 1, 0, 1f)
if(note == 2)
mSoundPool.play(adbping, 2.5f, 2.5f, 1, 0, 1f)
if(note == 3)
mSoundPool.play(adping, 2.45f, 2.45f, 1, 0, 1f)
if(note == 4)
mSoundPool.play(aebping, 2.4f, 2.4f, 1, 0, 1f)
[and so on]
现在我可以在我的活动中访问它:
companion object
lateinit var pingSoundPool: PingSoundPool
在 onCreate 中做pingSoundPool = PingSoundPool(this)
像这样,我可以用FullscreenActivity.pingSoundPool.loadPings(note: Int)
播放这些声音中的任何一个
现在问题来了,我想改变声音。第一步是创建一个首选项,给我一个带有所需声音的字符串(“ping”、“pong”、“flute”、“violin”等)。第二步是获取所述字符串并相应地加载 SoundPool。
现在如果我尝试把这个 -
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val pingsound = sharedPreferences.getString("pingsound", "")
if(pingsound == "ping")
open var babping = mSoundPool.load(context, R.raw.ab830ping, 1)
open var aaping = mSoundPool.load(context, R.raw.a220ping, 1)
open var abbping = mSoundPool.load(context, R.raw.bb233ping, 1)
open var abping = mSoundPool.load(context, R.raw.b247ping, 1)
[etc]
在我的 SoundPool 类中,我收到一条错误消息,“期待一个成员声明。”/“函数声明必须有一个名称。”
如果我只是复制整个班级的内容并像这样创建一个新班级
class PongSoundPool(context: Context): PingSoundPool(context)
override var mAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_GAME)
.build()
override var mSoundPool = SoundPool.Builder()
.setMaxStreams(9)
.setAudioAttributes(mAttributes)
.build()
open var babping = mSoundPool.load(context, R.raw.othersound1, 1)
open var aaping = mSoundPool.load(context, R.raw.othersound2, 1)
open var abbping = mSoundPool.load(context, R.raw.othersound3, 1)
open var abping = mSoundPool.load(context, R.raw.othersound4, 1)
并像这样在我的活动中分配pingSoundPool
的值
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
val pingsound = sharedPreferences.getString("pingsound", "")
when (pingsound)
"ping" -> pingSoundPool = PingSoundPool(this)
"pong" -> pingSoundPool = PongSoundPool(this)
然后,一旦我将首选项更改为“pong”,什么也没有发生。重新启动应用程序时出现运行时错误:
java.lang.RuntimeException: Unable to start activity ComponentInfocom.example/com.example.FullscreenActivity: java.lang.IllegalArgumentException: Invalid null AudioAttributes
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.IllegalArgumentException: Invalid null AudioAttributes
at android.media.SoundPool$Builder.setAudioAttributes(SoundPool.java:601)
at com.example.PingSoundPool.<init>(PingSoundPool.kt:16)
at com.example.PongSoundPool.<init>(PongSoundPool.kt:7)
at com.example.FullscreenActivity.onCreate(FullscreenActivity.kt:97)
at android.app.Activity.performCreate(Activity.java:6975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
它在 PingSoundPool 中指向的行是:.setAudioAttributes(mAttributes)
现在我不知道如何实现这一点。有人帮忙吗?
编辑:我仍在寻找解决方案。
我尝试过不加载新的 SoundPool,而是直接从 PongSoundPool 访问加载的声音,如下所示:override var babping = FullscreenActivity.pingSoundPool.mSoundPool.load(context, R.raw.othersound, 1)
当我这样做时,我不会崩溃,而且声音也不会加载。我在 logcat 中得到了sample X not READY
,即使是在几分钟之后。
【问题讨论】:
【参考方案1】:您的第一次崩溃是由于不正确的继承。如果您在PingSoundPool
中实现了var mAttributes
和var mSoundPool,请不要在PongSoundPool
上覆盖它。您也可以通过创建 not PingSoundPool
作为父类来改进您的架构。但是BaseSoundPool
具有最终属性mAttributes
和mSoundPool
以及抽象方法fun play(note: Int)
abstract class BaseSoundPool(val context: Context)
protected var loadedSoundChannels: IntArray? = null
private val attributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_GAME)
.build()
final val soundPool = SoundPool.Builder()
.setMaxStreams(9)
.setAudioAttributes(attributes)
.build()
fun load(rawSoundIds: IntArray)
loadedSoundChannels?.run unload(this) // todo implement unload fun by yourself
loadedSoundChannels = IntArray(rawSoundIds.size)
soundPool.load(context, rawSoundIds[it], 1)
abstract fun play(note: Int)
class PingSoundPool(context: Context) : BaseSoundPool(context)
override fun play(note: Int)
loadedSoundChannels?.getOrNull(note)?.let
soundPool.play(note, 1f, 1f, 1, 0, 1f);
还要记住SoundPool.load
是异步操作,所以你不能在加载后立即调用play。此外,在加载新的声音数据时,您应该卸载之前加载的数据。
也许你会发现我对SoundPool 的实现很有用,它在不同的 API 上更可预测。
【讨论】:
以上是关于如何更改 SoundPool的主要内容,如果未能解决你的问题,请参考以下文章