一、 音频概念

音频信号是一种连续变化的模拟信号,但计算机只能处理和记录二进制的数字信号,由自然音源得到的音频信号必须经过一定的变换,成为数字音频信号之后,才能送到计算机中作进一步的处理。

对于OSS编程来说,需要掌握声音数字化的两个关键步骤:采样和量化。采样就是每隔一定时间就读一次声音信号的幅度,而量化则是将采样得到的声音信号幅度转换为数字值,从本质上讲,采样是时间上的数字化,而量化则是幅度上的数字化。

下面是音频编程时经常要使用到的技术指标:

1. 采样频率

采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。正常人听觉的频率范围大约在20Hz~20kHz之间,根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等。

2. 量化位数

量化位数是对模拟音频信号的幅度进行数字化,它决定了模拟信号数字化以后的动态范围,常用的有8位、12位和16位。量化位越高,信号的动态范围越大,数字化后的音频信号就越可能接近原始信号,但所需要的存贮空间也越大。

3. 声道数

声道数是反映音频数字化质量的另一个重要因素,它有单声道和双声道之分。双声道又称为立体声,在硬件中有两条线路,音质和音色都要优于单声道,但数字化后占据的存储空间的大小要比单声道多一倍。

二、 声卡驱动(OSS)

目前Linux下常用的声卡驱动程序主要有两种:OSS和ALSA。

OSS(Open Sound System)部分代码开源,其他部分由4Front Technologies公司以二进制的形式提供。

ALSA(Advanced Linux Sound Architecture)是完全开放源代码的产品。因为OSS由商业公司提供,而ALSA由志愿者维护,所以OSS支持的声卡类型更多。

1. OSS的安装(Ubuntu环境)

当前OSS的版本是V4.2-build 2004

下载地址: http://www.4front-tech.com/download.cgi

根据Linux内核版本选择安装包。

P.S.:查看内核版本的命令为uname –r

ubuntu选择DEB包。安装命令dpkg -l oss-Linux_v4.2-2004_i686.deb。安装完成后,会在/dev下找到/dev/dsp,/dev/mixer等设备文件。也可以用osstest命令来测试oss是否正常工作。

2. 设备文件说明
l /dev/sndstat

设备文件/dev/sndstat的作用是用于汇报声卡当前的状态。Linux下的cat命令可以方便的获取声卡的当前状态。

l /dev/dsp

声卡驱动程序提供的/dev/dsp是用于数字采样(sampling)和数字录音(recording)的设备文件,它对于Linux下的音频编程来讲非常重要:向该设备写数据即意味着激活声卡上的D/A转换器进行放音,而向该设备读数据则意味着激活声卡上的A/D转换器进行录音。目前许多声卡都提供有多个数字采样设备,它们在Linux下可以通过/dev/dsp1等设备文件进行访问。

无论是从声卡读取数据,或是向声卡写入数据,事实上都具有特定的格式(format),默认为8位无符号数据、单声道、8KHz采样率,如果默认值无法达到要求,可以通过ioctl系统调用来改变它们。通常说来,在应用程序中打开设备文件/dev/dsp之后,接下去就应该为其设置恰当的格式,然后才能从声卡读取或者写入数据。

l /dev/mixer

在声卡的硬件电路中,混音器(mixer)是一个很重要的组成部分,它的作用是将多个信号组合或者叠加在一起,对于不同的声卡来说,其混音器的作用可能各不相同。运行在Linux内核中的声卡驱动程序一般都会提供/dev/mixer这一设备文件,它是应用程序对混音器进行操作的软件接口。

由于混音器的操作不符合典型的读/写操作模式,因此除了open和close两个系统调用之外,大部分的操作都是通过ioctl系统调用来完成的。与/dev/dsp不同,/dev/mixer允许多个应用程序同时访问,并且混音器的设置值会一直保持到对应的设备文件被关闭为止。

为了简化应用程序的设计,Linux上的声卡驱动程序大多都支持将混音器的ioctl操作直接应用到声音设备上,也就是说如果已经打开了/dev/dsp,那么就不用再打开/dev/mixer来对混音器进行操作,而是可以直接用打开/dev/dsp时得到的文件标识符来设置混音器。

l /dev/sequencer

目前大多数声卡驱动程序还会提供/dev/sequencer这一设备文件,用来对声卡内建的波表合成器进行操作,或者对MIDI总线上的乐器进行控制,一般只用于计算机音乐软件中。

三、 编程接口与框架(DSP)

无论是OSS还是ALSA,都是以内核驱动程序的形式运行在Linux内核空间中的,应用程序要想访问声卡这一硬件设备,必须借助于Linux内核所提供的系统调用(system call)。从程序员的角度来说,对声卡的操作在很大程度上等同于对磁盘文件的操作:首先使用open系统调用建立起与硬件间的联系,此时返回的文件描述符将作为随后操作的标识;接着使用read系统调用从设备接收数据,或者使用write系统调用向设备写入数据,而其它所有不符合读/写这一基本模式的操作都可以由ioctl系统调用来完成;最后,使用close系统调用告诉Linux内核不会再对该设备做进一步的处理。

1. 编程接口
l open系统调用

系统调用open可以获得对声卡的访问权,同时还能为随后的系统调用做好准备。

函数原型:

   1:  #include <fcntl.h>
   2:  #include <sys/types.h>
   3:  #include <sys/stat.h>
   4:  //严格说一般使用open系统调用不需要包含sys/types.h,sys/stat.h。
   5:  int open(const char *path, int oflags);
   6:  int open(const char *path, int oflags, mode_t mode);

参数path是将要被打开的设备文件的名称,对于声卡来讲一般是/dev/dsp。参数oflags用来指明应该以什么方式打开设备文件,格式是

(O_RDONLY | O_WRONLY | ORDWR)[ | O_APPEND | O_TRUNC | O_CREAT| O_EXCL]

分别表示以只读、只写或者读写的方式打开设备文件,后面参数可选;使用O_CREAT标志时,需要用3个参数的open调用,这时用mode设置文件的权限。

如果open系统调用能够成功完成,它将返回一个正整数作为文件标识符,在随后的系统调用中需要用到该标识符。如果open系统调用失败,它将返回-1,同时还会设置全局变量errno,指明是什么原因导致了错误的发生。

l read系统调用

系统调用read用来从声卡读取数据

函数原型:

   1:  #include <unistd.h>
   2:  size_t read(int fildes, void *buf, size_t nbytes);

参数fildes是设备文件的标识符,它是通过之前的open系统调用获得的;参数buf是指向缓冲区的字符指针,它用来保存从声卡获得的数据;参数nbytes则用来限定从声卡获得的最大字节数。如果read系统调用成功完成,它将返回从声卡实际读取的字节数,通常情况会比nbytes的值要小一些;如果read系统调用失败,它将返回-1,同时还会设置全局变量errno,来指明是什么原因导致了错误的发生。

l write系统调用

系统调用write用来向声卡写入数据

函数原型:

   1:  #include <unistd.h>
   2:  size_t write(int fildes, const void *buf, size_t nbytes);

系统调用write和系统调用read在很大程度是类似的,差别只在于write是向声卡写入数据,而read则是从声卡读入数据。参数fildes同样是设备文件的标识符,它也是通过之前的open系统调用获得的;参数buf是指向缓冲区的字符指针,它保存着即将向声卡写入的数据;参数nbytes则用来限定向声卡写入的最大字节数。

如果write系统调用成功完成,它将返回向声卡实际写入的字节数;如果read系统调用失败,它将返回-1,同时还会设置全局变量errno,来指明是什么原因导致了错误的发生。无论是read还是write,一旦调用之后Linux内核就会阻塞当前应用程序,直到数据成功地从声卡读出或者写入为止。

l ioctl系统调用

系统调用ioctl可以对声卡进行控制,凡是对设备文件的操作不符合读/写基本模式的,都是通过ioctl来完成的,它可以影响设备的行为,或者返回设备的状态。

函数原型:

   1:  #include <sys/ioctl.h>
   2:  int ioctl(int fildes, int request, ...);

参数fildes是设备文件的标识符,它是在设备打开时获得的;如果设备比较复杂,那么对它的控制请求相应地也会有很多种,参数request的目的就是用来区分不同的控制请求;通常说来,在对设备进行控制时还需要有其它参数,这要根据不同的控制请求才能确定,并且可能是与硬件设备直接相关的。

l close系统调用

当应用程序使用完声卡之后,需要用close系统调用将其关闭,以便及时释放占用的硬件资源。

函数原型:

   1:  #include <unistd.h>
   2:  int close(int fildes);

参数fildes是设备文件的标识符,它是在设备打开时获得的。一旦应用程序调用了close系统调用,Linux内核就会释放与之相关的各种资源,因此建议在不需要的时候尽量及时关闭已经打开的设备。

2. DSP编程框架
l 打开设备

对声卡进行编程时首先要做的是打开与之对应的硬件设备,这是借助于open系统调用来完成的,并且一般情况下使用的是/dev/dsp文件。采用何种模式对声卡进行操作也必须在打开设备时指定,对于不支持全双工的声卡来说,应该使用只读或者只写的方式打开,只有那些支持全双工的声卡,才能以读写的方式打开,并且还要依赖于驱动程序的具体实现。Linux允许应用程序多次打开或者关闭与声卡对应的设备文件,从而能够很方便地在放音状态和录音状态之间进行切换,建议在进行音频编程时只要有可能就尽量使用只读或者只写的方式打开设备文件,因为这样不仅能够充分利用声卡的硬件资源,而且还有利于驱动程序的优化。

范例:只写方式(放音palyback)打开设备

   1:  int handle = open("/dev/dsp", O_WRONLY);
   2:   
   3:  if (handle == -1) {
   4:   
   5:      perror("open /dev/dsp");
   6:   
   7:      return -1;
   8:   
   9:  }

l 设置声道(channel)

根据硬件设备和驱动程序的具体情况,可以将其设置为1(单声道,mono)或者2(立体声,stereo)。

范例:设置声道

   1:  ioctl_val = chn;
   2:  if ((ioctl(fd, SNDCTL_DSP_CHANNELS, &ioctl_val)) == -1)
   3:  {
   4:      fprintf(stderr, "Set Audio Channels %d failed:%s\n", chn,
   5:      strerror(errno));
   6:      return (-1);
   7:  }
   8:  if (ioctl_val != chn)
   9:  {
  10:      fprintf(stderr, "do not support channel %d,supported %d\n", chn,ioctl_val);
  11:      return (-1);
  12:  }

l 设置采样格式

范例:

   1:  ioctl_val = bits;
   2:  if (ioctl(fd, SNDCTL_DSP_SETFMT, &ioctl_val) == -1)
   3:  {
   4:      fprintf(stderr, "Set fmt to bit %d failed:%s\n", bits,
   5:      strerror(errno));
   6:      return (-1);
   7:  }
   8:  if (ioctl_val != bits)
   9:  {
  10:      fprintf(stderr, "do not support bit %d, supported %d\n", bits,
  11:      ioctl_val);
  12:      return (-1);
  13:  }
  14:   

l 设置采样频率

调用ioctl时将第二个参数的值设置为SNDCTL_DSP_SPEED,同时在第三个参数中指定采样频率的数值。对于大多数声卡来说,其支持的采样频率范围一般为5kHz到44.1kHz或者48kHz,但并不意味着该范围内的所有频率都会被硬件支持,在Linux下进行音频编程时最常用到的几种采样频率是11025Hz、16000Hz、22050Hz、32000Hz和44100Hz。

范例:

   1:  ioctl_val = hz;
   2:  if (ioctl(fd, SNDCTL_DSP_SPEED, &ioctl_val) == -1)
   3:  {
   4:      fprintf(stderr, "Set speed to %d failed:%s\n", hz,
   5:      strerror(errno));
   6:      return (-1);
   7:  }
   8:  if (ioctl_val != hz)
   9:  {
  10:      fprintf(stderr, "do not support speed %d,supported is %d\n", hz,ioctl_val);
  11:      return (-1);
  12:  }
  13:   

l 录音、放音

对设备读操作即为录音,写操作即为放音。

范例:

   1:  nRD = read(s_fd, buff, BUFF_SIZE);

l 关闭设备

范例:

   1:  close(dev_fd);

四、 参考资料

1. Linux音频编程指南, http://www.ibm.com/developerworks/cn/linux/l-audio/, 肖文鹏 (xiaowp@263.net);

2. OSS--跨平台的音频接口简介, http://www.ibm.com/developerworks/cn/linux/l-ossapi/index.html, 汤凯 (tangk73@hotmail.com);

3. OSS安装帮助, http://www.opensound.com/release/oss-install.pdf, 4Front Technologies;

4. Linux下的OSS音频接口编程一例, http://blog.chinaunix.net/space.php?uid=7897183&do=blog&cuid=189502, rockins。

转载于:https://www.cnblogs.com/jasonwang/archive/2011/03/30/oss_program.html

OSS音频编程概述(DSP部分)相关推荐

  1. 整理下OSS方面的资料,免得到处找,linux音频编程,open sound system

    浅析ASoC-audio驱动oss框架下/dev/dsp与alsa框架下设备节点打开和创建简易流程 http://blog.chinaunix.net/u2/70445/showart_2070710 ...

  2. 【Linux系统编程应用】Linux音频编程接口

    如何对各种音频设备进行操作是在Linux上进行音频编程的关键,通过内核提供的一组系统调用,应用程序能够访问声卡驱动程序提供的各种音频设备接口,这是在Linux下进行音频编程最简单也是最直接的方法. 1 ...

  3. linux下lamealsa进行音频流操作(三)alsa音频编程教程

    1. ALSA音频编程介绍   ALSA 代表高级 Linux 声音架构.它由一组内核驱动程序.一个应用程序编程接口 (API) 库和用于在 Linux 下支持声音的实用程序组成.在本文中,我简要概述 ...

  4. 【Linux系统编程应用】Linux音频编程实战(一)

    在Linux下进行音频编程时,重点在于如何正确地操作声卡驱动程序所提供的各种设备文件,由于涉及到的概念和因素比较多,所以遵循一个通用的框架无疑将有助于简化应用程序的设计. 1 DSP编程 对声卡进行编 ...

  5. 实时音频编程(二):实践与技巧

    文章目录 简介 Q&A Question 1: 你是选择传递还是共享对象? Question 2: 是否与实时线程交互? Question 3: 共享数据是否足够小? Question 4: ...

  6. MindSpore API编程概述

    MindSpore API编程概述 总体架构 MindSpore是一个全场景深度学习框架,旨在实现易开发.高效执行.全场景覆盖三大目标,其中易开发表现为API友好.调试难度低,高效执行包括计算效率.数 ...

  7. linux文件系统添加pcm,嵌入式linux中PCM音频编程实践

    嵌入式设备中经常需要用的音频,音频设备最原始的数据格式就是PCM,也就是大家常见的WAV,在linux中,音频编程使用最多的就是alsa框架,下面就来看一下pcm音频的编程实例吧. 首先需要包含头文件 ...

  8. 【Android】Android网络编程概述

    Android网络编程概述 原文来自:http://blog.csdn.net/kieven2008/article/details/8210737 首先,应该了解的几个问题: 1)Android平台 ...

  9. Windows音频编程:Win32 Wave API 的使用

    //Windows音频编程:Win32 Wave API 的使用 //下面是一个Win32控制台程序的源码,环境VS2008,新建一个空的Win32控制台项目,加入此文件编译即可,功能为录制5秒并回放 ...

最新文章

  1. mysql post 中文乱码_mysql/mariaDB中文乱码问题的处理
  2. 机器学习中梯度下降算法的实际应用和技巧
  3. android飞翔的小鸟游戏素材包_开心消消乐×愤怒的小鸟:为开心而战
  4. AS 2.0新功能 Instant Run
  5. linux下安装TensorFlow(centos)
  6. 社群广场程序公众号版本程序源码-支持群采集
  7. java中的 FileWriter类 和 FileReader类的一些基本用法
  8. mysql 取substring_如何在MySQL中的字段上应用Substring()以获取字符串的一部分?
  9. php开发总结,PHP开发规范总结
  10. cmake 多次编译_Part01_CMakeLists构建管理多个模块的C代码
  11. 大数据_Hbase-API访问_Java操作Hbase_数据操作_命名空间创建_表创建_表查询---Hbase工作笔记0013
  12. spring学习-xml属性注入-数组--list--map--set类型
  13. (转载)C#中如何获取当前路径的几种方法
  14. 服务器系统如何校验md5值,什么是md5校验工具,md5校验工具怎么用?
  15. 最小二乘法拟合空间直线的原理及实现
  16. 2020-09-07(基于控制台的DVD管理系统)
  17. mysql修改游戏数据_Sqlite3 数据库工具修改游戏数据库文件图文教程
  18. “蔚来杯“2022牛客暑期多校训练营1 J Serval and Essay(图的启发式合并)
  19. 关于echart 饼图显示不出来 挖坑总结
  20. 鹰潭高通量测序建设细节概述

热门文章

  1. Android 第一篇
  2. Java 12 将于3月19日发布,8 个最终 JEP 一览
  3. WPF快速指导2:模板
  4. 如何在JS中改变Extjs combox 的值
  5. 华为eudemon 200E的hrp双心跳热备配置
  6. PHP realpath() 函数
  7. Quantaxis更新数据到最新
  8. btree索引和hash索引的区别(待更新)
  9. linux/shell相关知识点
  10. andriod studio 运行 无结果_华为物联网操作系统LiteOS内核教程01——IoT-Studio介绍及安装...