2010-07-06 39 views
0

我正在研究一種聲音轉換算法,其中收到一組有符號短褲。
在算法中的指定點它的樣品從16位轉換到14位,它確實是這樣的:pcm16到pcm14轉換使用加+移

int16_t sample = (old_sample + 2) >> 2; 

對我來說,它顯然需要換擋,因爲我們希望擺脫至少2個有效位,但那裏的+2呢?

回答

8

向下移動失去最不重要的兩位。如果你只是移動,那麼即使最低兩位都被設置,它也會總是減少。如果設置了較大的丟失位,則增加兩輪。 (也值得注意的是,減少比特數的更好的方法是使用dithering,即在樣本量減少之前增加一個隨機(和非常小)的噪聲量;這樣可以避免這樣的問題:由於聲音是週期性的,四捨五入通常會持續向上或一直向下一個特定的頻率,導致聲音可察覺失真。維基百科的文章連接解釋它比我更好!)

+0

Jaysus,四捨五入,當然。 – Fail 2010-07-06 17:07:44

1

我想它的目的是有四捨五入的效果嗎?我只希望他們對old_sample以上的情況進行調整,使其超過MAX_INT16 - 2。否則,當它溢出時可能會有問題。

+0

如果它是MAX_INT16 - 2,它仍然沒問題......我認爲old_sample應該在加入2之前轉換爲32位int,然後這個轉換將確保下一個轉換到16位不會造成傷害...不等等,它可能......它應該是算術轉換,而不是邏輯轉換(如果樣本被認爲是有符號的,就像它看起來一樣);是否>>按標準執行算術移位? – ShinTakezou 2010-07-06 17:27:52

+0

是的,應該讀取多於MAX_INT16,將編輯修復。我很確定它是一個有符號數的算術轉換,也是一個無符號數的邏輯轉換,雖然我可能再次出錯。希望有人會指出,如果我是。 – torak 2010-07-06 17:43:23

+0

@ShinTakezou:移動負整數的行爲是實現定義的,實際上這意味着算術或邏輯移位,取決於所討論的體系結構中最簡單的移位。 – caf 2010-07-07 01:09:11

0

該代碼的意圖可能是四捨五入的,如其他答覆中所示。但這當然是一個非常糟糕的例子。有兩件事情怎麼回事,原來的程序員可能沒有打算:

  • 推廣int並重新分配給int16_t
  • signed

推廣到int的轉變(因爲+2這只是一個int)在這裏不好,因爲你不知道任何隨機平臺上的int的精度是多少,你碰巧登陸。

signed值的右移是編譯器相關的,如果該值爲負,所以結果可能會發生變化因平臺,太。

+0

對「int」的提升並不算太壞,因爲int必須至少是16位。但是,如果輸入的樣本是32766或32767,推廣到「長期」會更好,以避免溢出問題。 – caf 2010-07-07 01:12:00

+0

@caf:我不同意這種觀點,相反,這是一個非常討厭的問題錯誤類型。它讓你認爲代碼中的所有東西都可以正常工作,直到......有人在16位平臺上編譯它(當然,我知道這些天很少見)*和*遇到了'+2 '你有嚴重的撞車事故。非常討厭,無法調試。所以在這裏一個必要的強制轉換是必須的,我會這樣做來使int32_t成爲一致的。 (就像我剛纔所說的那樣,更改類型爲'unit..') – 2010-07-07 06:00:26

+0

當結果被截斷爲14位時,升級和右移都沒有問題。無論如何,使用更長的數據類型將保留的位將被丟棄,就像未定義的位一樣。 我沒有看到「嚴重碰撞」儘可能;問題將是樣本會有效改變標誌。這可以在輸出中聽到,但如果樣本很大,那麼它可能會被剪切。 當然,抖動是正確的答案。 – janm 2010-07-07 09:20:41

1

正如其他人已經注意到的那樣,+2是一種嘗試使右轉向執行一輪到最近的分割。然而,存在兩個問題:

  • 的32766或32767輸入樣本可能溢出int當添加2(int只保證能夠表示數字高達32767);

  • 負數的右移行爲是實現定義的。

爲了避免這些問題,它應該是:

int16_t sample = (old_sample > 0 ? old_sample + 2L : old_sample - 2L)/4; 

(不同於移位運算符,在C99除法運算符被定義爲圓,向零)。