签到

06月20日
尚未签到

共有回帖数 0

    幻梦如戏

    等级:




    其实说到mp3播放,其实听上去似乎真没有什么技术含量,因为很多的人都做过mp3播放器,而且90%都是拖控件或者直接调用第三方的一个play,似乎简简单单轻轻松松,不信可以去易语言吧或者vb之类的吧里去看看,一大票人自以为拖了一个wmp就能逆天做个千千静听了,其实音乐编程绝不像你想象中的那么简单,同样和图形学一样涉及一大票的数学物理知识,不过也不像Graphics编程,没有充实的线代老底会变得痛不欲生。
    不过为了达到普及知识的目的,本菜菜决定将本章节分为两个部分,第一部分我已经为初学者们封装好了一个类,想尝鲜又觉得深究有困难的朋友可以直接调用这个类,简简单单的一个play就可以播放一个mp3,第二部分就送给那些老鸟但没接触过音乐解码的朋友们,本菜菜将会讲解libmad的解码流程与一些该注意的细节,并粗略讲解下mp3的解码原理
    阅读须知
    1.当然,第一部分你不需要任何基础,但阅读第二部分请阅读本菜菜的part1,在那里讲解了一系列必要的音频基础
    2.基于directX SDK你懂的
    3.做教程要求深入浅出,本菜菜尽量以最大可能把代码写的尽可能简单尽可能短尽可能的少调用那些奇葩的API与模板,但尽管如此,阅读仍需要一些基础,不仅仅是编程方面的
    4.本章开放完整源代码
    5.老样子在线直播,所以更新较慢,稍安毋躁

    1.#include "Mp3Audio.h"
    2.实例化 CMp3Audio mp3Audio;
    3.打开文件 mp3Audio.open(char *FileName);
    4.播放 mp3Audio.play(窗口句柄);

    第一部分讲完了,因为关键代码就这么长......将我的类包含在项目中,然后设置包含libmab.lib的目录到你的项目中就完了,代码将在本章节结束后最后一楼发布
    第二部分
    就像我们当年mp4还卖到五六百块的年代,最广泛支持的格式就是avi了,而网上流行的都是rmvb rm格式,怎么办,格式转换,转换成这种大部分mp4都支持的格式....,其实以此类推,无非就是要有一个标准,这个标准的码流是公认的必须被支持的,至于你要做什么格式是你的事,反正最终传输到音频设备上的必须是这种公认的编码格式,在音频编程中,这种大家公认的编码叫PCM,不管你是mp3也好,wma也好,ape也好,最终都要变成PCM,这也就是解码的由来,本章节也是基于这种思想之上的
    为什么用libmad
    1.首先它是开源的
    2.工业级标准,不管你是M$的粉丝还是linuxer(实际上libmad这种命名不就是linux的习惯吗)它甚至还可以移植到你的win mobile或单片机上
    3.mp3解码我就只用过这个

    说说libmad
    它是开源的,你可以直接看它的源代码,代码写的又骚又浪而且极为精炼,该有的都有,不该有的都没有,注释不多,意思是这些代码没啥技术含量你都懂的,当然libmad是一个无需置疑的一个灰常优秀的解码库。
    但是网上的资料却不多,大都是你抄我的我抄你的,抄来抄去发现其实就这么几篇,然后经过懂的的不大懂各种修改各种跳大神,好好的代码面目全非,看那些代码让人感觉用lidmad解码真是玄之又玄,还好原作者留了一个demo,才让人茅塞顿开,最后发现,原来是那么简单的一回事
    不过在讲解libmad之前,你需要了解一下mp3文件的格式
    和wav格式不同,wav格式就像是流水,但mp3就像是传送带上一个一个的块,wav格式有一个header来告诉你 bitrate samplerate 和channels,但是mp3没有,所以用mp3的第一帧来记录这些信息,每一个帧都带有一个帧头占地32字节,当然制定mp3的专家组都是抠门鬼,32直接还省着用,所以这32直接是一个位域,提取数据必须要运用到位操作,但这点我们无需担心,因为libmad已经为我们做好了一切了
    那么如何用libmad进行解码,其实大部分基于libmad的音频播放器的算法大概可以归结成如下
    1.打开一个文件
    2.从文件中读取一段数据(读多少看你心情)
    3.libmad有一个专门的stream,用一个函数将那段数据和这个数据绑定起来
    4.解码,将那个数据中包含的帧一帧一帧地解码出来,到后面常常发现省下的数据不够构成一帧,libmad抛出一个特定的ERROR_BUFLEN错误,然后它会告诉你指向这个残缺数据第一个直接的指针与剩余数据的大小,之后你需要把这段残缺的数据保存起来,然后再从文件中读取数据与之拼接成完整帧,然后继续解码
    5.将解码好的数据送到你的pcmbuffer中,这里你要注意一下Endian的问题,win要big endian
    unix 和linux要 little endian
    6。播放
    好了,现在说说libmad,虽说音频编程不简单但是用libmad只要理解出奇的简单,我们不跳大神长话短说,现在我也困的要死急着睡觉
    首先,创建一个基于libmad的项目我还是建议你
    #include "libmad.h"并pragma comment(lib,"libmad.lib")
    当然你也可以将整个libmad包含在你的项目中重新编译一遍,毕竟他是开源的
    我们用到以下几个变量










    mad_synth_frame这个函数,可以看到, 它将Frame里的数据合成到synth当中,当然别忘了,假如这是第一个解码出来的帧,帧头部可是保存着我们需要的数据的,因此下面的代码中我们提取这些关键的数据,待会我们需要用这个m_sampleRate和m_Channels这两个来创建一个soundbuffer以让音乐正确播放
    那么如何提取当中的pcm数据呢
    通过
    int SampleCount=Synth.pcm.length;我们可以得到解码后pcm数据的长度
    而这个
    ch1 = Synth.pcm.samples[0] ;//声道1的数据
    ch2 = Synth.pcm.samples[1] ;//声道2的数据
    这是两个声道的数据,我们需要将他放到一个一维数组中,这里涉及到了endian的问题
    在代码中我使用了RenderPCM这个函数将数据合成到一个m_PCMBuffer中,代码有点长,请看源代码
    最后,我们得到了音频播放的数据和一个pcmBuffer,之后就是创建Soundbuffer了






    楼主 2015-11-12 20:42 回复

共有回帖数 0
  • 回 帖
  • 表情 图片 视频
  • 发表

登录直线网账号

Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号 意见反馈 | 关于直线 | 版权声明 | 会员须知