亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

分層音頻文件Java時的峰值削波

分層音頻文件Java時的峰值削波

慕田峪9158850 2022-07-20 10:33:40
因此,作為我正在進行的項目的一部分,我試圖將多個音頻片段疊加在一起以創建人群的聲音,并將其寫入新的 .WAV 文件。首先,我創建一個文件(一個 16 位 PCM .WAV 文件)的 byte[] 表示,這似乎不會導致任何問題。public byte[] toByteArray(File file){    try    {        AudioInputStream in = AudioSystem.getAudioInputStream(file);        byte[] byteArray = new byte[(int) file.length()];//make sure the size is correct        while (in.read(byteArray) != -1) ;//read in byte by byte until end of audio input stream reached        return byteArray;//return the new byte array    }然后,我創建一個緩沖區(一個整數數組,以便在添加字節時防止字節溢出)并嘗試在我的文件的字節數組版本中分層。 int[] buffer = new int[bufferLength];//buffer of appropriate length        int offset = 0;//no offset for the very first file        while(!convertedFiles.isEmpty())//until every sample has been added        {            byte[] curr = convertedFiles.pop();//get a sample from list            if(curr.length+offset < bufferLength)            {                for (int i =0; i < curr.length; i++)                {                    buffer[i] += curr[i];                }            }           offset = randomiseOffset();//next sample placed in a random location in the buffer        }當我嘗試實現一種隨機偏移時,問題就出現了。我可以將所有音頻從索引 0(緩沖區 [0])添加到我的緩沖區,因此所有內容都可以立即播放,并且可以正常工作。但是,如果我嘗試在整個緩沖區中隨機分散單個剪輯,我會遇到問題。當我嘗試抵消文件的添加時,相對于緩沖區的長度,我得到了可怕的靜態和削峰。 buffer[i+offset] += curr[i];我意識到我需要小心避免溢出,這就是為什么我嘗試使用整數緩沖區而不是字節緩沖區。我不明白的是為什么它只在我引入偏移時才會中斷。我沒有發布實際使用 AudioSystem 對象創建新文件的代碼,因為它似乎沒有任何效果。這是我第一次使用音頻編程,因此非常感謝任何幫助。
查看完整描述

1 回答

?
牧羊人nacy

TA貢獻1862條經驗 獲得超7個贊

你的randomiseOffset()方法是什么樣的?是否考慮到每個音頻樣本都是兩個字節長?如果randomiseOffset()給你奇怪的偏移量,你最終會混合一個樣本的低字節和另一個樣本的高字節,這聽起來像(通常是可怕的)噪音。也許這就是您識別為削波的聲音。


要做到這一點,您需要先解碼音頻,即考慮樣本長度(2 字節)和通道數(?),進行操作,然后將音頻再次編碼為字節流。


假設您只有一個通道并且字節順序是little-endian。然后您將兩個字節解碼為如下示例值:


private static int byteToShortLittleEndian(final byte[] buf, final int offset) {

    int sample = (buf[offset] & 0xff) + ((buf[offset+1] & 0xff) << 8);

    return (short)sample;

}

要進行編碼,您可以使用如下內容:


private static byte[] shortToByteLittleEndian(final int[] samples, final int offset) {

    byte[] buf = new byte[2];

    int sample = samples[offset];

    buf[0] = sample & 0xFF;

    buf[1] = (sample >> 8) & 0xFF;

    return buf;

}

以下是在您的案例中使用這兩種方法的方式:


byte[] byteArray = ...;  // your array

// DECODE: convert to sample values

int[] samples = byteArray.length / 2;

for (int i=0; i<samples.length; i++) {

    samples[i] = byteToShortLittleEndian(byteArray, i*2);

}

// now do your manipulation on the samples array

[...]

// ENCODE: convert back to byte values

byte[] byteOut = new byte[byteArray.length];

for (int i=0; i<samples.length; i++) {

    byte[] b = shortToByteLittleEndian(samples, i);

    byteOut[2*i] = b[0];

    byteOut[2*i+1] = b[1];

}

// do something with byteOut ...

(請注意,您可以通過批量解碼/編碼輕松提高效率,而不是如上所示處理單個樣本。我只是認為它更容易理解。)


在您的操作過程中,您必須注意您的樣本值。它們不得大于Short.MAX_VALUE或小于Short.MIN_VALUE。如果您檢測到您超出了有效范圍,只需縮放整個數組。這樣你就可以避免剪裁。


查看完整回答
反對 回復 2022-07-20
  • 1 回答
  • 0 關注
  • 92 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號