播放WAV音频

在网上找到uda1341的驱动,编译成模块uda1341.ko,打开内核配置菜单
Device Drivers  --->
  Sound  --->
    <M> Sound card support
make modules  生成 soundcore.ko 模块,加载这两个模块就可以播放音频了

仔细看了uda1341的驱动,发现只能播放16bit的音频,单声道的音频在应用程序
向驱动复制时转化成双声道。所以最好选择双声道16bit的wav音频。
先看看wav文件的格式,前面是一些音频信息,可以读取作为参数。
WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE
Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。具体见下图:

------------------------------------------------
|          RIFF WAVE Chunk                |
|          ID   = 'RIFF'                  |
|          RiffType = 'WAVE'              |
------------------------------------------------
|          Format Chunk                   |
|          ID = 'fmt '                    |
------------------------------------------------
|          Fact Chunk(optional)           |
|          ID = 'fact'                    |
------------------------------------------------
|          Data Chunk                     |
|          ID = 'data'                    |
------------------------------------------------
         图1 Wav格式包含Chunk示例


RIFF WAVE Chunk
==================================
|        | 所占字节数|   具体内容 |
==================================
| ID     |   4 Bytes |   'RIFF'   |
----------------------------------
| Size   |   4 Bytes |            |
----------------------------------
| Type   |   4 Bytes |   'WAVE'   |
----------------------------------
         图2   RIFF WAVE Chunk

以'RIFF'作为标示,然后紧跟着为size字段,该size是整个wav文件大小减去ID和Size所占用的字节数,即FileLen - 8 = Size。然后是Type字段,为'WAVE',表示是wav文件。
结构定义如下:
struct RIFF_HEADER
{
   char szRiffID[4];
   DWORD dwRiffSize;
   char szRiffFormat[4];
};

 

Format Chunk
====================================================================
|               | 字节数      |              具体内容              |
====================================================================
| ID            |   4 Bytes   | 'fmt '                             |
--------------------------------------------------------------------
| Size          |   4 Bytes   | 数值为16或18,18则最后又附加信息   |
--------------------------------------------------------------------
| FormatTag     |   2 Bytes   | 编码方式,一般为0x0001             |
--------------------------------------------------------------------
| Channels      |   2 Bytes   | 声道数目,1--单声道;2--双声道     |
--------------------------------------------------------------------
| SamplesPerSec |   4 Bytes   | 采样频率                           |
--------------------------------------------------------------------
| AvgBytesPerSec|   4 Bytes   | 每秒所需字节数                     |
--------------------------------------------------------------------
| BlockAlign    |   2 Bytes   | 数据块对齐单位(每个采样字节数,声道*采样bit/8)|
--------------------------------------------------------------------
| BitsPerSample |   2 Bytes   |       采样量化bit数                |
--------------------------------------------------------------------
|               |   2 Bytes   | 附加信息(可选,通过Size来判断有无)|
--------------------------------------------------------------------
                        图3   Format Chunk

 

以'fmt '作为标示。一般情况下Size为16,此时最后附加信息没有;如果为18
则最后多了2个字节的附加信息。主要由一些软件制成的wav格式中含有该2个字节的
附加信息。
结构定义如下:
struct FMT_BLOCK
{
   char   szFmtID[4];
   DWORD   dwFmtSize;
   WAVE_FORMAT wavFormat;
};
struct WAVE_FORMAT
{
   WORD wFormatTag;
   WORD wChannels;
   DWORD dwSamplesPerSec;
   DWORD dwAvgBytesPerSec;
   WORD wBlockAlign;
   WORD wBitsPerSample;
};

Fact Chunk
==================================
|      | 所占字节数|   具体内容 |
==================================
| ID   |   4 Bytes | 'fact'     |
----------------------------------
| Size   |   4 Bytes | 数值为4    |
----------------------------------
| data   |   4 Bytes |            |
----------------------------------
         图4   Fact Chunk

Fact Chunk是可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk。
结构定义如下:
struct FACT_BLOCK
{
   char   szFactID[4];
   DWORD   dwFactSize;
};

Data Chunk
==================================
|      | 所占字节数|   具体内容 |
==================================
| ID     |   4 Bytes | 'data'     |
----------------------------------
| Size   |   4 Bytes |            |
----------------------------------
| data   |           |            |
----------------------------------
         图5 Data Chunk


Data Chunk头结构定义如下:
struct DATA_BLOCK
{
   char szDataID[4];
   DWORD dwDataSize;
};

Data Chunk是真正保存wav数据的地方,以'data'作为该Chunk的标示。然后是
数据的大小。紧接着就是wav数据。根据Format Chunk中的声道数以及采样bit数,
wav数据的bit位置可以分成以下几种形式:
---------------------------------------------------------------------
| 单声道     | 取样1 | 取样2 | 取样3 | 取样4 |
|            |--------------------------------------------------------
|   8bit量化 | 声道0 | 声道0 | 声道0 | 声道0 |
---------------------------------------------------------------------
| 双声道     |             取样1             |             取样2             |
|            |--------------------------------------------------------
|   8bit量化 |   声道0(左)   |   声道1(右)   |   声道0(左)   |   声道1(右)   |
---------------------------------------------------------------------
|            |           取样1             |           取样2             |
| 单声道     |--------------------------------------------------------
| 16bit量化  |    声道0     |   声道0      |    声道0     |   声道0      |
|            | (低位字节)   | (高位字节)   | (低位字节)   | (高位字节)   |
---------------------------------------------------------------------
|           |                             取样1                             |
| 双声道    |--------------------------------------------------------
| 16bit量化 |   声道0(左)   |   声道0(左)   |   声道1(右)   |   声道1(右)   |
|           |  (低位字节)   |  (高位字节)   |  (低位字节)   |  (高位字节)   |
---------------------------------------------------------------------
                     图6 wav数据bit位置安排方式
用ultraedit打开xp关机声的wav文件,可以看这些参数

最重要的三个参数就是 audio_channels 声道数, audio_fmt 采样位数, audio_rate 采样频率。这样每秒就需要把(采样频率×采样位数×声道)/ 8 字节的数据通过IIS接口送给 uda1341 。
以下是网上的一个播放wav文件的c程序,稍加修改就可以在ARM上播放。这里我已经知道参数,所以只读一次跳过,并未使用。

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

#define OPEN_DSP_FAILED      0x00000001    /*open dsp failed!*/
#define SAMPLERATE_STATUS     0x00000002    /*samplerate status failed*/
#define SET_SAMPLERATE_FAILED   0x00000003    /*set samplerate failed*/
#define CHANNELS_STATUS         0x00000004    /*Channels status failed*/
#define SET_CHANNELS_FAILED     0x00000005    /*set channels failed*/
#define FMT_STATUS        0x00000006    /*FMT status failed*/
#define SET_FMT_FAILED      0x00000007    /*set fmt failed*/
#define OPEN_FILE_FAILED        0x00000008    /*opem filed failed*/

int S32410_Audio_Play(char *pathname,int nSampleRate,int nChannels,int fmt)
{
 int dsp_fd,mix_fd,status,arg;
 dsp_fd = open("/dev/sound/dsp" , O_RDWR);   /*open dsp  注意设备的地址*/
 if(dsp_fd < 0)
 {
  return  OPEN_DSP_FAILED;
 }
 arg = nSampleRate;
 status = ioctl(dsp_fd,SOUND_PCM_WRITE_RATE,&arg); /*set samplerate*/
 if(status < 0)
 {
  close(dsp_fd);
  return SAMPLERATE_STATUS;
 }
 if(arg != nSampleRate)
 {
  close(dsp_fd);
  return SET_SAMPLERATE_FAILED;
 }
 arg = nChannels;  /*set channels*/  
 status = ioctl(dsp_fd, SOUND_PCM_WRITE_CHANNELS, &arg);
 if(status < 0)
 {
  close(dsp_fd);
  return CHANNELS_STATUS;
 }
 if( arg != nChannels)
 {
  close(dsp_fd);
  return SET_CHANNELS_FAILED;
 }
 arg = fmt; /*set bit fmt*/
 status = ioctl(dsp_fd, SOUND_PCM_WRITE_BITS, &arg);
 if(status < 0)
 {
  close(dsp_fd);
  return FMT_STATUS;
 }
 if(arg != fmt)
 {
  close(dsp_fd);
  return SET_FMT_FAILED;
 }   /*以上设置三个重要参数 默认就是 44100 2 16*/            
 FILE *file_fd = fopen(pathname,"r");
 if(file_fd == NULL)
 {
  close(dsp_fd);
  return OPEN_FILE_FAILED;
 }
 int num = 3*nChannels*nSampleRate*fmt/8; //每次写的字节数
 int get_num;      //其实每次写8192个字节的整数倍最好
 char buf[num];     //因为驱动里就是开辟了8块8192大小的 DMA buffer,每次需要把一个buffer写满,才通过DMA发送,这样循环次数会更少.
 get_num = fread(buf,1,36,file_fd);  //跳过wav文件音频信息头 36个字节
 while(feof(file_fd) == 0)
 {
  get_num = fread(buf,1,num,file_fd);
  write(dsp_fd,buf,get_num);
  if(get_num != num)
  {
   close(dsp_fd);
   fclose(file_fd);
   return 0;
  }
 }
 close(dsp_fd);
 fclose(file_fd);
 return 0;
}

int main()
{
 int value;
 value = S32410_Audio_Play("down.wav",44100,2,16);
 fprintf(stderr,"value is %d/n",value);
 return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值