思路是,先从mp3中提取pcm(raw原始数据),再将原始数据转成speex。
貌似不能播放,可能还存在其他问题,需要继续研究。
使用了两个类库NSpeex和NAudio
using (var waveStream = new NAudio.Wave.Mp3FileReader(@"D:\我的项目源码\Record\Record\bin\Debug\2.mp3")) { using (var fileOutputStream = new FileStream(@"D:\我的项目源码\Record\Record\bin\Debug\xxx.spx", FileMode.Create, FileAccess.Write)) { byte[] buff = new byte[waveStream.Length]; var r = waveStream.Read(buff, 0, buff.Length); var bytes = EncodeSpeech(buff, buff.Length); fileOutputStream.Write(bytes, 0, bytes.Length); } }
private static byte[] EncodeSpeech(byte[] buf, int len) { SpeexEncoder encoder = new SpeexEncoder(BandMode.Narrow); // set encoding quality to lowest (which will generate the smallest size in the fastest time) encoder.Quality = 1; int inDataSize = len / 2; // convert to short array short[] data = new short[inDataSize]; int sampleIndex = 0; for (int index = 0; index < len; index += 2, sampleIndex++) { data[sampleIndex] = BitConverter.ToInt16(buf, index); } // note: the number of samples per frame must be a multiple of encoder.FrameSize inDataSize = inDataSize - inDataSize % encoder.FrameSize; var encodedData = new byte[len]; int encodedBytes = encoder.Encode(data, 0, inDataSize, encodedData, 0, len); if (encodedBytes != 0) { // each chunk is laid out as follows: // | 4-byte total chunk size | 4-byte encoded buffer size | <encoded-bytes> | byte[] inDataSizeBuf = BitConverter.GetBytes(inDataSize); byte[] sizeBuf = BitConverter.GetBytes(encodedBytes + inDataSizeBuf.Length); byte[] returnBuf = new byte[encodedBytes + sizeBuf.Length + inDataSizeBuf.Length]; sizeBuf.CopyTo(returnBuf, 0); inDataSizeBuf.CopyTo(returnBuf, sizeBuf.Length); Array.Copy(encodedData, 0, returnBuf, sizeBuf.Length + inDataSizeBuf.Length, encodedBytes); return returnBuf; } else return buf; }
/// <summary> /// byte数组转short数组 /// </summary> /// <param name="bytes"></param> /// <returns></returns> private static short[] BytesToShorts(byte[] bytes) { //short[] data = new short[bytes.Length / 2]; //Buffer.BlockCopy(bytes, 0, data, 0, bytes.Length); //return data; //convert to short short[] data = new short[bytes.Length / 2]; int sampleIndex = 0; for (int index = 0; sampleIndex < data.Length; index += 2, sampleIndex++) { data[sampleIndex] = BitConverter.ToInt16(bytes, index); } return data; } /// <summary> /// 获取音频时长 /// </summary> /// <param name="voiceFile"></param> /// <returns></returns> private static int GetVoiceTimeLength(string voiceFile) { ShellClass sh = new ShellClass(); var dir = sh.NameSpace(Path.GetDirectoryName(voiceFile)); var item = dir.ParseName(Path.GetFileName(voiceFile)); string str = dir.GetDetailsOf(item, 27);// 获取歌曲时长。 if (!String.IsNullOrEmpty(str)) { var arr = str.Split(':'); var i = int.Parse(arr[0]) * 3600 + int.Parse(arr[1]) * 60 + int.Parse(arr[2]); return i; } else return 0; }
第二种获取时长方法
private static double GetVoiceTimeLength2(string voiceFile) { using (var waveStream = new NAudio.Wave.Mp3FileReader(voiceFile)) { return Math.Floor(waveStream.TotalTime.TotalSeconds); } }