Chinaunix首页 | 论坛 | 博客
  • 博客访问: 312191
  • 博文数量: 78
  • 博客积分: 3635
  • 博客等级: 中校
  • 技术积分: 1115
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-28 09:35
文章分类

全部博文(78)

文章存档

2011年(13)

2010年(65)

我的朋友

分类: LINUX

2010-11-02 18:02:21

From: http://blog.csdn.net/dansen_xu/archive/2008/05/09/2425498.aspx

在网上找到uda1341的驱动,编译成模块uda1341.ko,打开内核配置菜单
Device Drivers  --->
Sound  --->
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
#include
#include
#include
#include
#include
#include
#include
#include

#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;
}
阅读(1181) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-11-03 16:12:27

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com