簡體   English   中英

如何將SoundEffectInstances組合到新的聲音文件/ mp3或wav中

[英]How to combine SoundEffectInstances into a new Sound File /mp3 or wav

我正在使用新的WindowsPhone平台。 我想將SoundEffectInstance的一些實例合並成一個新的單個Sound文件(SoundEffectInstance,SoundEffect或MediaElement都沒關系。)然后我將該文件另存為mp3。

我怎么做? 通常,我會嘗試將所有文​​件發送到字節數組,但是我不確定這是否是正確的方法,或者如何將字節數組轉換為MP3格式的聲音。

例如,我有SoundEffectInstance soudBackground,播放時間為0-5秒。 然后,我會在3-4秒內播放SoundEffectInstance鈴聲,並在3.5秒至7秒之間播放SoundEffectInstance前景。 我想將所有這些組合到一個持續7秒的mp3文件中。

您要在此處完成兩個任務:

  • 將多個聲音文件合並為一個聲音文件
  • 將結果文件另存為MP3。

到目前為止,我發現第2項將面臨很多挑戰。到目前為止,我還沒有找到純的.Net MP3編碼器。 我發現的所有代碼都依賴於P / Invokes來編寫本機代碼(這當然在電話上不起作用)。

至於合並文件,您不想將它們視為SoundEffectInstance。 該類僅用於播放,並且將聲音文件的大多數細節抽象掉了。 相反,您將需要將聲音文件視為整數數組。 我將假設所有三個聲音文件的采樣率完全相同,並且這些都是16位錄音。 我還將假設這些wave文件記錄為單聲道。 我現在使情況保持簡單。 掌握了這種簡單方案之后,您就可以擴展立體聲和各種采樣率。

Wave文件的前48個字節不過是標頭。 跳過(暫時),然后將wave文件的內容讀入它們自己的數組中。 閱讀完所有內容后,我們就可以開始將它們混合在一起。 如果我們想開始產生一個采樣,這是所有三個結果的總和,那么忽略您要開始播放這些聲音的時差,我們可以通過將聲音文件數組中的值加在一起並將其寫到數組中來實現。保持我們的結果。 但是有一個問題。 16位數字最多只能增加32,767(向下最多-32,768)。 如果這三種聲音的總和超過這些限制,則失真會非常嚴重。 處理此問題的最簡單(盡管不一定是最佳方法)是考慮同時播放聲音的最大數量,並相應地縮小這些值。 從3.5秒到4秒標記,您將同時播放所有三種聲音。 因此,我們將除以三。 另一種方法是使用可以超出此范圍的數據類型對聲音樣本求和,然后在將它們混合在一起后將值歸一化為該范圍。

讓我們定義一些參數。

int SamplesPerSecond = 22000;
int ResultRecordingLength = 7;
short[] Sound01;
short[] Sound02;
short[] Sound03;
int[] ResultantSoundBuffer;
short[] ProcessedResultSoundBuffer;

//Insert code to populate sound array's here. 
// Sound01.Length will equal 5.0*SamplesPerSecond
// Sound02.Length will equal 1.0*SamplesPerSecond
// Sound03.Length will equal 3.5*SamplesPerSecond

ResultantSound = new int[ResultRecordingLength*SamplesPerSecond];

讀取完聲音文件並准備好接收結果文件的陣列后,就可以開始渲染了。 有幾種方法可以解決此問題。 這是一個:

void InitResultArray(int[] resultArray)
{
   for(int i=0;i<resultArray.Length;++i)
   {
      resultArray[i]=0;
   }
}

void RenderSound(short[] sourceSound, int[] resultArray, double timeOffset)
{
   int startIndex = (int)(timeOffset*SamplesPerSecond);
   int readIndex = 0;
   for(int readIndex=0;((readIndex<sourceSound.Length)&&(readIndex+sourceSound<resultArray.Length;++readIndex)
   {
      resultArray[readIndex+startIndex] += (int)sourceSound[readIndex];
   }
}

 RangeAdjust(int[] resultArray)
{
   int max = int.MinimumValue;
   int min = int.MaximumValue;
   for(int i=0;i<resultArray;++i)
   {
     max = Math.Max(max, resultArray[i]);
     min = Math.Min(min, resultArray[i]);
   }
   //I want the range normalized to [-32,768..32,768]
   //you may want to normalize differently.
   double scale = 65536d/(double)(max-min);
   double offset = 32767-(max*scale);
   for(int i=0;i<resultArray.Length;++i)
   {
      resultArray[i]= (scale*resultArray[i])+offset;
   }
}

您將調用InitResultAttay以確保結果數組填充有零(我相信默認情況下是,但我仍然希望將其顯式設置為零),然后為結果中想要的每種聲音調用RenderSound()。 渲染聲音后,請調用RangeAdjust來標准化聲音。 剩下的就是將其寫入文件。 您需要從整數轉換為短褲。

short[] writeBuffer = new short[ResultantSound.Length];
for(int i=0;i<writeBuffer.Length;++i)
   writeBuffer[i]=(short)ResultantSound[i];

現在,混合聲音已准備就緒,可以寫入文件了。 缺少一件事,您需要在寫入文件之前先寫入48字節的wave標頭。 我已經在此處編寫了有關如何執行此操作的代碼: http : //www.codeproject.com/KB/windows-phone-7/WpVoiceMemo.aspx

暫無
暫無

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

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