转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd
作者联系方式:Li XianJing <xianjimli at hotmail dot com>
更新时间:2006-12-19
我们知道,在Win32下,用waveOut系列函数播放声音,用waveIn系列函数录制声音。这套函数设计简单易用,如果使用DirectX可能还会有更好用的接口。而在linux下,这个问题要麻烦不少,在很长一段时间里,我甚至不知道linux下是如何播放声音的。这几天在研究ALSA,我知道ALSA是OSS的替代品,而且兼容OSS。为了了解ALSA的优势所在,我决定先研究OSS。本文记录了一些在研究过程中所记的笔记。
据说Open Sound System (OSS)是第一个为统一unix下数字音频处理的尝试。当然这种尝试是非常成功的,Opensound的实现可以移植到绝大多数unix操作系统上,而且有大量的应用程序支持OSS,Mplayer就是其中之一。Opensound的实现不是开放源码的,linux上的实现可能并非是Opensound所提供的。不过OSS只是一套规范,这个规范是开放的,只要有时间和精力,我们自己也可以实现一套符合OSS的代码。
OSS并没有规定操作系统内部的实现方式,也没有为驱动程序的实现提供指南,而是只规定了操作系统与应用程序交互的接口。OSS采取unix惯用的方式,通过文件与应用程序交互,而不增加任何系统调用。使用传统的open/close/read/write/ioctl系列文件操作函数就足够了。数据通过read/write来传递数据,而通过ioctl来传递控制信息。OSS定义了下列这些设备文件:
1. /dev/mixer
这是所谓混音器,一个看似很专业的术语。它在这里的功能实际上很简单,主要是对声卡进行设置,比较设置speaker、mic和midi的音量等等。这些设置主要是通过ioctl进行,比如可以用SNDCTL_DSP_SETPLAYVOL设置speaker的音量,用SNDCTL_DSP_SETRECVOL设置mic的音量,用SNDCTL_DSP_SET_PLAYTGT选择输出的speaker(比如机身的speaker或者earphone)。
2. /dev/sndstat
这主要是用于debug的,cat /dev/sndstat可以输出一些OSS驱动程序检测的设备信息,这些信息是给人读的而不是程序使用的。在FC4上没有这个文件,可能FC4已经使用了ALSA吧,尽管ALSA兼容OSS,多半只是程序上的兼容,所以忽略了这个文件。
3. /dev/dsp 和/dev/audio
这是两个非常重要的文件,往该文件写的数据传向speaker,即完成播放过程。从该文件读数据,系统会从mic采用数据并返回给应用程序,即实现录音过程。这两个文件的功能非常类似,只是默认的编码方式有些差别。/dev/dsp默认采用线性编码,/dev/audio默认采用对数编码。/dev/audio 主要是用于和SunOS保持兼容性,可以通过ioctl设置使两者保持相同的行为。
4. /dev/sequencer
该文件主要是给电子(MIDI)音乐应用程序使用的,也利用它来实现游戏中的音效。通过该文件可以访问声卡内部和外部(即子卡)中的声音合成(synthesizer)设备。声音合成(synthesizer)设备的功能是把MIDI转成波型数据,一般通过调频(FM)和波表(wavetable)来实现。
5. /dev/music
该文件类似于/dev/sequencer,但它可以以同样的方式处理声音合成(synthesizer)设备和MIDI设备(可能是指MIDI键盘吧),而且具有更好的设备无关性,但是不能像/dev/sequencer那可以精确的控制单个音符(note)(?)。
6. /dev/midi
该文件是MIDI总线端口的比较底层的接口,它的工作方式很像一个TTY (character terminal),所有发送给它的数据立即传递到MIDI端口。
7. /dev/dmfm
该文件是调频合成器(FM synthesizers)的原始接口,通过它可以访问FM的一些底层寄存器。
8. /dev/dmmidi
该文件是MIDI设备(MIDI device)的原始接口,它提供直接TTY方式访问MIDI端口,主要是给一个特殊应用程序使用。(不知道它与/dev/midi的差别到底在哪里。)
几个术语和概念:
1. 关于PCM的
PCM是Pulse code modulation的缩写,它是对波形最直接的编码方式。它在音频中的地位可能和BMP在图片中的地位有点类似吧。
Sampling rate:从模拟信号到数字信号,即从连续信号到离散信号的转换都是通过离散采样完成的,Sampling rate就是每秒种采样的个数。根据香农采样定理,要保证信号不失真,Sampling rate要大于信号最高频率的两倍。我们知道人的耳朵能听到的频率范围是20hz – 20khz,所以Sampling rate达到40k就够了,再多了也只是浪费。但是有时为了节省带宽和存储资源,可以降低Sampling rate而损失声音的质量,所以我们常常见到小于40k采样率的声音数据。
Sample size:用来量化一个采样的幅度,一般为8 bits、16 bits和24 bits。8 bits只有早期的声卡支持,而24 bits只有专业的声卡才支持,我们用的一般都是16 bits的。
Number of channels:声音通道个数,单声道为一个,立体声为两个,还有更多的(如8个声道的7.1格式)。一般来说,每个声道都来源于一个独立的mic,所以声道多效果会更好(更真实),当然代价也更大。
Frame: Frame是指包含了所有通道的一次采样数据,比如对于16bits的双声道来说,一个frame的大小为4个字节(2 * 16)。
2. 关于MIDI
MIDI是Musical Instrument Digital Interface的缩写。说白了,MIDI只一个通信协议,用来在乐器之间进行通信的,让所有的乐器都说同一种语言。这种通信通常是通过一个高速串口来实现的,速率为31250bps,8bits的数据,外加一个起始位和一个停止位。下面简单介绍一下这个协议的内容:
MIDI的消息由状态(Status,或者称为命令更好)和数据两部分组成,状态由一个字节表示,所有状态值的最高位都为1,即大于等于128。数据由多个字节表示,数据长度视状态而定,但所有数据的最高位都为0,即小于128。状态的8bits,又分为两个4bits,高的4bits代表状态的类型,低四位代表通道。MIDI的状态有:
8 = Note Off
9 = Note On
A = AfterTouch (ie, key pressure)
B = Control Change
C = Program (patch) change
D = Channel Pressure
E = Pitch Wheel
F = System Exclusive
Note On: 它是一个抽象的动作,当演奏者按下钢琴的键,拉动小提琴的弦或者拨动吉它的弦,这个动作称为note on。
Note Off: 它是一个抽象的动作,当演奏者放开钢琴的键,停止拉动小提琴或者手指离开吉它的弦,这个动作称为note off。
AfterTouch: 同是按键动作,力度的差异产生效果也不一样,即使在保持按键的过程中,压力也会有变化,这由AfterTouch状态来调整。
Control Change:用来对MIDI设备进行设置,比如设置音量和立体声平衡值等等,它有128种取值(0-127)。
Program (patch) change:一个Program 一般与一种乐器对应,比如Piano、 Guitar和Trumpet,要换乐器就用这个状态。
Channel Pressure: 和AfterTouch的功能类似,但它不只影响一个note,而是影响一个通道,通常用来设置默认值。
Pitch Wheel:设置Pitch Wheel的值,好像是设置乐器的基准音调吧,不太懂。这里有篇文章讲得不错,大家可以看看。
下面我们看看编程实例:
1. 操作mixer
打开设备文件:
if ((mixerfd = open ("/dev/mixer", O_RDWR, 0)) == -1)
{
perror ("/dev/mixer");
exit (-1);
}
通过ioctl控件设备:
oss_sysinfo info;
if (ioctl (mixerfd, SNDCTL_SYSINFO, &info) == -1)
{
perror ("SNDCTL_SYSINFO");
if (errno == EINVAL)
fprintf (stderr, "Error: OSS version 4.0 or later is required/n");
exit (-1);
}
|
2. 录音
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/soundcard.h>
#include <time.h>
int main(int argc, char *argv[])
{
int fd, i, src;
oss_mixer_enuminfo ei;
if (argc < 2)
{
fprintf(stderr, "Usage: %s dspdev/n", argv[0]);
exit(-1);
}
if ((fd=open(argv[1], O_RDONLY, 0))==-1)
{
perror(argv[1]);
exit(-1);
}
if (ioctl(fd, SNDCTL_DSP_GET_RECSRC_NAMES, &ei)==-1)
{
perror("SNDCTL_DSP_GET_RECSRC_NAMES");
exit(-1);
}
if (argc == 2)
{
for (i=0;i<ei.nvalues;i++)
printf("Rec source #%d = '%s'/n", i, ei.strings+ei.strindex[i]);
exit(0);
}
if (strcmp(argv[2], "?")==0 || strcmp(argv[2], "-")==0)
{
if (ioctl(fd, SNDCTL_DSP_GET_RECSRC, &src)==-1)
{
perror("SNDCTL_DSP_GET_RECSRC");
exit(-1);
}
printf("Current recording source is #%d/n", src);
printf("Current recording source is #%d (%s)/n",
src, ei.strings+ei.strindex[src]);
exit(0);
}
src=0;
for (i=0;i<ei.nvalues;i++)
{
if (strcmp(argv[2], ei.strings+ei.strindex[i])==0)
{
if (ioctl(fd, SNDCTL_DSP_SET_RECSRC, &src)==-1)
{
perror("SNDCTL_DSP_SET_RECSRC");
exit(-1);
}
exit(0);
}
src++;
}
fprintf(stderr, "What?/n");
exit(-1);
}
|
3. 播放PCM
打开dsp设备文件
if ((fd = open (name, mode, 0)) == -1)
{
perror (name);
exit (-1);
}
设置格式
tmp = AFMT_S16_NE; /* Native 16 bits */
if (ioctl (fd, SNDCTL_DSP_SETFMT, &tmp)==-1)
{
perror("SNDCTL_DSP_SETFMT");
exit(-1);
}
设置声道个数
tmp = 1;
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &tmp)==-1)
{
perror("SNDCTL_DSP_CHANNELS");
exit(-1);
}
设置采用率
sample_rate = 48000;
if (ioctl (fd, SNDCTL_DSP_SPEED, &sample_rate)==-1)
{
perror("SNDCTL_DSP_SPEED");
exit(-1);
}
播放
if (write (fd_out, buf, sizeof (buf)) != sizeof (buf))
{
perror ("Audio write");
exit (-1);
}
|
4. 播放midi
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/soundcard.h>
#define DEVICE "/dev/midi"
int
main ()
{
int fd;
unsigned char note_on[] = { 0xc0, 0, /* Program change */
0x90, 60, 60
}; /* Note on */
unsigned char note_off[] = { 0x80, 60, 60 }; /* Note off */
if ((fd = open (DEVICE, O_WRONLY, 0)) == -1)
{
perror ("open " DEVICE);
exit (-1);
}
if (write (fd, note_on, sizeof (note_on)) == -1)
{
perror ("write " DEVICE);
exit (-1);
}
sleep (1); /* Delay one second */
if (write (fd, note_off, sizeof (note_off)) == -1)
{
perror ("write " DEVICE);
exit (-1);
}
close (fd);
exit (0);
}
|
以上是这两天阅读OSS规范、MIDI和音频相关资料的笔记和总结,有些内容不是很确信,若有错误,希望大家指正。谢谢
参考资料:
OSS:http://manuals.opensound.com
MIDI: http://www.borg.com/~jglatt/tech/midispec.htm
~~end~~
相关推荐
开放声音系统(Open Sound System,OSS)是一个在 Unix 操作系统上用于发出和取得声音的接口。它是基于标准的 Unix 设备(即 POSIX 的读、写、ioctl 等)。 这个 API 设计成使用传统 Unix 的 open()、read()、write...
linux系统下的Open Sound System Programmer s Guide,就是oss了。对写linux下音频驱动和音频应用程序的朋友很有帮助。
苍穹外卖阿里云oss存储笔记
oss是open sound system的缩写。该文档是对oss的系统介绍。
Linux Open Sound System(OSS--Linux 的音频驱动) 4.x Programmer's Guide。
Xiaomi_Kernel_OpenSource,小米内核开源:cancro kk oss(包含mi 3w、mi 3c、mi 4系列、mi note)、armani jb oss(h1s)、dior kk oss(hm note-lte)、法拉利l-oss(小米4i)、thmoas kk oss(hm2 lte)、libra-l-...
Linux Sound Driver OSS emulation layer for the mixer interface
怎么将OSS挂载到Linux的操作过程
小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss示例小程序直传oss...
using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using Aliyun.OSS; using UnityEditor; using Aliyun.OSS.Common; public class AliyunOss { /...
小程序配置阿里云OSS下载文件,在请求头里配置生成强制下载链接,所需文件,因为在阿里云oss平台只能设置查看/下载 ,一种方式,对于某些业务需求不能够满足,所以此思路就是--在设置时把文件设置成公共读,然后拿到...
harbor配置oss1
介绍SAP如何使用OSS连接,操作步骤详细
oss upload use for oss upload ,you can use it aliyun open store it is a important c interface thank you .
android 集成OSS 上传图片
在2.6系列内核中,ALSA已经成为默认的声音子系统,用来替换2.4系列内核中的OSS(Open Sound System,开放声音系统)。但是开发者需要安装这个开发库,编译很简单,./configure && make即可,编译的时候添加上-...
OSS联结,简单的说是把自己的SAP服务器和SAP的服务器做联结的方法,方便SAP来检查服务器的运行状况和解决问题。
OSS远程上传附件文件,单个多个,可以对文件删除
2008-2009年 中国电信运营支撑系统(OSS)市场研究 年度总报告
阿里云存储服务( Open Open StorageStorage StorageStorage ServiceServiceService Service,简称 OSS ),是阿里云对外提供的 ),是阿里云对外提供的 海量,安全低成本高可靠的 云存储服务。用户以通过简单REST...