分享

读取*.wav音频文件

 魔音工作室 2012-11-25
1、wav音频文件的格式

wav文件由文件头采样数据2部分组成。

文件头又分为RIFF(Resource Interchange File Format)、WAVE文件标识段 和 声音数据格式说明段组成。

各段的起始地址分别由RIFF标识符、WAVE标识符、以及波形格式标识符(FMT)标定。

(1)文件头格式

注意:下面的地址是连续的

(2)数据格式

虽然上图给出的数据标识符起始地址刚好是文件头的末地址+1,但并不代表总是这样。

因此,我们在读取数据时最好是找到数据标识符,该标识符的4个字节刚好是'd'、‘a’、‘t’、‘a’。

2、C语言读取wav文件

首先对一些类型使用了重定义

  1. typedef unsigned char uchar;
  2. typedef unsigned char uint8;
  3. typedef unsigned short uint16;
  4. typedef unsigned long uint32;
  5. typedef char sint8;
  6. typedef short sint16;
  7. typedef long sint32;
  8. typedef float fp32;
  9. typedef double fp64;
  10. typedef enum BOOLEAN
  11. {
  12. TRUE = 1,
  13. FALSE = 0
  14. } boolean;


(1)wav结构体定义

  1. //wave文件头
  2. typedef struct WaveHeader
  3. {
  4. uint8 riff[4]; //资源交换文件标志
  5. uint32 size; //从下个地址开始到文件结尾的字节数
  6. uint8 wave_flag[4]; //wave文件标识
  7. uint8 fmt[4]; //波形格式标识
  8. uint32 fmt_len; //过滤字节(一般为00000010H)
  9. uint16 tag; //格式种类,值为1时,表示PCM线性编码
  10. uint16 channels; //通道数,单声道为1,双声道为2
  11. uint32 samp_freq; //采样频率
  12. uint32 byte_rate; //数据传输率 (每秒字节=采样频率×每个样本字节数)
  13. uint16 block_align; //块对齐字节数 = channles * bit_samp / 8
  14. uint16 bit_samp; //bits per sample (又称量化位数)
  15. } wave_header_t;
  16. typedef struct WaveStruct
  17. {
  18. FILE *fp; //file pointer
  19. wave_header_t header; //header
  20. uint8 data_flag[4]; //数据标识符
  21. uint32 length; //采样数据总数
  22. uint32 *pData; //data
  23. } wave_t;
  24. wave_t wave;


(2)读取文件头信息

  1. /*
  2. * open *.wav file
  3. */
  4. void WaveOpen(char *file, int raw, int mono_stereo)
  5. {
  6. uchar temp = 0;
  7. uint8 read_bytes = 0;
  8. char *channel_mappings[] = {NULL,"mono","stereo"};
  9. uint32 total_time = 0;
  10. struct PlayTime //播放时间
  11. {
  12. uint8 hour;
  13. uint8 minute;
  14. uint8 second;
  15. } play_time;
  16. if(NULL == (wave.fp=fopen(file, "rb"))) /* open file */
  17. {
  18. printf("file %s open failure!\n", file);
  19. }
  20. /* read heade information */
  21. if(4 != fread(wave.header.riff, sizeof(uint8), 4, wave.fp)) /* RIFF chunk */
  22. {
  23. printf("read riff error!\n");
  24. return;
  25. }
  26. if(1 != fread(&wave.header.size, sizeof(uint32), 1, wave.fp)) /* SIZE : from here to file end */
  27. {
  28. printf("read size error!\n");
  29. return;
  30. }
  31. if(4 != fread(wave.header.wave_flag, sizeof(uint8), 4, wave.fp)) /* wave file flag */
  32. {
  33. printf("read wave_flag error!\n");
  34. return;
  35. }
  36. if(4 != fread(wave.header.fmt, sizeof(uint8), 4, wave.fp)) /* fmt chunk */
  37. {
  38. printf("read fmt error!\n");
  39. return;
  40. }
  41. if(1 != fread(&wave.header.fmt_len, sizeof(uint32), 1, wave.fp)) /* fmt length */
  42. {
  43. printf("read fmt_len error!\n");
  44. return;
  45. }
  46. if(1 != fread(&wave.header.tag, sizeof(uint16), 1, wave.fp)) /* tag : PCM or not */
  47. {
  48. printf("read tag error!\n");
  49. return;
  50. }
  51. if(1 != fread(&wave.header.channels, sizeof(uint16), 1, wave.fp)) /* channels */
  52. {
  53. printf("read channels error!\n");
  54. return;
  55. }
  56. if(1 != fread(&wave.header.samp_freq, sizeof(uint32), 1, wave.fp)) /* samp_freq */
  57. {
  58. printf("read samp_freq error!\n");
  59. return;
  60. }
  61. if(1 != fread(&wave.header.byte_rate, sizeof(uint32), 1, wave.fp)) /* byte_rate : decode how many bytes per second */
  62. { /* byte_rate = samp_freq * bit_samp */
  63. printf("read byte_rate error!\n");
  64. return;
  65. }
  66. if(1 != fread(&wave.header.block_align, sizeof(uint16), 1, wave.fp)) /* quantize bytes for per samp point */
  67. {
  68. printf("read byte_samp error!\n");
  69. return;
  70. }
  71. if(1 != fread(&wave.header.bit_samp, sizeof(uint16), 1, wave.fp)) /* quantize bits for per samp point */
  72. { /* bit_samp = byte_samp * 8 */
  73. printf("read bit_samp error!\n");
  74. return;
  75. }
  76. <span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">/* jump to "data" for reading data */
  77. do
  78. {
  79. fread(&temp, sizeof(uchar), 1, wave.fp);
  80. }
  81. while('d' != temp);
  82. wave.data_flag[0] = temp;
  83. if(3 != fread(&wave.data_flag[1], sizeof(uint8), 3, wave.fp)) /* data chunk */
  84. {
  85. printf("read header data error!\n");
  86. return;
  87. }
  88. </span>if(1 != fread(&wave.length, sizeof(uint32), 1, wave.fp)) /* data length */
  89. {
  90. printf("read length error!\n");
  91. }
  92. /* jduge data chunk flag */
  93. if(!StrCmp(wave.data_flag, "data", 4))
  94. {
  95. printf("error : cannot read data!\n");
  96. return;
  97. }
  98. total_time = wave.length / wave.header.byte_rate;
  99. play_time.hour = (uint8)(total_time / 3600);
  100. play_time.minute = (uint8)((total_time / 60) % 60);
  101. play_time.second = (uint8)(total_time % 60);
  102. /* printf file header information */
  103. printf("%s %ldHz %dbit, DataLen: %ld, Rate: %ld, Length: %2ld:%2ld:%2ld\n",
  104. channel_mappings[wave.header.channels], //声道
  105. wave.header.samp_freq, //采样频率
  106. wave.header.bit_samp, //每个采样点的量化位数
  107. wave.length,
  108. wave.header.byte_rate,
  109. play_time.hour,play_time.minute,play_time.second);
  110. //fclose(wave.fp); /* close wave file */
  111. }


按结构体一点点的读出文件头的信息,请注意

/* jump to "data" for reading data */

的那一段,“先识别data标识符,再接着往下读取”。

(3)读数据

在读完数据长度之后就全是数据了,直接使用fread按uint32格式读取数据即可,我这里每次读取1152个数据(即一帧)。

  1. /*
  2. * get wave data
  3. */
  4. uint32* GetWave(void)
  5. {
  6. static uint32 buffer[1152] = {0};
  7. uint16 n = 0;
  8. uint16 p = 0;
  9. p = fread(buffer, sizeof(uint32), n, wave.fp);
  10. if(!p)
  11. {
  12. return 0;
  13. }
  14. else
  15. {
  16. for(; p<n; p++)
  17. {
  18. buffer[p] = 0;
  19. }
  20. return buffer;
  21. }
  22. }

上面程序中注意几点,

(1)不要定义大容量的局部变量,因为局部变量存放在堆栈中。如果一定要定义,要定义成static类型。

(2)不要返回局部变量的的地址,因为在堆栈中的地址值是不确定的。

上面的程序返回局部数组的指针,前提是 已经将数据存放在静态数据存储区。

但不管怎样,返回局部变量的地址总是不好的。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多