MP3解码详解(还清高高手指点)

在网上看了很多的说法,但是还是有点模糊,涉及到很多的数学公式和他的存储方式

我也是在网上找到的资料,根大家分享一下,本人编译并执行成功过。如果涉及到侵权,本人马上删除。

首先说一下读取PCM格式的音频播放:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include<sys/soundcard.h>


//wav format
typedef struct _WAVEFILE_HEADER//波形文件头结构体
{
        char ChunkID[4];      //"RIFF"
        long int ChunkSize;      //整个文件大小-8bytes
        char Format[4];          //"wave"
        char Subchunk1ID[4];  //"fmt" 表示以下是format chunck
        long int Subchunk1Size;  //格式数据的字节数 一般是16,特殊的也有18
        short AudioFormat;    //编码方式
        short NumChannels;    //声道数量
        long int SampleRate;        //采样率
        long int ByteRate;           //每秒所需字节数
        short BlockAlign;        //每次采样需要的字节数
        short BitsPerSample;     //每个采样需要的bit数
        char Subchunk2ID[4];     //'data'字符串,标识以下是数据
        long Subchunk2Size;      //数据的大小

}WAVEFILE_HEADER;


///安装dsp  设置   采样率   声道个数
int setup_dsp(int dsp_fd,int rate,int channels)
{
 int format;
int tmpchannels=2;
int tmprate = 44100;
 if( ioctl(dsp_fd, SNDCTL_DSP_STEREO, &tmpchannels) == -1 ) //SOUND_PCM_WRITE_CHANNELS
 {
  perror("ioctl sterr failed");
  return -1;
 }
 
 switch(tmpchannels)
 {
  case 0:
   format = AFMT_U8;
   printf("format = %d\n", AFMT_U8);
   break;
  case 1:
  case 2:
   format = AFMT_S16_LE;
   printf("format = %d\n", AFMT_S16_LE);
   break;
  default:
   perror("unsuport channels");
   return -1;
 }

 if(ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)//SOUND_PCM_WRITE_BITS
 {
  perror("ioctl set formalt");
  return -1;
 }
 if(ioctl(dsp_fd, SNDCTL_DSP_SPEED, &tmprate) == -1)//SOUND_PCM_WRITE_RATE
 {
  perror("ioctl set_speed failed");
  return -1;
 }
 return 0;
}

///设置同步播放
int sync_dsp(int dsp_fd)
{
 if(ioctl(dsp_fd, SNDCTL_DSP_SYNC) != 0)
 {
  perror("ioctl sync failed");
  return -1;
 }
 return 0;
}


int play_music(char* music_name )
{
 WAVEFILE_HEADER head;
 FILE* music_fp;
 int music_len;
 long rate;
 char* buf;
 long n;
 int dsp_fd;

 //打开 alarm.wav音乐文件music_name
 music_fp = fopen("15.wav", "rb");
 if(music_fp == NULL)
 {
  perror("fopen music file failed");
  return -1;
 }
 //读取音乐文件头
 if(fread(&head,sizeof(head),1,music_fp) != 1 )
 {
  perror("fread head err");
  return -1;
 }
 printf("ChunkID=%s, ChunkSize=%ld, Format=%s, \
Subchunk1ID=%s \nSubchunk1Size=%ld, AudioFormat=%d, \
NumChannels=%d, SampleRate=%ld, \nByteRate=%ld, BlockAlign=%d, \
BitsPerSample=%d, Subchunk2ID=%s, Subchunk2Size=%ld\n",\
   head.ChunkID, head.ChunkSize, head.Format, \
   head.Subchunk1ID, head.Subchunk1Size, head.AudioFormat, \
   head.NumChannels, head.SampleRate, head.ByteRate, \
   head.BlockAlign, head.BitsPerSample, head.Subchunk2ID, head.Subchunk2Size);
 //验证文件头
 /*if(memcmp(&head.ChunkID,"RIFF",4) != 0 )
 {
  perror("music head chunkId err");
  return -1;
 }

 //验证比特率
 if(head.BitsPerSample == 24)
 {
  perror("unsuport samply size ");
  return -1;
 }*/
 //music_len = head.ChunkSize+8;
  music_len = 35039456+8;
 printf("music_len :%d\n",music_len);
 
 //打开声卡
 dsp_fd = open("/dev/dsp",O_WRONLY);
 if(dsp_fd< 0)
 {
  perror("open dsp err");
  exit(0);
 }

 ///安装dsp  设置  采样率   声道个数
 if(setup_dsp(dsp_fd,head.SampleRate,head.NumChannels) != 0)
 {
  perror("setup_dsp failed");
  return -1;
 }

 生效setup_dsp设置
 if(sync_dsp(dsp_fd) != 0)
 {
  perror("sync dsp failed");
  return -1;
 }

 //-----设置采样率--------
    //采样位数*采样率/8 =  字节数量
    //+7 方式采样率不是8的整数倍的情况
    //  /8*2 = /4 都按照双声道处理
    //size =  (head.BitsPerSample*head.SampleRate+7)>>2;

     //rate = head.ByteRate; //每次读取的字节 = 字节速率
 //rate = head.SampleRate * head.BitsPerSample * head.NumChannels >>2;
 rate = 352800;
    buf = (char*)malloc(rate); //音乐数据缓存
 printf("rate:%ld\n", rate);

 //打印需要播放的总时间
 //printf("music time:%d\n",head.Subchunk2Size/head.ByteRate);
 
 if(buf != NULL)
 {
  //int i = 10;
  do{
  
   n = fread(buf, 1, rate, music_fp);
   printf("n:%ld\n",n);
   if(n > 0)
   {
    write(dsp_fd, buf, n);
   }
   
   if(feof(music_fp))
   {
    printf("play over!\n");
    break;
   }
  
  }while(1);
  fclose(music_fp);
 }
 
}


int main(int argc,char** argv)
{

 play_music(argv[1]);
 
 return 0;
}

 

接下来是MP3的解码程序:

显示解码表dewindow.txt

D[  0]= 0.000000000 D[  1]=-0.000015259 D[  2]=-0.000015259 D[  3]=-0.000015259
 
D[  4]=-0.000015259 D[  5]=-0.000015259 D[  6]=-0.000015259 D[  7]=-0.000030518
 
D[  8]=-0.000030518 D[  9]=-0.000030518 D[ 10]=-0.000030518 D[ 11]=-0.000045776
 
D[ 12]=-0.000045776 D[ 13]=-0.000061035 D[ 14]=-0.000061035 D[ 15]=-0.000076294
 
D[ 16]=-0.000076294 D[ 17]=-0.000091553 D[ 18]=-0.000106812 D[ 19]=-0.000106812
 
D[ 20]=-0.000122070 D[ 21]=-0.000137329 D[ 22]=-0.000152588 D[ 23]=-0.000167847
 
D[ 24]=-0.000198364 D[ 25]=-0.000213623 D[ 26]=-0.000244141 D[ 27]=-0.000259399
 
D[ 28]=-0.000289917 D[ 29]=-0.000320435 D[ 30]=-0.000366211 D[ 31]=-0.000396729
 
D[ 32]=-0.000442505 D[ 33]=-0.000473022 D[ 34]=-0.000534058 D[ 35]=-0.000579834
 
D[ 36]=-0.000625610 D[ 37]=-0.000686646 D[ 38]=-0.000747681 D[ 39]=-0.000808716
 
D[ 40]=-0.000885010 D[ 41]=-0.000961304 D[ 42]=-0.001037598 D[ 43]=-0.001113892
 
D[ 44]=-0.001205444 D[ 45]=-0.001296997 D[ 46]=-0.001388550 D[ 47]=-0.001480103
 
D[ 48]=-0.001586914 D[ 49]=-0.001693726 D[ 50]=-0.001785278 D[ 51]=-0.001907349
 
D[ 52]=-0.002014160 D[ 53]=-0.002120972 D[ 54]=-0.002243042 D[ 55]=-0.002349854
 
D[ 56]=-0.002456665 D[ 57]=-0.002578735 D[ 58]=-0.002685547 D[ 59]=-0.002792358
 
D[ 60]=-0.002899170 D[ 61]=-0.002990723 D[ 62]=-0.003082275 D[ 63]=-0.003173828
 
D[ 64]= 0.003250122 D[ 65]= 0.003326416 D[ 66]= 0.003387451 D[ 67]= 0.003433228
 
D[ 68]= 0.003463745 D[ 69]= 0.003479004 D[ 70]= 0.003479004 D[ 71]= 0.003463745
 
D[ 72]= 0.003417969 D[ 73]= 0.003372192 D[ 74]= 0.003280640 D[ 75]= 0.003173828
 
D[ 76]= 0.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: HTML5 青蛙跳高高游戏源码是一个基于HTML5和JavaScript编写的简单Web游戏。玩家控制一只青蛙,跳跃并躲避障碍物,最终达到最高分数。 游戏的核心代码是一个事件监听器,当玩家按下空格键时,青蛙将跳跃。同时,一个计时器将启动,随着时间的推移使障碍物不断上升,难度逐渐增加。 游戏的图形界面使用了HTML5 Canvas元素,它可以直接绘制图形和动画。青蛙和障碍物都是用Canvas绘制出来的。 源码中还包括一些常用的JavaScript库,如jQuery和Bootstrap。这些库可以使开发者更快地完成游戏开发,并提供更好的用户体验。 除了游戏逻辑和界面外,源码还包括一些CSS样式表,用于美化游戏页面的外观。例如,游戏中使用了动画效果来增强用户交互体验。 总之,HTML5 青蛙跳高高游戏源码是一个简单而有趣的Web游戏,可以帮助开发者了解HTML5和JavaScript的基本语法和技术,并提供了一个入门级别的项目作为参考。 ### 回答2: 为了学习html5游戏开发,我寻找了一些简单的游戏源码来进行学习和实践,其中第一个选择的就是青蛙跳高高游戏的源码。 青蛙跳高高游戏的源码包括HTML、CSS和JavaScript三个文件,非常简洁明了。其中HTML文件定义了游戏窗口的样式和布局,CSS文件则定义了游戏中各个元素的样式,如青蛙、平台、背景等。JavaScript文件则包括游戏的核心逻辑和交互实现。 游戏玩法很简单,玩家需要控制青蛙跳上一些不断上升的平台,不断跳跃升高并尽可能长时间地生存下去。游戏中还加入了一些随机道具和加成效果来增加游戏乐趣和挑战性。 值得一提的是,这个游戏源码设计非常合理,代码结构清晰,易于扩展和维护。同时,它还应用了一些常用的HTML5技术,如Canvas和Audio等,使得游戏在表现和效果上都很出色。 总的来说,这个青蛙跳高高游戏的源码适合初学者进行练手和学习,也可以作为进一步深入HTML5游戏开发的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值