在Kotlin/Java中直接从生成的声音阵列播放声音
我正在寻找一种在Kotlin/Java中生成和播放声音的方法。我已经寻找了很多,并尝试了不同的解决方案,但它不是真的令人满意。 我不是在寻找Java控件类,它允许我将混响添加到现有的声音中,或者是javax.sound.midi包,它允许我进行midi排序。相反,我想通过以下方式从头开始构建声音作为声音向量/列表:在Kotlin/Java中直接从生成的声音阵列播放声音,java,audio,kotlin,signal-processing,javasound,Java,Audio,Kotlin,Signal Processing,Javasound,我正在寻找一种在Kotlin/Java中生成和播放声音的方法。我已经寻找了很多,并尝试了不同的解决方案,但它不是真的令人满意。 我不是在寻找Java控件类,它允许我将混响添加到现有的声音中,或者是javax.sound.midi包,它允许我进行midi排序。相反,我想通过以下方式从头开始构建声音作为声音向量/列表: fun createSinWaveBuffer(freq: Double, ms: Int, sampleRate: Int = 44100): ByteArray { va
fun createSinWaveBuffer(freq: Double, ms: Int, sampleRate: Int = 44100): ByteArray {
val samples = (ms * sampleRate / 1000)
val output = ByteArray(samples)
val period = sampleRate.toDouble() / freq
for (i in output.indices) {
val angle = 2.0 * Math.PI * i.toDouble() / period
output[i] = (Math.sin(angle) * 127f).toByte()
}
//output.forEach { println(it) }
return output
}
然后我想播放声音,让扬声器的实际输出与发送到函数的输入参数在频率、长度等方面匹配。当然,创建两个不同频率的声音向量应该将它们相加,或者至少取平均值应该导致两个音调同时播放
这在matlab中非常简单,如果你有一个向量y,像这样
t=0:1/samplerate:duration;
y=sin(2*pi*freq*t);
照办
sound(y,sampleRate)
虽然Java中可能没有这么简单或干净的解决方案,但我仍然觉得应该可以播放自定义声音
在这里和其他地方搜索了一些之后,这是我正在尝试的最干净的解决方案之一(尽管它使用sun.audio,但其他建议更为混乱):
但是playsound(createSinWaveBuffer(440.0、10000、44100))在我的扬声器中听起来不太合适。它听起来波涛汹涌,不是440赫兹,不是纯正弦波,也不是10秒。
我缺少什么?首先,不要使用sun软件包。永远
对于桌面,方法是生成数据,获取数据,打开并启动该行,然后将数据写入其中。重要的是,生产线适合您选择生成的产品。在这种情况下,8位/采样,采样率44100
Hz
这里有一个Java的工作示例,我相信您可以轻松地将其转换为Kotlin
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class ClipDemo {
private static byte[] createSinWaveBuffer(final float freq, final int ms, final float sampleRate) {
final int samples = (int)(ms * sampleRate / 1000);
final byte[] output = new byte[samples];
final float period = sampleRate / freq;
for (int i=0; i<samples; i++) {
final float angle = (float)(2f * Math.PI * i / period);
output[i] = (byte) (Math.sin(angle) * 127f);
}
return output;
}
public static void main(String[] args) throws LineUnavailableException {
final int rate = 44100;
final byte[] sineBuffer = createSinWaveBuffer(440, 5000, rate);
// describe the audio format you're using.
// because its byte-based, it's 8 bit/sample and signed
// if you use 2 bytes for one sample (CD quality), you need to pay more attention
// to endianess and data encoding in your byte buffer
final AudioFormat format = new AudioFormat(rate, 8, 1, true, true);
final SourceDataLine line = AudioSystem.getSourceDataLine(format);
// open the physical line, acquire system resources
line.open(format);
// start the line (... to your speaker)
line.start();
// write to the line (... to your speaker)
// this call blocks.
line.write(sineBuffer, 0, sineBuffer.length);
// cleanup, i.e. close the line again (left out in this example)
}
}
导入javax.sound.sampled.AudioFormat;
导入javax.sound.sampled.AudioSystem;
导入javax.sound.sampled.LineUnavailableException;
导入javax.sound.sampled.SourceDataLine;
公共类ClipDemo{
专用静态字节[]createSinWaveBuffer(最终浮点频率、最终整数毫秒、最终浮点采样器){
最终整数样本=(整数)(ms*采样器/1000);
最终字节[]输出=新字节[样本];
最终浮动周期=取样器/频率;
对于(int i=0;ii如果我对这个API的简单搜索有任何好处,那么我不认为选择音频播放器是一个维护良好的选项,是未来的证明。不过我可能错了。你是在寻找桌面还是Android解决方案?不要使用sun.audio
类-它们不是官方API的一部分,在现代版本中根本不起作用查看javax.sound.sampled
类。标记信息有很多指向示例的链接。一般来说,不要使用sun
类。@hendrik是一个桌面解决方案。如果可以使用任何标准的Java/kotlin类来完成,那就好了(我真的不明白为什么不能,因为这是你可以要求计算机做的最基本的事情之一),但我想嵌入式c/c++文件或.dll库也可以工作。SourceDataLine也适用于流式和连续音频。
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class ClipDemo {
private static byte[] createSinWaveBuffer(final float freq, final int ms, final float sampleRate) {
final int samples = (int)(ms * sampleRate / 1000);
final byte[] output = new byte[samples];
final float period = sampleRate / freq;
for (int i=0; i<samples; i++) {
final float angle = (float)(2f * Math.PI * i / period);
output[i] = (byte) (Math.sin(angle) * 127f);
}
return output;
}
public static void main(String[] args) throws LineUnavailableException {
final int rate = 44100;
final byte[] sineBuffer = createSinWaveBuffer(440, 5000, rate);
// describe the audio format you're using.
// because its byte-based, it's 8 bit/sample and signed
// if you use 2 bytes for one sample (CD quality), you need to pay more attention
// to endianess and data encoding in your byte buffer
final AudioFormat format = new AudioFormat(rate, 8, 1, true, true);
final SourceDataLine line = AudioSystem.getSourceDataLine(format);
// open the physical line, acquire system resources
line.open(format);
// start the line (... to your speaker)
line.start();
// write to the line (... to your speaker)
// this call blocks.
line.write(sineBuffer, 0, sineBuffer.length);
// cleanup, i.e. close the line again (left out in this example)
}
}