DSP

Linux音频编程指南四

2019-07-13 15:15发布

4.3 音频录放框架   下面给出一个利用声卡上的DSP设备进行声音录制和回放的基本框架,它的功能是先录制几秒种音频数据,将其存放在内存缓冲区中,然后再进行回放,其所有的功能都是通过读写/dev/dsp设备文件来完成的:   /*   * sound.c   */   #include   #include   #include   #include   #include   #include   #include   #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: ");   status = read(fd, buf, sizeof(buf)); /* 录音 */   if (status != sizeof(buf))   perror("read wrong number of bytes");   printf("You said: ");   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   #include   #include   #include   #include   #include   /* 用来存储所有可用混音设备的名称 */   const char *sound_device_names[] = SOUND_DEVICE_NAMES;   int fd;                  /* 混音设备所对应的文件描述符 */   int devmask, stereodevs; /* 混音器信息对应的位图掩码 */   char *name;   /* 显示命令的使用方法及所有可用的混音设备 */   void usage()   {   int i;   fprintf(stderr, "usage: %s "   "       %s "   "Where is one of: ", name, name);   for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)   if ((1 << i) & devmask) /* 只显示有效的混音设备 */   fprintf(stderr, "%s ", sound_device_names[i]);   fprintf(stderr, " ");   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 ", 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 ", 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%% ", dev, left, right);   /* 关闭混音设备 */   close(fd);   return 0;   }   编译好上面的程序之后,先不带任何参数执行一遍,此时会列出声卡上所有可用的混音通道:   [xiaowp@linuxgam sound]$ ./mixer   usage: ./mixer   ./mixer   Where 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这类声卡驱动程序进行交互,以及如何充分利用它们提供的各种功能,熟悉一些最基本的音频编程框架和模式对初学者来讲大有裨益