欢迎光临112期刊网!
网站首页 > 论文范文 > 计算机论文 > 计算机应用 > DOS下DSP播音的编程

DOS下DSP播音的编程

日期:2023-01-24 阅读量:0 所属栏目:计算机应用


  在dos下编程,将声音转化为数据记录下来,或将数据转化为声音,通过声卡上配置的喇叭回放出来,是一项很有实用价值和开发魅力的技术。时下流行的声卡,如sound blaster pro及其兼容卡,都配有数字声音处理器dsp芯片(digital sound processor),专门用于对声音进行数字记录及回放,是声音数字处理的基础硬件。而wav文件、voc文件等,则都是这些数据记载的具体形式。creative公司为了方便用户,提供了一组ct-voice驱动程序,专门针对voc文件,作为开发利用dsp功能的软接口,使用比较方便。但是,也造成了某些限制。对于开发者而言,直接对dsp硬件编程,实现其功能,也许是更有吸引力的。

  声音,无论是从扬声器输出的,还是从话筒输入的,都是模拟量。

  而数据,无论是内存里操作的,还是磁盘上存储的都是数字量。因此,微机处理声音,大多离不开adc与dac两种转换。由于声音数据的数据量比较大,在声音的数字处理中,除直接由cpu进行传输外,批量数据常采用dma方式传输,以节省较多的cpu时间。

  总括起来,adc与dac两种转换方式,直接传输和dma传输这两种传输方式,再加上不同的压缩方式,如喇叭控制、静寂等等,所有这些的不同组合,就构成了dsp的各种功能。根据dsp的硬件原理,其各种功能都规定了一定的操作步骤。

  一、dsp编程要点

  在dsp编程中,主要注意命令与端口两个层次的操作。

  命令。dsp的功能一般以一个操作码(称作命令号)的写操作为中心,按规定的步骤,配合若干必要的辅助操作,构成一串操作的组合,称为dsp命令。如8位直接播放功能命令号为10h,8位直接录音功能命令号为20h,喇叭的通断功能命令号分别为d1h与d3h等等。

  2.端口操作。dsp命令主要靠端口操作来实现。端口操作包括dsp初始化、写dsp命令(即发dsp命令)、读dsp状态参数、dsp中断等。所涉及的端口地址及相应的用途如表1。

  表1 dsp端口及用途

  端口地址由基址2x0h加6、0ah、0ch、0eh等形成,其中,x可取值1、2、3、4、5、6等,具体情况随硬件设置而定,多数卡在出厂被默认设置为2,即基址为220h。通过跳线,可改变此值,避免与其它设备口地址冲突。

  二、编程实例

  dsp的功能是比较丰富的,限于篇幅,本文只简要介绍其中的8位直接播放功能,由此举一反三,其它功能的用法不难得知。各功能的规定操作可参考文献1和2。

  1.命令操作步骤。8位直接播放功能的操作步骤如下:

  ·写命令号10h;

  ·写数据字节(即播放声音的8位数据);

  ·按采样率所需时间周期延时。

  以此三步操作为循环体,进行n次循环,即完成播放。其中,n为声音数据字节数。

  2.2xch端口写操作。在dsp编程中,无论是发送命令,还是发送数据,都是通过写端口2xch来完成的。在写端口2xch之前,应先读此端口,直到所得值的bit7为0,这才表明此端口处于可写状态,才能进行写操作。此过程的c语言形式如下:

  while (inportb(0x22c)&0x80);

  outportb(0x22c,byte);

  这里假定端口基址为220h。句中byte可以是命令号,也可以是数据。

  3.定时器。为使播放按一定的采样率进行,需对数据发送进行定时控制。这一般是借用主机定时中断int8,将其调用频率提高到与采样率相当的程度,利用其监视、控制数据发送的时间,来满足播音频率的要求。关于定时中断的编程技术已有过许多介绍,限于篇幅,不再赘述,读读文后的程序清单,即一目了然。应该说明的是,对于cpu较慢的机型如386,由于计时代码本身的执行时间可能已经超过采样率对应的时间周期,定时控制就达不到预期的效果。这种情况下,用一个空循环来定时,调整循环次数,即可满足频率要求。此法的缺点是定时精度差,参数因cpu速度而异。所幸的是,目前多数配置多媒体的pc机,其cpu都在486以上。

  4.内存利用。人耳可辨声音的最高频率可达20khz以上,因此dsp的采样率至少也要达到与此相当的水平,而为了容纳立体声双声道信息,采样率还要再翻一倍。常见的wav声音的采样率有44100、22050、11025等。在这么高的采样率下,声音的数据量自然很大,如44k采样率下,20秒的录音数据长达800多k。为在dos常规内存内处理这种规模的数据,实例程序采取了分块处理的方式,将数据分成以当前剩余自由内存大小为单位的块,将其逐次读入,逐次处理。同时,由于c语言的read()函数每次读操作的字节数最多不过64k-1,因此,每一个分块又需分

  若干次读入。实例表明,经此法处理的播放程序不受wav文件长度的限制,笔者在windows下录制的长达5m多的wav文件(11k采样率,约8分钟)也照播不误。

  5.声音文件。本文提供的程序实例其声音数据取自wav文件,其实,对于voc文件,本播放技术也一样适用,只不过数据的读取格式有所不同而已。关于wav文件的格式,可参考文献3,voc文件的格式参考献1和2。

  实例程序用borland c++ 3.1编译,在配置opti 386主板、海洋48

  6主板及多种与soundblaster pro兼容声卡的兼容机上运行通过。

  三、源程序清单

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include"timer.h"

  #define n1 20

  #define n2 100

  struct wavhead

  {

  char riff[4];

  long size0;

  char wavefmt[8];

  long size1;

  int fmttag;

  int channel;

  long samplespersec;

  long bytespersec;

  int blockalign;

  int bitspersample;

  char flg[4];

  }whead;

  unsigned port=0x210;

  char found=0;

  unsigned cnt1,cnt2;

  void portreset();

  void outwave(un

  signed char huge *,long);

  void writeportc(unsigned char);

  void errexit(char *);

  void main()

  {

  int fp;

  unsigned n,r,nn,i,j;

  char name[32];

  long fermem,rr,datasize;

  unsigned char huge *data,huge *p;

  if(argc<2)errexit("miss file name\n");

  strcpy(name,argv[1]);strcat(name,".wav");

  fp=-open(name,0-rdonly);if(fp=-1)errexit("error open fil

  e\n");

  -read(fp,&whead,sizeof(wavhead));

  if(lign=1 && strncmp(,"data",4)==0)

  {

  -read(fp,&datasize,4);//单声道wav数据

  }

  else if(lign=2 && strncmp(,"fact"

  ,4)==0)

  {

  lseek(fp,12l,1);

  -read(fp,&datasize,4);//双声道wav数据

  }

  else errexit("error file struct\n");

  farmem=farcoreleft();

  portreset();//初始化dsp端口

  counter=0;//开始计时

  settimer(newtimer,44100);//调整时间中断频率

  writeportc(0xd1);//接通喇叭

  if(farmem≥datasize)//数据量不超过内存容量

  {

  p=data=(unsigned char huge *)farmalloc(datasize);

  n=datasize/32768;r=datasize%32768;

  for(i=0;i

  -read(fp,p,r);

  outwave(data,datasize);

  }

  else//数据量超过内存容量

  {

  nn=datasize/farmem;//分块操作的块数

  rr=datasize%farmem;//最后一块的大小

  n=farmem/32768;//每块read次数

  r=farmem%32768;//read余零尾数

  data=(unsigned char huge *)farmalloc(farmem);

  for(i=0;i

  {

  p=data;

  for(j=0;j

  -read(fp,p,r);

  //读入内存

  outwave(data,farmem);//发送声音数据

  }

  p=data;

  n=rr/32768;r=rr%32768;//最后块的操作

  for(i=0;i

  -read(fp,p,r);

  //读入

  outwave(data,rr);//发送

  }

  writeportc(0xd3);//断开喇叭

  restoretimer();//恢复时间中断

  farfree(data);

  -close(fp);

  }

  void portreset()//初始化dsp端口

  {

  cnt1=n1;

  while(port≤0x260)&&!found)

  {//测端口基址

  outportb(port+6,1);

  outportb(port+6,0);

  cnt2=n2;

  while(cnt2>2 && inportb(port+0xe)<128)--cnt2;

  if(cnt2=0||inportb(port+0xa)!=oxaa)

  {

  --cnt1;

  if(cnt1==0)

  {

  cnt1=n1;

  port=port+0x10;

  }

  }

  else found=1;//找到基址

  }

  if(!found)errexit("reset failed\n");//找不到基址

  }

  void outwave(unsigned char huge *p,long len)

  {//发送声音数据

  long i;

  int smpl;

  smpl=lign;

  //采样周期系数

  for(i=0;i

  {

  writeportc(0x10);//发送命令

  writeportc(p[i]);//发送数据

  while(counter

  }

  }

  void writeportc(unsigned char v)

  {

  while(inportb(port+0xc)&0x80);//等待写有效状态

  outportb(port+0xc,v);//写端口(发送)

  }

  void errexit(char *msg)

  {

  -ax=3;

  asm int 10h

  printf(msg);

  exit(0);

  }

  //timer.h

  #includ

  #define oldtimerint 0x60

  unsigned long counter;

  unsigned counterint8,fpi8;

  void settimer(void interrupt(*rout)(…),unsigned freq)

  {//设置新频率的定时中断

  int icnt;

  fpi8=(freq+9)/18;//新旧频率的倍数

  asm cli

  icnt=1193180/freq;

  outportb(0x43,0x36);

  outportb(0x40,icnt & 255);

  outportb(0x40,icnt》8);

  setvect(oldtimerint,getvect(

  8));//保存旧定时中断

  setvect(8,rout);//置新的定时中断

  sam sti;

  }

  void restoretimer()

  {

  asm cli

  outportb(0x43,0x36);

  outportb(0x40,0);

  outportb(0x40,0);

  setvect(8,getvect(oldtimerint));//恢复原定时中断

  asm sti

  }

  void interrupt newtimer(…)

  {//新定时中断

  regpack r;

  counter++;//给应用程序提供新频率的计数

  if(--counterint8=0)

  {

  intr(oldtimerint,&r);//按原频率走动时钟

  counterint8=fpi8;//用新旧频率的倍数分频

  }

  else outportb(0x20,0x20);//退出中断

  }

  参考文献

  1 阎小兵等.多媒体开发工具.北京:电子工业出版社,1994.

  2 josha munnik等著,敬万钧等译.声霸--原理与应用.北京:电子工业出版社,1995.

  3 石宁等.在dos下使用windows *.wav文件.计算机世界月刊,1995(3)44-46.

本文链接:http://www.qk112.com/lwfw/jsjlw/jisuanjiyingyong/245558.html

论文中心更多

发表指导
期刊知识
职称指导
论文百科
写作指导
论文指导
论文格式 论文题目 论文开题 参考文献 论文致谢 论文前言
教育论文
美术教育 小学教育 学前教育 高等教育 职业教育 体育教育 英语教育 数学教育 初等教育 音乐教育 幼儿园教育 中教教育 教育理论 教育管理 中等教育 教育教学 成人教育 艺术教育 影视教育 特殊教育 心理学教育 师范教育 语文教育 研究生论文 化学教育 图书馆论文 文教资料 其他教育
医学论文
医学护理 医学检验 药学论文 畜牧兽医 中医学 临床医学 外科学 内科学 生物制药 基础医学 预防卫生 肿瘤论文 儿科学论文 妇产科 遗传学 其他医学
经济论文
国际贸易 市场营销 财政金融 农业经济 工业经济 财务审计 产业经济 交通运输 房地产经济 微观经济学 政治经济学 宏观经济学 西方经济学 其他经济 发展战略论文 国际经济 行业经济 证券投资论文 保险经济论文
法学论文
民法 国际法 刑法 行政法 经济法 宪法 司法制度 法学理论 其他法学
计算机论文
计算机网络 软件技术 计算机应用 信息安全 信息管理 智能科技 应用电子技术 通讯论文
会计论文
预算会计 财务会计 成本会计 会计电算化 管理会计 国际会计 会计理论 会计控制 审计会计
文学论文
中国哲学 艺术理论 心理学 伦理学 新闻 美学 逻辑学 音乐舞蹈 喜剧表演 广告学 电视电影 哲学理论 世界哲学 文史论文 美术论文
管理论文
行政管理论文 工商管理论文 市场营销论文 企业管理论文 成本管理论文 人力资源论文 项目管理论文 旅游管理论文 电子商务管理论文 公共管理论文 质量管理论文 物流管理论文 经济管理论文 财务管理论文 管理学论文 秘书文秘 档案管理
社科论文
三农问题 环境保护 伦理道德 城镇建设 人口生育 资本主义 科技论文 社会论文 工程论文 环境科学