2

私はオーディオの操作に非常に慣れていないため、何日も解決策を探していましたが、何も見つかりませんでした。

だから私はこれで .wav ファイルのバイト配列を取得します (出典: Java で Wav ファイルをバイト配列に変換)

ByteArrayOutputStream out = new ByteArrayOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(WAV_FILE));

int read;
byte[] buff = new byte[1024];
while ((read = in.read(buff)) > 0)
{
     out.write(buff, 0, read);
}
out.flush();
byte[] audioBytes = out.toByteArray();

次に、バイト配列を float 配列に変換し、-1.0 から 1.0 に正規化します。(ソース: wav オーディオ形式のバイト配列を浮動小数点に変換)

ShortBuffer sbuf =
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
short[] audioShorts = new short[sbuf.capacity()];
sbuf.get(audioShorts);

float[] audioFloats = new float[audioShorts.length];
for (int i = 0; i < audioShorts.length; i++) {
    audioFloats[i] = ((float)audioShorts[i])/0x8000;
}
return audioFloats;

後でこれを線画に変換し、java.swing を使用して波形を出力します。

class Panel2 extends JPanel {
float[] audioFloats;

    Dimension d;
    public Panel2(Dimension d, float[] audioFloats) {
        // set a preferred size for the custom panel.
        this.d = d;
        setPreferredSize(d);
        this.audioFloats = audioFloats;
    }


    @Override
    public void paint(Graphics g) {
        //super.paintComponent(g);
        super.paint(g); 

        //shift by 45 because first 44 bytes used for header
        for (int i = 45; i<audioFloats.length; i++){

            Graphics2D g2 = (Graphics2D) g;
            float inc = (i-45)*((float)d.width)/((float)(audioFloats.length-45-1));
            Line2D lin = new Line2D.Float(inc, d.height/2, inc, (audioFloats[i]*d.height+d.height/2));
            g2.draw(lin);

        }


    }
}

波形は 16 ビットの wav ファイルでのみ正しく表示されます (goldwave でクロス チェックしたところ、私の波形とその波形の両方が 16 ビットで同様に見えます)。

8 ビットの .wav ファイルでこれを行うにはどうすればよいですか?

これは宿題なので、私の唯一の制限は、wav ファイルをバイトごとに読み取ることです。

また、wav ファイルは PCM でコーディングされており、最初の 44 バイトがヘッダーとして予約されていることも知っています。

4

2 に答える 2

0

コードのこの部分を調整する必要があります。

ShortBuffer sbuf =
  ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
short[] audioShorts = new short[sbuf.capacity()];
sbuf.get(audioShorts);

float[] audioFloats = new float[audioShorts.length];
for (int i = 0; i < audioShorts.length; i++) {
    audioFloats[i] = ((float)audioShorts[i])/0x8000;
}

まったく必要ありませんByteBuffer。既にバイト配列を持っています。したがって、それをフロートに変換するだけです:

float[] audioFloats = new float[audioBytes.length];
for (int i = 0; i < audioBytes.length; i++) {
    audioFloats[i] = ((float)audioBytes[i])/0x80;
}
于 2012-10-10T20:22:40.733 に答える
0

オーディオ ストリームは、通常、データの 1 つのチャネルでインターリーブされ、次にデータの反対のチャネルでインターリーブされます。たとえば、最初の 16 ビットが左チャネルになり、次の 16 ビットが右チャネルになります。これらはそれぞれ 1 フレームのデータと見なされます。メソッドが 1 つのチャネルのみを読み取るように設定されているように見えるため、8 ビット ストリームが 1 つのチャネルのみであることを確認します。

また、フレームを変換する例では、個々のチャネルをショートとして取得し、それを16進数の0x8000または符号付きショートの最大値で割って10進数を見つけます。

short[] audioShorts = new short[sbuf.capacity()];
sbuf.get(audioShorts);
...
audioFloats[i] = ((float)audioShorts[i])/0x8000;

私の推測では、8 バイト ストリームを short ではなくタイプ「byte」として読み取り、それを 128 または符号付き 8 ビット値の最大値で割る必要があるということです。これには、16 ビット ストリームの代わりに 8 ビット ストリームを処理するまったく新しい方法を作成することが含まれます。以下の変更を伴います。

byte[] audioBytes = new byte[sbuf.capacity()];
sbuf.get(audioBytes);
...
audioFloats[i] = ((float)audioBytes[i])/0x80;
于 2012-10-10T20:31:01.197 に答える