2011-04-19 126 views
4

我有pcm音頻存儲在一個字節數組。它是每個樣本16位。我想讓它每個樣本音頻8位。轉換16位PCM到8位

任何人都可以提出一個很好的算法來做到這一點?右 -

,因爲我覺得它不是算法重要的我沒有提到的比特率?

+1

比特率可能很重要(但不一定) - 例如,當處理A/D轉換器時(在處理音頻時,您最終通過A/D輸出音頻),您可以將採樣率提高65k(如果我正確計算),以較少的位獲得更高的分辨率(稱爲過採樣)。 – flolo 2011-04-19 14:03:19

+1

這不是Java,但看看ffmpeg如何實現它。瀏覽這裏的代碼:http://ffmpeg.org/doxygen/0.5/pcm_8c-source.html – Aleadam 2011-04-19 14:08:26

+0

@gosho_ot_pochivka你可以讓我知道如何將16bit pcm轉換爲24位。謝謝 – ravi 2016-02-24 10:58:44

回答

7

我看不出現在爲什麼它是不夠的,只取高字節,即丟棄每個樣品的低8位。

當然假設樣本是線性的;如果他們不是,那麼也許你需要做一些事情來將它們線性化,然後才能放棄比特。

short sixteenBit = 0xfeed; 
byte eightBit = sixteenBit >> 8; 
// eightBit is now 0xfe. 

正如評論建議的AShelly,它可能是圓一個好主意,即加1,如果我們丟棄的字節高於一半其最大:

eightBit += eightBit < 0xff && ((sixteenBit & 0xff) > 0x80); 

測試對0xff執行clamp操作,所以我們不會冒險將1加到0xff並將其包裝到0x00,這會很糟糕。

+1

您可能還想要舍入而不是截斷。加'八位+ =(十六位&0x80)>> 7;'如果低位字節超過其一半的範圍,則加1。 – AShelly 2011-04-19 14:40:07

+1

@AShelly:true,這可能是一個好主意......你的代碼會導致0xff00到0xffff範圍內的值被包裝爲0x00,這可能比根本不捨得更糟。我會編輯。 – unwind 2011-04-20 10:12:22

+0

謝謝。如果我的輸入是在一個字節數組中(byte [] arr不短),那麼這是否意味着只放下一半字節,即採用arr [0],arr [2],arr [4]等。 – 2011-04-20 11:07:39

1

對16位採樣進行歸一化,然後按8位採樣的最大值進行重新調整。

這會產生更準確的轉換,因爲每個樣本的低8位不會被丟棄。但是,我的解決方案比選定的答案在計算上更昂貴。

6

16位樣品通常簽署和8位樣本通常是無符號的,所以最簡單的答案是,你需要16位樣本轉換籤訂(16位採樣幾乎總是存儲爲一個範圍從-32768到+32767)無符號,然後取結果的前8位。在C中,這可以表示爲output =(unsigned char)((unsigned short)(input + 32768)>> 8)。這是一個好的開始,並且可能足夠滿足您的需求,但聽起來不會很好。這聽起來很粗糙,因爲「量化噪音」。

量化噪聲是原始輸入和算法輸出之間的差異。不管你做什麼,你都會有噪音,平均噪音會「半」。對此你沒有辦法做,但有辦法使噪音不那麼明顯。

量化噪聲的主要問題是它傾向於形成圖案。如果輸入和輸出之間的差異是完全隨機的,事情實際上聽起來會很好,但相反,對於波形的某個部分,輸出會反覆過高,對於下一部分輸出會過低。你的耳朵採用這種模式。

要獲得聽起來不錯的結果,您需要添加抖動。抖動是一種試圖平滑量化噪聲的技術。最簡單的抖動只是從噪聲中移除圖案,以便噪聲圖案不會偏離實際的信號圖案。更好的抖動可以更進一步,並採取措施減少噪聲,方法是將多個樣本的誤差值相加,然後在總誤差足夠大以便值得修正時加入校正。

您可以在線找到各種抖動算法的解釋和代碼示例。一個很好的研究領域可能是SoX工具,http://en.wikipedia.org/wiki/SoX。檢查源代碼的抖動效果,並嘗試將各種聲音從16位轉換爲8位,同時啓用和不啓用抖動。轉換爲8位聲音時,抖動可能會使質量出現差異,您會感到驚訝。

1
byteData = (byte) (((shortData +32768)>>8)& 0xFF) 

這對我有用。