惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
L
LINUX DO - 热门话题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
博客园_首页
MongoDB | Blog
MongoDB | Blog
V
V2EX
GbyAI
GbyAI
量子位
Microsoft Azure Blog
Microsoft Azure Blog
有赞技术团队
有赞技术团队
G
Google Developers Blog
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
S
SegmentFault 最新的问题
O
OpenAI News
N
News and Events Feed by Topic
博客园 - Franky
爱范儿
爱范儿
Forbes - Security
Forbes - Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V2EX - 技术
V2EX - 技术
Application and Cybersecurity Blog
Application and Cybersecurity Blog
N
News and Events Feed by Topic
N
News | PayPal Newsroom
Schneier on Security
Schneier on Security
Cloudbric
Cloudbric
Security Archives - TechRepublic
Security Archives - TechRepublic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recent Commits to openclaw:main
Recent Commits to openclaw:main
人人都是产品经理
人人都是产品经理
P
Privacy International News Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
D
DataBreaches.Net
Last Week in AI
Last Week in AI
罗磊的独立博客
Spread Privacy
Spread Privacy
Recent Announcements
Recent Announcements
The Cloudflare Blog
Google DeepMind News
Google DeepMind News
AWS News Blog
AWS News Blog
The Register - Security
The Register - Security
Y
Y Combinator Blog
J
Java Code Geeks
I
Intezer

博客园 - 风中灵药

如何在mvc中共用一个dbconext以节省资源提高性能? asp.net core api路由及多语言切换的实现 安装win7 64位和win10 64位双系统小结 macbook装双系统多分区其实很简单,你只要把macbook当作一台普通pc就可以了! 个人对AutoResetEvent和ManualResetEvent的理解 关于WPF下ComBox的SelectionChanged事件 一条语句实现查询各类别前10条记录 【原】Sql2005 实现递归 【转】javascript操作cookies 以及 正确使用cookies的属性 回归: css, bug bug, background-repeat and frames 如何用oledb读取dbf(FoxPro表)文件? SQL注入中利用XP_cmdshell提权的用法(转) Sql 2005自动备份并自动删除3天前的备份 ActiveX开发心得(原创) 常用正则表达式(包括中文匹配) 使用ASP.NET Global.asax 文件(转) 如何不打开文件 直接出现下载保存提示框 Replace ntext类型中的文字 关于IFRAME 自适应高度的研究[转]
mp3转speex的一些研究(貌似不能播放,暂存着)
风中灵药 · 2017-03-31 · via 博客园 - 风中灵药

思路是,先从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);
            }
        }