Linux音频编程指南四

来源:互联网 发布:java job quartz 编辑:程序博客网 时间:2024/05/22 05:25
4.3 音频录放框架

  下面给出一个利用声卡上的DSP设备进行声音录制和回放的基本框架,它的功能是先录制几秒种音频数据,将其存放在内存缓冲区中,然后再进行回放,其所有的功能都是通过读写/dev/dsp设备文件来完成的:

  /*

  * sound.c

  */

  #include <unistd.h>

  #include <fcntl.h>

  #include <sys/types.h>

  #include <sys/ioctl.h>

  #include <stdlib.h>

  #include <stdio.h>

  #include <linux/soundcard.h>

  #define LENGTH 3    /* 存储秒数 */

  #define RATE 8000   /* 采样频率 */

  #define SIZE 8      /* 量化位数 */

  #define CHANNELS 1  /* 声道数目 */

  /* 用于保存数字音频数据的内存缓冲区 */

  unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];

  int main()

  {

  int fd; /* 声音设备的文件描述符 */

  int arg; /* 用于ioctl调用的参数 */

  int status;   /* 系统调用的返回值 */

  /* 打开声音设备 */

  fd = open("/dev/dsp", O_RDWR);

  if (fd < 0) {

  perror("open of /dev/dsp failed");

  exit(1);

  }

  /* 设置采样时的量化位数 */

  arg = SIZE;

  status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);

  if (status == -1)

  perror("SOUND_PCM_WRITE_BITS ioctl failed");

  if (arg != SIZE)

  perror("unable to set sample size");

  /* 设置采样时的声道数目 */

  arg = CHANNELS;

  status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);

  if (status == -1)

  perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");

 if (arg != CHANNELS)

  perror("unable to set number of channels");

  /* 设置采样时的采样频率 */

  arg = RATE;

  status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);

  if (status == -1)

  perror("SOUND_PCM_WRITE_WRITE ioctl failed");

  /* 循环,直到按下Control-C */

  while (1) {

  printf("Say something:\n");

  status = read(fd, buf, sizeof(buf)); /* 录音 */

  if (status != sizeof(buf))

  perror("read wrong number of bytes");

  printf("You said:\n");

  status = write(fd, buf, sizeof(buf)); /* 回放 */

  if (status != sizeof(buf))

  perror("wrote wrong number of bytes");

  /* 在继续录音前等待回放结束 */

  status = ioctl(fd, SOUND_PCM_SYNC, 0);

  if (status == -1)

  perror("SOUND_PCM_SYNC ioctl failed");

  }

  }

  4.4 混音器框架

  下面再给出一个对混音器进行编程的基本框架,利用它可以对各种混音通道的增益进行调节,其所有的功能都是通过读写/dev/mixer设备文件来完成的:

  /*

  * mixer.c

  */

  #include <unistd.h>

  #include <stdlib.h>

  #include <stdio.h>

  #include <sys/ioctl.h>

  #include <fcntl.h>

  #include <linux/soundcard.h>

  /* 用来存储所有可用混音设备的名称 */

  const char *sound_device_names[] = SOUND_DEVICE_NAMES;

  int fd;                  /* 混音设备所对应的文件描述符 */

  int devmask, stereodevs; /* 混音器信息对应的位图掩码 */

  char *name;

  /* 显示命令的使用方法及所有可用的混音设备 */

  void usage()

  {

  int i;

  fprintf(stderr, "usage: %s <device> <left-gain%%> <right-gain%%>\n"

  "       %s <device> <gain%%>\n\n"

  "Where <device> is one of:\n", name, name);

  for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)

  if ((1 << i) & devmask) /* 只显示有效的混音设备 */

  fprintf(stderr, "%s ", sound_device_names[i]);

  fprintf(stderr, "\n");

  exit(1);

  }

  int main(int argc, char *argv[])

  {

  int left, right, level;  /* 增益设置 */

  int status;              /* 系统调用的返回值 */

  int device;              /* 选用的混音设备 */

  char *dev;               /* 混音设备的名称 */

  int i;

  name = argv[0];

/* 以只读方式打开混音设备 */

  fd = open("/dev/mixer", O_RDONLY);

  if (fd == -1) {

  perror("unable to open /dev/mixer");

  exit(1);

  }

  /* 获得所需要的信息 */

  status = ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask);

  if (status == -1)

  perror("SOUND_MIXER_READ_DEVMASK ioctl failed");

  status = ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs);

  if (status == -1)

  perror("SOUND_MIXER_READ_STEREODEVS ioctl failed");

  /* 检查用户输入 */

  if (argc != 3 && argc != 4)

  usage();

  /* 保存用户输入的混音器名称 */

  dev = argv[1];

  /* 确定即将用到的混音设备 */

  for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)

  if (((1 << i) & devmask) && !strcmp(dev, sound_device_names[i]))

  break;

  if (i == SOUND_MIXER_NRDEVICES) { /* 没有找到匹配项 */

  fprintf(stderr, "%s is not a valid mixer device\n", dev);

  usage();

  }

  /* 查找到有效的混音设备 */

  device = i;

  /* 获取增益值 */

  if (argc == 4) {

  /* 左、右声道均给定 */

  left  = atoi(argv[2]);

  right = atoi(argv[3]);

  } else {

  /* 左、右声道设为相等 */

  left  = atoi(argv[2]);

  right = atoi(argv[2]);

  }

  /* 对非立体声设备给出警告信息 */

  if ((left != right) && !((1 << i) & stereodevs)) {

  fprintf(stderr, "warning: %s is not a stereo device\n", dev);

  }

  /* 将两个声道的值合到同一变量中 */

  level = (right << + left;

  /* 设置增益 */

  status = ioctl(fd, MIXER_WRITE(device), &level);

  if (status == -1) {

  perror("MIXER_WRITE ioctl failed");

  exit(1);

  }

  /* 获得从驱动返回的左右声道的增益 */

  left  = level & 0xff;

  right = (level & 0xff00) >> 8;

  /* 显示实际设置的增益 */

  fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right);

  /* 关闭混音设备 */

  close(fd);

  return 0;

  }

  编译好上面的程序之后,先不带任何参数执行一遍,此时会列出声卡上所有可用的混音通道:

  [xiaowp@linuxgam sound]$ ./mixer

  usage: ./mixer <device> <left-gain%> <right-gain%>

  ./mixer <device> <gain%>

  Where <device> is one of:

  vol pcm speaker line mic cd igain line1 phin video

  之后就可以很方便地设置各个混音通道的增益大小了,例如下面的命令就能够将CD输入的左、右声道的增益分别设置为80%和90%:

  [xiaowp@linuxgam sound]$ ./mixer cd 80 90

  cd gain set to 80% / 90%

  五、小结

  随着Linux平台下多媒体应用的逐渐深入,需要用到数字音频的场合必将越来越广泛。虽然数字音频牵涉到的概念非常多,但在Linux下进行最基本的音频编程却并不十分复杂,关键是掌握如何与OSS或者ALSA这类声卡驱动程序进行交互,以及如何充分利用它们提供的各种功能,熟悉一些最基本的音频编程框架和模式对初学者来讲大有裨益

原创粉丝点击