我正在开发新的WindowsPhone平台。我有几个SoundEffectInstance,我想合并成一个新的单一声音文件(无论是SoundEffectInstance,SoundEffect或MediaElement,这并不重要)。然后,我想将该文件作为mp3保存到电话中。
我该怎么做?通常,我会尝试将所有文件发送到一个字节数组,但我不确定这是不是正确的方法,也不确定如何将字节数组转换为MP3格式的声音。
例如,我有SoundEffectInstance soudBackground,播放时间为0-5秒。然后我让SoundEffectInstance铃声播放3-4秒,SoundEffectInstance前台播放3.5到7秒。我想将所有这些合并到一个持续7秒的mp3文件中。
发布于 2011-12-20 23:53:28
这里有两个您要尝试完成的任务:
到目前为止,我发现你在使用第二项时会遇到一些挑战。到目前为止,我还没有找到一个纯.Net MP3编码器。我找到的所有方法都依赖于原生代码的P/Invoke(这当然不能在手机上工作)。
至于组合这些文件,您不希望将它们视为SoundEffectInstance。该类仅用于播放,它将声音文件的大部分细节抽象化。相反,您需要将声音文件视为int数组。我将假设所有三个声音文件的采样率是完全相同的,并且这些都是16位录音。我还将假设这些wave文件是以单声道录制的。我现在让场景变得简单。在掌握了这个更简单的场景之后,您可以使用立体声和各种采样率对其进行扩展。
wave文件的前48个字节只是标题。跳过这个部分(现在),将wave文件的内容读入它们自己的数组中。一旦它们都读完了,我们就可以开始把它们混合在一起了。忽略你想要开始播放这些声音的时间差,如果我们想要开始产生一个样本,这是所有三个声音的组合结果,我们可以通过将声音文件数组中的值加在一起,并将其写到一个数组中来保存我们的结果。但是有一个问题。16位数字只能上升到32,767 (下降到-32,768)。如果这三种声音的总和超过了这些限制,你就会得到非常严重的失真。处理此问题的最简单(但不一定是最好)方法是考虑将播放的最大同时声音数,并相应地缩小这些值。从3.5秒到4秒,您将播放所有三种声音。因此,我们将通过除以3来进行缩放。另一种方法是使用可以超出此范围的数据类型对声音样本进行求和,然后在完成将它们混合在一起时将值归一化到此范围。
让我们定义一些参数。
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来确保结果数组中填充了0(我相信它是默认的,但我仍然喜欢显式地将它设置为0),然后为您希望在结果中包含的每个声音调用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
https://stackoverflow.com/questions/8375149
复制相似问题