2009-12-16 55 views
3

我想上傳一個8000hz,16位wav文件到AS3中的11025hz。在這一點上,我不關心應用我最終需要的低通濾波器。我是referencing this wiki page如何上傳使用AS3的wav文件?

以下是我迄今所做的:

  1. 計算最小公倍數是3528000
  2. 計算L達到441
  3. 計算值M是320
  4. 新增440個零樣本之間
  5. 每320個樣本寫入一個新的字節數組

但是,當我去玩新的wav時,它是無法區分的噪音。這裏是我的代碼:

const sourceRate:uint = 8000; 
const targetRate:uint = 11025; 
var lcm:uint = lcm(targetRate, sourceRate); // = 3528000 
var l:uint = lcm/sourceRate; // = 441 
var m:uint = lcm/targetRate; // = 320 

// upsample by factor of l 
var upsampleData:ByteArray = new ByteArray(); 
upsampleData.endian = Endian.LITTLE_ENDIAN; 

// originalWavData is a ByteArray of the source wav data 
// fill is a ByteArray that contains 440 zeroes, written using writeShort(0x0) 

while(originalWavData.bytesAvailable > 1) { 
    upsampleData.writeBytes(fill); 
    upsampleData.writeShort(originalWavData.readShort()); 
} 

// downsample by factor of m 
var downsampleData:ByteArray = new ByteArray(); 
downsampleData.endian = Endian.LITTLE_ENDIAN; 

upsampleData.position = 0; 

for(var k:uint=0; k<upsampleData.length; k++) { 
    upsampleData.position = k * m; 
    if(upsampleData.bytesAvailable < 2) break; 
    downsampleData.writeShort(upsampleData.readShort()); 
} 

任何人都可以告訴我我在做什麼錯在我的代碼?這是我的第一個問題,所以如果我忘記了一些東西,或者需要提供更多信息,請告訴我。

謝謝!

更新:

我簡單化ARIC的回答,我現在使用下面的代碼成功上採樣:

/** 
* Generates a ByteArray containing numSamples of 
* data using linear interpolation between points 
* y0 and y1. 
*/ 
function interpolate(y0:int, y1:int, numSamples:uint):ByteArray { 
    var b:ByteArray = new ByteArray(); 
    b.endian = Endian.LITTLE_ENDIAN; 
    var m:Number = Math.round((y1-y0)/numSamples); 
    for(var i:uint=0; i<numSamples; i++) { 
     var n:int = m * i + y0; 
     b.writeShort(n); 
    } 
    b.position = 0; 
    return 0; 
} 

// upsample by factor of l 
var n1:int = 0; 
while(originalWavData.bytesAvailable > 1) { 
    var sample:int = originalWavData.readShort(); 
    upsampleData.writeBytes(interpolate(n1, sample, (l-1))); 
    n1 = sample; 
} 

// downsample by factor of m 
while(upsampleData.bytesAvailable > 1) { 
    downsampleData.writeShort(upsampleData.readShort()); 
    upsampleData.position += ((m-1)*2); 
} 

有兩件事情需要注意此解決方案:我上採樣的音頻驗證碼,所以音質不是非常重要。此外,第一個樣本只是沉默,所以我不需要計算第一個樣本左側的值。這就是爲什麼n1最初等於0的原因。另外,我並沒有將生成的樣本平均到我的下采樣中,而是隻抓取了每個M樣本,對我的目的來說聽起來很好。

我相信有1000個更好的方法來做到這一點,但爲了我所需要的,它的工作原理。再次感謝Aric的回答。

+0

加零會無疑產生不好的數據。嘗試將它看作一個圖像,並想象如果告訴您將圖像的水平分辨率提高到四倍,並且您在每個正常像素之間添加了3個黑色像素,將會怎樣?你需要看插值。我讀過的一種更好的方法是將聲音文件轉換到其頻率域,然後將其轉換回更高的分辨率。 – 2009-12-16 22:10:16

+0

感謝您的信息。我讀過同樣的東西。不幸的是,我對數字信號處理一無所知,並且關於FFT的閱讀(http://en.wikipedia.org/wiki/Fast_Fourier_transform)讓我更加困惑。你有什麼樣的例子/資源可以讓你瞭解DFT的基本知識,哪些不是?我理解轉換到頻域的概念,但我無法理解如何以更高的分辨率進行轉換。任何信息真的很感激。謝謝! – 2009-12-16 22:23:24

+0

當您試圖在維基百科進行該方法時,是否通過低通濾波器運行上採樣數據?我現在正在使用Aric的方法,但我對添加零點 - 然後過濾器方法感到好奇。 – 2010-12-12 04:53:01

回答

5

爲什麼要上取樣是否有特殊原因?上採樣不會給你更好的音頻,只是在CD上錄製手機對話會給你「CD質量」的音頻。

如果你真的想上取樣,那麼正如Lasse提到的那樣,不要只插入零。正如維基百科指出的那樣,您需要內插樣本的內容,上採樣到3528000Hz,然後下采樣回到11025Hz。

對於上採樣,一種方法是通過在每個點之間使用線算法。假設8 kHz記錄中的前三個採樣是:[15,25,33]。

要將這三個採樣上採樣到3528000 Hz,您需要輸出(441 * 3 = 1323)採樣。第220個樣本應該是15,第661個應該是25,而第1102個樣本應該是33.在點之間畫一條直線,你會得到一個體面的上樣。

一旦你這樣做了,你需要將你的1323個樣本降到4個樣本。第一個應該是樣本的平均值160-480,第二個是平均值481-800,第三個是平均值801-1160,第四個是平均值1161-1480。當然,你缺少樣本1324-1480,你可以用原始數據中的樣本#4生成樣本。

這應該至少讓你接近。但在你這樣做之前,問問你自己是否真的需要上樣。除非你使用一些只採用特定格式的奇怪軟件,否則最好還是給它提供你所擁有的數據。

+0

非常感謝您的回答。我明白,升頻不會提高質量。這就是我正在做的:我使用FreeTTS在中間層生成音頻驗證碼。我使用的聲音是8khz的聲音,這就是爲什麼我有一個8khz的wav文件。 Flash本身不會播放wav文件,所以我不得不在運行時生成SWF文件,並將wav文件嵌入生成的SWF文件中。 Flash只支持5512.5赫茲倍數的採樣率,所以我決定上採樣音頻客戶端(保存我們的應用服務器一些時鐘週期)。我用你的答案來解決問題。再次感謝! – 2009-12-17 16:32:01