2013-08-26 69 views
0

在Flash中生成聲波時,我遇到以下問題。 這是發電機部分:刪除AS3中生成的聲音中未激發的點擊

const SAMPLING_RATE:int = 44100; 
const TWO_PI:Number = 2 * Math.PI; 
const TWO_PI_OVER_SR:Number = TWO_PI/SAMPLING_RATE; 
const SAMPLE_SIZE:int = 8192/4; 


function generateSine(fq:Number):ByteArray 
{ 
var bytes:ByteArray = new ByteArray(); 
var sample:Number; 
var amp:Number = 1; 


for (var i:int=0; i<SAMPLE_SIZE; i++) 
{ 
    sample = amp* Math.sin(i * TWO_PI_OVER_SR * fq ); 
    bytes.writeFloat(sample); 
} 


bytes.position = 0; 
return bytes; 
} 

,這是播放部分:

function playbackSampleHandler(event:SampleDataEvent):void 
{ 
var sample:Number; 

for (var i:int = 0; i < SAMPLE_SIZE && soundData.bytesAvailable; i++) 
{ 
    sample = soundData.readFloat(); 
    event.data.writeFloat(sample); 
    event.data.writeFloat(sample); 
} 
} 



function onClickPlay(e:MouseEvent) 
{ 
soundData= new ByteArray(); 
    var sound:ByteArray= new ByteArray(); 
    sound=generateSine(440); 
soundData.writeBytes(sound,0,sound.length); 
soundData.position = 0; 
morphedSound.addEventListener(SampleDataEvent.SAMPLE_DATA, playbackSampleHandler); 
soundChannel = morphedSound.play();    
} 

快速解釋: 我基本上寫爲正弦函數到ByteArray和比再現處理程序的值讀出該陣列並播放聲音。我只寫了一個8192/4採樣緩衝區。

問題: 我的問題是,當你這樣做時,在聲音結束時出現令人討厭的點擊,這是正弦波被非0值切割的僞像。所以我的問題是如何避免這種情況?

Bonus: 我也想知道如何在Flash中的緩衝區非常嚴格時(例如從2048到8192)生成正弦波100毫秒的正弦波?

鏈接: 如果它幫助我的代碼是基於本教程 http://www.bit-101.com/blog/?p=2669 和我自己的探索。

+0

我注意到downvote,我不介意,但我不知道爲什麼有人低估了這個,因爲問題是非常詳細的包括代碼,它顯示了研究工作?如果有人指出如何更好地提出這個問題,或者如果它是重複的,請發表評論。 – PSIXO

回答

1

您需要保留樣本數據處理結束時出現的正弦波的相位。否則,你的正弦波不能順利地繼續,你會得到你所說的點擊。

var totalSamples:int=0; 
function generateSine(fq:Number):ByteArray 
{ 
var bytes:ByteArray = new ByteArray(); 
var sample:Number; 
var amp:Number = 1; 


for (var i:int=0; i<SAMPLE_SIZE; i++) 
{ 
    sample = amp* Math.sin((i+totalSamples) * TWO_PI_OVER_SR * fq ); 
    // this uses stored phase ^^^ 
    bytes.writeFloat(sample); 
} 
totalSamples+=SAMPLE_SIZE; // this preserves phase between subsequent samples 

bytes.position = 0; 
return bytes; 

}

更新:我注意到你連續兩次調用發電機 - 這是可怕的。如果你只需要一個工作結果,你就不能兩次調用一個函數。

function onClickPlay(e:MouseEvent) soundData = generateSine(440); //爲什麼使用writeBytes如果我們只能使用賦值? soundData.position = 0; morphedSound.addEventListener(SampleDataEvent.SAMPLE_DATA,playbackSampleHandler); soundChannel = morphedSound.play();
}

此外,爲了使聲音的全(半)波的聲音將其取出最後單擊所需,使用這種技術:

function generateSine(fq:Number,cleanFinish:Boolean=false):ByteArray 
{ 
var bytes:ByteArray = new ByteArray(); 
var sample:Number; 
var amp:Number = 1; 


for (var i:int=0; i<SAMPLE_SIZE; i++) 
{ 
    sample = amp* Math.sin((i+totalSamples) * TWO_PI_OVER_SR * fq ); 
    // this uses stored phase ^^^ 
    bytes.writeFloat(sample); 
    if (cleanFinish) 
     if ((Math.abs(sample)<(SAMPLING_RATE/fq/3))&&(i>SAMPLE_SIZE-SAMPLING_RATE/fq)) break; 
    // this triggers a drop if we are sampling the last wave already 
} 
totalSamples+=i; // this preserves phase between subsequent samples 

bytes.position = 0; 
return bytes; 

}

調用此函數將可選的布爾參數設置爲true以接收正確終止的波形。

+0

謝謝你的幫助。那麼這確實解決了問題的一部分,但仍然令人討厭的點擊聲音結束。所以問題實際上是我該如何才能在Math.sin(x)= 0時結束聲音? – PSIXO

+0

好的,你必須截斷你的ByteArray到最後一個大約零位,或者指示發生器至少在你請求它結束時產生完整的正弦波。 – Vesper

+0

謝謝!我正在嘗試第一種截斷方法,並逐漸降低體積,使樣品結束,這給了我良好的結果。我將如何做另一種方法來指示只產生全波? – PSIXO

0

「樣品」的所有SAMPLE_SIZE值必須以三片進行分割: 第一個和所述第三片必須具有每250個值和中間的一個 其餘:SAMPLE_SIZE - 500將這個如下: 生成一個在步驟.004之間,在0和.996之間的250個值的數組: 我的意思是:.000,.004,.008,...,.996,並用它們填充一個數組,例如mod [i] 從0到249.(mod用於調製...) 修改如下所示的初始循環,從而導致從0到(+/-)放大器的衰減(前250個值),然後剩餘的值直到最後250保持(+/-)放大器,最後,最後250個值從(+/-)放大器衰減到0.糟糕的點擊仍然是......歷史!我希望這個幫助。

function generateSine(fq:Number):ByteArray 
{ 
    var bytes:ByteArray = new ByteArray(); 
    var sample:Number; 
    var amp:Number = 1; 


for (var i:int=0; i< 250; i++) 
    { 
     sample = amp* Math.sin(i * TWO_PI_OVER_SR * fq ) * mod[i]; 
     bytes.writeFloat(sample); 
    } 

    for (var i:int=250; i<SAMPLE_SIZE - 250; i++) 
    { 
     sample = amp* Math.sin(i * TWO_PI_OVER_SR * fq ); 
     bytes.writeFloat(sample); 
    } 

    for (var i:int=SAMPLE_SIZE - 250; i<SAMPLE_SIZE; i++) 
    { 
     sample = amp* Math.sin(i * TWO_PI_OVER_SR * fq ) * (.996 - mod[i]); 
     bytes.writeFloat(sample); 
    } 


    bytes.position = 0; 
    return bytes; 
}