3

オーディオ処理をしようとしていますが、ステレオからモノラルへの変換に本当に行き詰まっています。ステレオからモノラルへの変換についてインターネットで調べました。

私が知る限り、左チャンネルと右チャンネルを取り、それらを合計して 2 で割ることができます。しかし、結果を再度 WAV ファイルにダンプすると、フォアグラウンド ノイズが大量に発生します。データの処理中にノイズが発生する可能性があることはわかっています。バイト変数にオーバーフローがあります。

これは、MP3 ファイルから byte[] データ チャンクを取得するクラスです。

public class InputSoundDecoder {

private int BUFFER_SIZE = 128000;
private String _inputFileName;
private File _soundFile;
private AudioInputStream _audioInputStream;
private AudioFormat _audioInputFormat;
private AudioFormat _decodedFormat;
private AudioInputStream _audioInputDecodedStream;

public InputSoundDecoder(String fileName) throws UnsuportedSampleRateException{
    this._inputFileName = fileName;
    this._soundFile = new File(this._inputFileName);
    try{
        this._audioInputStream = AudioSystem.getAudioInputStream(this._soundFile);
    }
    catch (Exception e){
        e.printStackTrace();
        System.err.println("Could not open file: " + this._inputFileName);
        System.exit(1);
    }

    this._audioInputFormat = this._audioInputStream.getFormat();

    this._decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 1, 44100, false);
    this._audioInputDecodedStream = AudioSystem.getAudioInputStream(this._decodedFormat, this._audioInputStream);

    /** Supported sample rates */
    switch((int)this._audioInputFormat.getSampleRate()){
        case 22050:
                this.BUFFER_SIZE = 2304;
            break;

        case 44100:
                this.BUFFER_SIZE = 4608;
            break;

        default:
            throw new UnsuportedSampleRateException((int)this._audioInputFormat.getSampleRate());
    }

    System.out.println ("# Channels: " + this._decodedFormat.getChannels());
    System.out.println ("Sample size (bits): " + this._decodedFormat.getSampleSizeInBits());
    System.out.println ("Frame size: " + this._decodedFormat.getFrameSize());
    System.out.println ("Frame rate: " + this._decodedFormat.getFrameRate());

}

public byte[] getSamples(){
    byte[] abData = new byte[this.BUFFER_SIZE];
    int bytesRead = 0;

    try{
        bytesRead = this._audioInputDecodedStream.read(abData,0,abData.length);
    }
    catch (Exception e){
        e.printStackTrace();
        System.err.println("Error getting samples from file: " + this._inputFileName);
        System.exit(1);
    }

    if (bytesRead > 0)
        return abData;
    else
        return null;
}

}

つまり、getSamples を呼び出すたびに、次のような配列が返されます。

buff = {Lchannel、Rchannel、Lchannel、Rchannel、Lchannel、Rchannel、Lchannel、Rchannel...}

モノへの変換の処理ルーチンは次のようになります。

    byte[] buff = null;
        while( (buff = _input.getSamples()) != null ){

            /** Convert to mono */
            byte[] mono = new byte[buff.length/2];

            for (int i = 0 ; i < mono.length/2; ++i){
                int left = (buff[i * 4] << 8) | (buff[i * 4 + 1] & 0xff);
                int right = (buff[i * 4 + 2] <<8) | (buff[i * 4 + 3] & 0xff);
                int avg = (left + right) / 2;
                short m = (short)avg; /*Mono is an average between 2 channels (stereo)*/
                mono[i * 2] = (byte)((short)(m >> 8));
                mono[i * 2 + 1] = (byte)(m & 0xff);
            }

}

そして、次を使用して wav ファイルに書き込みます。

     public static void writeWav(byte [] theResult, int samplerate, File outfile) {
        // now convert theResult into a wav file
        // probably should use a file if samplecount is too big!
        int theSize = theResult.length;


        InputStream is = new ByteArrayInputStream(theResult);
        //Short2InputStream sis = new Short2InputStream(theResult);

        AudioFormat audioF = new AudioFormat(
                AudioFormat.Encoding.PCM_SIGNED,
                samplerate,
                16,
                1,          // channels
                2,          // framesize
                samplerate,
                false
        );

        AudioInputStream ais = new AudioInputStream(is, audioF, theSize);

        try {
            AudioSystem.write(ais, AudioFileFormat.Type.WAVE, outfile);
        } catch (IOException ioe) {
            System.err.println("IO Exception; probably just done with file");
            return;
        }


    }

サンプルレートとして 44100 を使用。

実際に私が持っている byte[] 配列はすでに pcm になっているので、mp3 -> pcm 変換を指定して行うことに注意してください

 this._decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 1, 44100, false);
this._audioInputDecodedStream = AudioSystem.getAudioInputStream(this._decodedFormat, this._audioInputStream);

先ほど言ったように、Wav ファイルに書き込んでいるときにノイズが多くなりました。バイトのすべてのチャンクに FFT を適用するふりをしていますが、ノイズが多いため、結果は正しくないと思います。

2つの曲を取っているので、そのうちの1つは別の20秒のクロップであり、クロップされたfftの結果を元の20秒のサブセットと比較すると、まったく一致しません.

原因はステレオ→モノの変換ミスだと思います。

誰かがこれについて何か知っていることを願って、

よろしく。

4

1 に答える 1

7

コメントで指摘されているように、エンディアンが間違っている可能性があります。また、signed short に変換してシフトすると、最初のバイトが 0xFF になる場合があります。

試す:

int HI = 0; int LO = 1;
int left = (buff[i * 4 + HI] << 8) | (buff[i * 4 + LO] & 0xff);
int right = (buff[i * 4 + 2 + HI] << 8) | (buff[i * 4 + 2 + LO] & 0xff);
int avg = (left + right) / 2;
mono[i * 2 + HI] = (byte)((avg >> 8) & 0xff);
mono[i * 2 + LO] = (byte)(avg & 0xff);

次に、HI と LO の値を切り替えて、改善するかどうかを確認します。

于 2013-05-09T19:04:07.850 に答える