英文:
How to play an MP3 file stored in resources folder in Kotlin Multiplatform with Jetpack Compose for Desktop?
问题
我正在尝试在我的Compose for Desktop项目中按下按钮时播放声音。我的MP3文件存储在资源文件夹中(./src/jvmMain/resources/beep.mp3)。
我一直在尝试使用useResource
函数,如下所示(在@Composable Button的onClick
参数内部):
scope.launch {
useResource("beep.mp3") {
val clip = AudioSystem.getClip()
val audioInputStream = AudioSystem.getAudioInputStream(it)
clip.open(audioInputStream)
clip.start()
}
}
但我遇到了一个错误:Exception in thread "AWT-EventQueue-0" java.io.IOException: mark/reset not supported。如果我不使用scope
,我也会得到相同的错误,我在我的可组合顶层定义如下:
val scope = rememberCoroutineScope()
任何帮助将不胜感激!
英文:
I'm trying to play a sound in my Compose for Desktop project when pressing a button. My MP3 file is stored in the resources folder (./src/jvmMain/resources/beep.mp3).
I've been trying using the useResource
function as follows (inside onClick
parameter of a @Composable Button):
scope.launch {
useResource("beep.mp3") {
val clip = AudioSystem.getClip()
val audioInputStream = AudioSystem.getAudioInputStream(
it
)
clip.open(audioInputStream)
clip.start()
}
}
but I get an error: Exception in thread "AWT-EventQueue-0" java.io.IOException: mark/reset not supported. I got the same error if I don't use the scope
, which I define at the top level of my composable as:
val scope = rememberCoroutineScope()
Any help will be appreciated!
答案1
得分: 1
需要一个库来解码MP3文件。这是关键。您可以添加以下Maven依赖项:
implementation("com.googlecode.soundlibs:mp3spi:1.9.5.4")
使用最初的Java Sound API,您可以使用以下代码:
import java.io.File;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioSystem.getAudioInputStream;
import javax.sound.sampled.DataLine.Info;
import javax.sound.sampled.SourceDataLine;
class AudioPlayer {
public void play(String path) {
File file = new File(path);
getAudioInputStream(file).use(in -> {
AudioFormat outFormat = getOutFormat(in.getFormat());
Info info = new Info(SourceDataLine.class, outFormat);
AudioSystem.getLine(info).use(line -> {
if (line instanceof SourceDataLine) {
SourceDataLine sourceLine = (SourceDataLine) line;
sourceLine.open(outFormat);
sourceLine.start();
stream(getAudioInputStream(outFormat, in), sourceLine);
sourceLine.drain();
sourceLine.stop();
}
});
});
}
private AudioFormat getOutFormat(AudioFormat inFormat) {
int ch = inFormat.getChannels();
float rate = inFormat.getSampleRate();
return new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, rate, 16, ch, ch * 2, rate, false);
}
private void stream(AudioInputStream in, SourceDataLine line) {
byte[] buffer = new byte[65536];
int n;
while ((n = in.read(buffer, 0, buffer.length)) != -1) {
line.write(buffer, 0, n);
}
}
}
然后,从非UI线程/协程调用play
方法:
new AudioPlayer().play(fullPathToMP3File);
原始工作由oldo完成,参考链接:https://odoepner.wordpress.com/2013/07/19/play-mp3-or-ogg-using-javax-sound-sampled-mp3spi-vorbisspi/
<details>
<summary>英文:</summary>
A library is needed to decode MP3 files. This is the key. You may add this maven dependency:
implementation("com.googlecode.soundlibs:mp3spi:1.9.5.4")
Using Java Sound APIs you originally used:
import java.io.File
import javax.sound.sampled.AudioFormat
import javax.sound.sampled.AudioInputStream
import javax.sound.sampled.AudioSystem
import javax.sound.sampled.AudioSystem.getAudioInputStream
import javax.sound.sampled.DataLine.Info
import javax.sound.sampled.SourceDataLine
class AudioPlayer {
fun play(path: String) {
val file = File(path)
getAudioInputStream(file).use { in
->
val outFormat = getOutFormat(in
.format)
val info = Info(SourceDataLine::class.java, outFormat)
AudioSystem.getLine(info).use { line ->
(line as? SourceDataLine)?.let { l ->
l.open(outFormat)
l.start()
stream(getAudioInputStream(outFormat, in
), l)
l.drain()
l.stop()
}
}
}
}
private fun getOutFormat(inFormat: AudioFormat): AudioFormat {
val ch = inFormat.channels
val rate = inFormat.sampleRate
return AudioFormat(AudioFormat.Encoding.PCM_SIGNED, rate, 16, ch, ch * 2, rate, false)
}
private fun stream(`in`: AudioInputStream, line: SourceDataLine) {
val buffer = ByteArray(65536)
var n = 0
while (n != -1) {
line.write(buffer, 0, n)
n = `in`.read(buffer, 0, buffer.size)
}
}
}
And call the `play` method from a non-UI thread / coroutine:
AudioPlayer().play(fullPathToMP3File)
Credit to original work by oldo: https://odoepner.wordpress.com/2013/07/19/play-mp3-or-ogg-using-javax-sound-sampled-mp3spi-vorbisspi/
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论