簡體   English   中英

從音頻PCM 16位到8位-產生噪音

[英]From audio PCM 16 bit to 8 bit - getting noise

我實現了以下算法,將PCM 16位音頻數據轉換為8位:

if(encoding == AudioFormat.ENCODING_PCM_8BIT){
    int len = data.length;          
    data1 = new byte[len/2];
    int tempint;

    for (int k = 0, i=1; i < len; i+=2, k++) {
        tempint = ((int)data[i]) ^ 0x00000080; 
        data1[k] = (byte)tempint;
    }
    data=null;
}

其中data is byte[] 運行這段代碼后,輸出中contains a lot of noise並提示我在這里做錯了什么。 What should I do besides dropping the lower byte?

[編輯]:修改了代碼:

if(encoding == AudioFormat.ENCODING_PCM_8BIT){

            int len = data.length;          
            data1 = new byte[len/2];
            for (int i = 0; i < len/2; i++) {                   
                    data1[i] = data[i*2+1];     
            }

  }

the input/output looks like:

 Original data(counter:0) = 4
    Original data(counter:1) = -1
    Original data(counter:2) = 75
    Original data(counter:3) = -1
    Original data(counter:4) = 16
    Original data(counter:5) = -1
    Original data(counter:6) = 44
    Original data(counter:7) = -1
    Original data(counter:8) = 7
    Original data(counter:9) = -1
    Original data(counter:10) = 22
    Original data(counter:11) = -1
    Original data(counter:12) = 22
    Original data(counter:13) = -1
    Original data(counter:14) = 12
    Original data(counter:15) = -1

Output data:(counter:0) = -1
Output data:(counter:1) = -1
Output data:(counter:2) = -1
Output data:(counter:3) = -1
Output data:(counter:4) = -1
Output data:(counter:5) = -1
Output data:(counter:6) = -1
Output data:(counter:7) = -1
Output data:(counter:8) = -1
Output data:(counter:9) = -1
Output data:(counter:10) = -1
Output data:(counter:11) = -1
Output data:(counter:12) = -1
Output data:(counter:13) = -1
Output data:(counter:14) = -1
Output data:(counter:15) = -1

我丟棄第一個字節還是第二個字節都沒有關系,噪聲仍然存在。 在這里,我刪除了第一個字節(而不是第二個)

以下算法已大大降低了噪聲量,但無法完全消除它:

if(encoding == AudioFormat.ENCODING_PCM_8BIT){  
            ShortBuffer intBuf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
            short[] samples16Bit = new short[intBuf.remaining()];
            intBuf.get(samples16Bit);
            data1 = new byte[samples16Bit.length];
            for (int i = 0; i < samples16Bit.length; i++) {
                data1[i] = (byte)((samples16Bit[i] / 256)+128);
            }
        }

您所遇到的噪音僅僅是由您將音頻轉換到的位范圍引起的。 16Bit信號的本底噪聲為-96dB,而8Bit信號的本底噪聲為-48dB。 就這些數字而言,這看起來似乎並不多,但這是一個巨大的差異。 降采樣算法幾乎總是采用某種抖動來減少與轉換相關的噪聲量。 通過以編程方式或使用任何合適的音頻程序在8Bit中創建正弦波,您可以輕松地演示質量(和噪聲水平)的差異。 您會發現8Bit並不是真正的質量。 用16Bit正弦波重復實驗以進行比較。 不是您,而是位距。

為什么不只是這個呢?

int len = data.length;          
data1 = new byte[len/2];
for (int i=0; i < len/2; ++i)
    data1[i] = data[i*2];

我假設您的數據是Bigendian。 如果是LE,這應該可以工作:

int len = data.length;          
data1 = new byte[len/2];
for (int i=0; i < len/2; ++i)
    data1[i] = data[i*2+1];

由於多種原因,您會有很多雜音。 首先,您僅填充數組的每個其他值,未填充的值自動為零,這會極大地扭曲波形。 其次,您只選擇原始數據的前8位,這意味着如果數據點的前8位碰巧全部為零,則您將丟失所有數據,而該信息可能位於較高位。

天真的建議是縮放所有數據點(如果有符號,則除以2 ^ 7),以使最高數據點最多為8位,您仍然會丟失信息並引入失真,因為您被迫將數據保存為整數,並且整數除法將迫使除后相同(接近)范圍內的值相等,但這應少很多噪音:)

感謝下面的評論,如果僅從原始數據中獲取所有其他數據點,則會引入一種稱為Aliasing的失真。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM