我需要使用Java访问多个音频输入,因此首先咨询SO并找到this answer并且设法使用PortAudio Java绑定(jpab)。不幸的是,我发现很少和过时的documentation。
我发现我在eclipse中使用Processing尝试了这个:
import java.nio.ByteBuffer;
import org.jpab.Callback;
import org.jpab.Device;
import org.jpab.PortAudio;
import org.jpab.PortAudioException;
import org.jpab.Stream;
import org.jpab.StreamConfiguration;
import org.jpab.StreamConfiguration.Mode;
import org.jpab.StreamConfiguration.SampleFormat;
import processing.core.PApplet;
public class PortAudioPlot extends PApplet implements Callback {
float min = 1000000,max = 0;
public void setup(){
try {
PortAudio.initialize();
for(Device d : PortAudio.getDevices()) println(d);
Device d = PortAudio.getDevices().get(1);// Microphone (Realtek High Definition Audio)
if(d.getMaxInputChannels() > 0){
println(d.getName());
StreamConfiguration sc = new StreamConfiguration();
sc.setInputDevice(d);
sc.setInputFormat(SampleFormat.SIGNED_INTEGER_16);
sc.setMode(Mode.INPUT_ONLY);
sc.setSampleRate(44100);
sc.setInputChannels(d.getMaxInputChannels());
PortAudio.createStream(sc, this, new Runnable() {
public void run() {
try {
PortAudio.terminate();
} catch (PortAudioException ignore) { ignore.printStackTrace(); }
}
}).start();
}
} catch (PortAudioException e) {
e.printStackTrace();
}
}
public void draw(){
if(keyPressed && key == 's') saveFrame(dataPath("frame-####.jpg"));
}
public void stop(){
try {
PortAudio.terminate();
} catch (PortAudioException e) {
e.printStackTrace();
}
super.stop();
}
public static void main(String[] args) {
PApplet.main(PortAudioPlot.class.getSimpleName());
}
@Override
public State callback(ByteBuffer in, ByteBuffer out) {
int size = in.capacity();
println("in size: " + size + " min: " + min + " max: " + max);
background(255);
beginShape(LINES);
for (int i = 0; i < size; i++) {
float v = in.getFloat(i);
if(!Float.isNaN(v) && v != Float.POSITIVE_INFINITY && v != Float.NEGATIVE_INFINITY){
float x = (float)i/size * width;
float y = (height * .5f) + (v * .5f);
if(v < min) min = v;
if(v > max) max = v;
vertex(x,y);
}
}
endShape();
return State.ABORTED;
}
}
我从麦克风第一开始,我认为我已经接近,因为我看起来有些值,但我不是100%肯定我正在遍历输入ByteBuffer。
使用jpab访问值并使用音频输入绘制波形的正确方法是什么?
我已经更新了代码并设法让某些东西更贴近情节,但我仍然处于黑暗中。从输入ByteBuffer读取的浮点数的正确最小/最大范围是多少?我是以正确的方式使用它吗?
以下是我所得到的内容的快速预览:
我还上传了eclipse项目here。它正在使用prebuilt Windows x86 PortAudio binaries。
另一个更新: 我被告知值应该从-1.0到1.0并调整我的代码以映射/钳位,但我不确定这是否正确。 这是一个更新的例子:
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.jpab.Callback;
import org.jpab.Device;
import org.jpab.PortAudio;
import org.jpab.PortAudioException;
import org.jpab.Stream;
import org.jpab.StreamConfiguration;
import org.jpab.StreamConfiguration.Mode;
import org.jpab.StreamConfiguration.SampleFormat;
import processing.core.PApplet;
public class PortAudioPlot extends PApplet implements Callback {
int[] pix;
int hh;//half height
int py;//y for each channel plot
int numChannels;
int pad = 5;
public void setup(){
try {
colorMode(HSB,360,100,100);
hh = height/2;
pix = new int[width*height];
PortAudio.initialize();
for(Device d : PortAudio.getDevices()) println(d);
Device d = PortAudio.getDevices().get(1);// Microphone (Realtek High Definition Audio)
numChannels = d.getMaxInputChannels();
py = height / numChannels;
if(numChannels > 0){
println(d.getName()+" sr:" + d.getDefaultSampleRate());
StreamConfiguration sc = new StreamConfiguration();
sc.setInputLatency(d.getDefaultLowInputLatency());
sc.setInputDevice(d);
sc.setInputFormat(SampleFormat.SIGNED_INTEGER_16);
sc.setMode(Mode.INPUT_ONLY);
sc.setSampleRate(d.getDefaultSampleRate());
sc.setInputChannels(numChannels);
PortAudio.createStream(sc, this, new Runnable() {
public void run() {
try {
PortAudio.terminate();
} catch (PortAudioException ignore) { ignore.printStackTrace(); }
}
}).start();
}
} catch (PortAudioException e) {
e.printStackTrace();
}
}
public void draw(){
loadPixels();
arrayCopy(pix, pixels);
updatePixels();
if(keyPressed && key == 's') saveFrame(dataPath("frame-####.jpg"));
}
public void stop(){
try {
PortAudio.terminate();
} catch (PortAudioException e) {
e.printStackTrace();
}
super.stop();
}
public static void main(String[] args) {
PApplet.main(PortAudioPlot.class.getSimpleName());
}
@Override
public State callback(ByteBuffer in, ByteBuffer out) {
int size = in.capacity();
println("in size: " + size);
Arrays.fill(pix, color(0,0,100));
for (int i = 0; i < width; i++) {
int ch = i%numChannels;//channel id
int sy = py * ch;//channel plot y starting position
int minY = sy+pad;//min y for min input value
int maxY = (sy*2)-pad;//min y for min input value
int buffIndex = i * size / width;//map i(x pixel index) to buffer index
float v = in.getFloat(buffIndex);
if(!Float.isNaN(v) && v != Float.POSITIVE_INFINITY && v != Float.NEGATIVE_INFINITY){
int vOffset = constrain((int)map(v,-1.0f,1.0f,minY,maxY),minY,maxY);
pix[vOffset * height + i] = color(map(ch,0,numChannels,0,360),100,50);
}
}
return State.RUNNING;
}
}
我还注意到,当我设置延迟时,输入的ByteBuffer计数会发生变化。
另一个让我注意到的令人困惑的事情是:JPAB
有关我如何继续的任何线索?
答案 0 :(得分:0)
最终目标是访问多个音频输入,此时这条路线似乎无处可寻。
我在Windows和OSX上测试过的最简单的解决方案很容易设置并且可以在普通Java中运行,但在处理中也很好用Beads可以连接到JACK 。有关更多详细信息,请参阅此thread,尤其是有关JNAJack的后续部分(不再维护JJack)。我已使用此版本的Beads(下载链接)和JNA(下载链接)。
这是我用来测试的基本代码示例:
import java.util.Arrays;
import org.jaudiolibs.beads.AudioServerIO;
import net.beadsproject.beads.core.AudioContext;
import net.beadsproject.beads.core.AudioIO;
import net.beadsproject.beads.core.UGen;
import net.beadsproject.beads.ugens.Gain;
import processing.core.PApplet;
public class BeadsJNA extends PApplet {
AudioContext ac;
public void setup(){
ac = new AudioContext(new AudioServerIO.Jack(),512,AudioContext.defaultAudioFormat(4,2));//control number of ins(4) and outs(2)
UGen microphoneIn = ac.getAudioInput();
Gain g = new Gain(ac, 1, 0.5f);
g.addInput(microphoneIn);
ac.out.addInput(g);
println("no. of inputs: " + ac.getAudioInput().getOuts());
ac.start();
}
public void draw(){
loadPixels();
Arrays.fill(pixels, color(0));
for(int i = 0; i < width; i++)
{
int buffIndex = i * ac.getBufferSize() / width;
int vOffset = (int)((1 + ac.out.getValue(0, buffIndex)) * height / 2);
pixels[vOffset * height + i] = color(255);
}
updatePixels();
}
public static void main(String[] args) {
PApplet.main(BeadsJNA.class.getSimpleName());
}
}
这在现阶段对我有用,所以这是一个有效的答案 直到有人会在Windows上分享一个简单的方法来使用jpab / jportaudio 绘制输入波形。