2

Javaで複数のオーディオ入力にアクセスする必要があるので、最初にSOに相談し、この回答を見つけて、PortAudio Javaバインディング(jpab)を使用するようにデバイス化しました。残念ながら、古くなったドキュメントはほとんど見つかりませんでした。

私が見つけたもので、私は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;
    }

}

私はマイク1から始めて、いくつかの値のように見えるので近づいていると思いますが、入力ByteBufferを正しくトラバースしていると100%確信していません。

jpabを使用して値にアクセスし、オーディオ入力から波形をプロットする正しい方法は何ですか?

コードを少し更新して、なんとかプロットに近づけることができましたが、まだ暗闇の中にいます。入力ByteBufferから読み取られたfloatの正しい最小/最大範囲は何ですか?私はそれを正しい方法で使用していますか?

これが私が持っているものの簡単なプレビューです:

波のプロット

eclipseプロジェクトもここにアップロードしました。ビルド済みのWindowsx86PortAudioバイナリを使用しています。

別の更新:値を-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カウントが変化することにも気づきました。

そして、私が気付いたもう1つの紛らわしい点は、JPABはjportaudioと同じではありませんが、createStream(jpab)/ openStream(jportaudio)を除いて、ほとんどのAPIは似ています。コンパイルされたバージョンのjportaudioを見つけられず、Windowsで自分でコンパイルすることもできませんでした。

どうすれば続行できるかについての手がかりはありますか?

4

1 に答える 1

1

最終的な目標は複数のオーディオ入力にアクセスすることであり、現時点ではこのルートはどこにも通じていないようです。

私がWindowsとOSXでテストした最も単純なソリューションは、セットアップが簡単で、プレーンJavaで動作しますが、Processingでも非常にうまく機能し、JACKに接続できるBeadsを使用します。詳細、特に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を使用して入力から波形をプロットする簡単な方法を共有するまでは、有効な答えです。

于 2013-03-28T12:01:51.830 に答える