C语言中声音问题

woshizhouqi 2008-06-02 11:52:29
C语言中的一段代码只能使主板喇叭发声,不能从耳机里听到声音,谁能帮我解决
附代码:


#include<stdio.h>
#include<dos.h>
#include<graphics.h>
#include<fcntl.h>
#include<time.h>
void interrupt(* handler)( );
int handle,control;
enum NOTES
{
C10=131,D10=147,E10=165,F10=175,G10=196,A10=220,B10=247,
C0=262, D0=296, E0=330, F0=349, G0=392, A0=440, B0=494,
C1=523, D1=587, E1=659, F1=698, G1=784, A1=880, B1=988,
C2=1047, D2=1175, E2=1319, F2=1397, G2=1568, A2=1760, B2=1796
}song[]={
E1,16,E1,8,E1,8,F1,16,G1,16,F1,16,F1,16,E1,16,D1,
16,C1,16,C1,16,D1,16,E1,16,E1,16,D1,16,D1,16,E1,16,
E1,8,E1,8,F1,16,G1,16,G1,16,F1,16,E1,16,D1,16,C1,
16,C1,16,D1,16,E1,16,D1,16,D1,16,C1,16,D1,16,D1,8,
D1,8,E1,16,C1,16,D1,16,E1,8,F1,8,E1,16,C1,16,D1,
16,E1,8,F1,8,E1,16,C1,16,C1,16,D1,16,G0,16,E1,16,
E1,16,E1,8,F1,16,G1,16,G1,16,F1,16,E1,16,D1,16,C1,
16,C1,16,D1,16,E1,16,E1,16,D1,16,C1,16,D1,16,
0,0};
void interrupt music()
{
static int flag=0,note=0,fre,dur=8;
flag++;
fre=song[note];
dur=song[note+1];
if(fre)
{
flag=0;
/*打开计数器*/
outportb(0x43,0xb6);
/*计算频率*/
fre=(unsigned)(1193180L/fre);
/*将频率写入计时器*/
outportb(0x42,(char)fre);
outportb(0x42,(char)(fre>>8));
/*从扬声器端口读出控制信息*/
control=inportb(0x61);
/*写入扬声器,使之发声*/
outportb(0x61,(control)|0x3);
note=note+2;
if(note>=134)note=0;
}
}
void main()
{
int gdriver=DETECT,gmode,i,j;
initgraph (&gdriver,&gmode,"e:\\tc");
while(!kbhit())
{
/*获取0x1c中断向量*/
handler=getvect(0x1c);
/*将music函数写入到0x1c中断向量中去*/
setvect(0x1c,music);
/*清除屏幕*/
cleardevice( );
/*将背景色设置成黑色*/
setbkcolor(BLACK);
for(i=0;i<300;i++)
{
j=i%30;
/*前景色设置*/
setcolor(j/2);
/*画圆*/
circle(320,240,(j+1)*5);
if(j==0)cleardevice( );
delay(100);
}
}
/*关闭PC扬声器*/
outportb(0x61,control&0xfe);
/*将0x1c中断向量置成系统原有的处理例程*/
setvect(0x1c,handler);
getch();
cleardevice();
closegraph();
}


...全文
479 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
young123tao 2010-11-26
  • 打赏
  • 举报
回复
晕了,太复杂了
BG2UKY 2008-11-28
  • 打赏
  • 举报
回复
学习,但是在易语言下如何实现?
xiongwangmxf 2008-06-14
  • 打赏
  • 举报
回复
学习了..
lily2005lucky 2008-06-13
  • 打赏
  • 举报
回复
高!!![Quote=引用 6 楼 icansaymyabc 的回复:]
我见过一种电脑,内置声卡和立体声喇叭的,没有主板扬声器,可插上耳机取代喇叭,开机的自检声音都从声卡发出。

你换一台这样的电脑问题就解决了。
[/Quote]
EddyCoffee 2008-06-12
  • 打赏
  • 举报
回复
学习ING
刘光伟 2008-06-03
  • 打赏
  • 举报
回复
学习
  • 打赏
  • 举报
回复
PC机内的扬声器发出,所以这个问题将与硬件扬声器电路有关。
解决这一编程问题,让我们首先简单了解一下计算机发声的原理。在
PC机的系统板上装有定时与计数器 8253芯片,还有 8255可编程并行接口芯片,由它们组成的硬件电路可用来产生 PC机内扬声器的声音,对于 286、386、486、586等 PC微机,由于采用了超大
规模集成电路,因而看不到这些芯片,它们均集成在外围电路芯片上了。

当我们操作计算机时,常常听到的发声,就是由软件控制这些电路而产生的。声音的长短和音调的高低,均可由程序进行控制。在扬声器电路中,定时器的频率决定了扬声器发音的频率,所以可通过设定定时器电路的频率来使扬声器发出不同的声音。对定时器电路进行频率设定时,首先对其命令寄存器 (口地址为 0x43)写命令字,如写入 0xb6,这可用
outporb(0x43,0xb6);来实现,则表示选择该定时器的第二个通道,计数频率先送低
8位(二进制),后送高 8位。接着用口地址 0x42送频率计数值,先送低 8位,后送高 8位,即用 outportb(0x42,低 8位频率计数值 )和 outportb(0x42,高 8位频率计数值
)来实现。通过这两步使定时器电路产生一系列方波信号,此信号是否能推动扬声器发音,还要看由 8255产生的门控信号和送数信号是否为 1,而它们也可编程,口地址为 0x61。为了不影响 8255口地址 61H中的其他高位,应先输入口地址 6lH的现有值 bits,即用 bits= inportb(0x61)来实现,然后就可用 outportb(0x61,bits|3)来允许发声,而用 outportb(0x61,bits&0xfc)来禁止发声,且不改变 8255其它位原来的值,关于这方面的详细内容可以参阅 IBM PC/XT接口技术方面书籍有关内容。

编写音乐程序播放歌曲,最简单的方法是可以直接使用 TURBO C在 dos.h中提供的有关发声的函数 sound()和 nosound()。sound()函数用于产生声音,其原型如下:
void sound(unsigned frequency);
该函数的入口参数为扬声器要产生声音的频率。与 sound()函数相反,nosound ()函数用于关闭扬声器,其原型为:
void nosound(void);
该函数没有入口和出口参数,它只是简单地把口地址
61H中的低 2位清 0。

在利用函数
sound产生指定频率的声音后,一般要过一段时间后再调用函数 nosound关闭扬声器,这样我们才能清楚地听到一个声音。如果扬声器刚打开就关闭,我们是很难听到一个声音的。某个频率的声音延续时间的长短是重要的,它将直接影响音响效果。这需要使
用 TURBOC提供了专门的延时函数 delay,其原型说明如下:
void delay (unsigned milliseconds);该函数中断程序的执行,中断的时间由 milliseconds指定。

例程
该程序每间隔
10000 milliseconds pc扬声器发出不同频率的声音,直到频率大于
5000hz。
#include<dos.h>
main()
{

int freq;
for(freq=50;freq<5000;freq+=50)
{


sound (freq);

delay(10000);
}
nosound();


}

如果不能使用上述现成的函数
sound()和
nosound(),当然我们也可以采用上节中的方法,

I/O接口的输入输出函数,自己编写产生声音和关闭声音的函数。下面可供参考的函数
SOUND()与
TURBOC提供的产生声音函数
sound()的算法类似:首先函数
SOUND()中使用
了一个由一个整数和两个字符组成的联合,其目的在于方便地把一个
16位数分解成两个
8
位数。为了打开扬声器,需要把口地址
61H的低
2位置位,但又不能影响其他高位,为此,
先输入口地址
61H中的现有值,与
3逻辑或后再输出到口地址
61H。


void SOUND(unsigned frequency)
{


union { /* 定义由—个整数和两个字符组成的联合 */
unsigned divisor;
unsigned char c[2];

} tone;
tone.divisor=119328/frequency; /* 计算该频率对应的定时器计数值 */
outportb(0x43,0xb6); /* 通知定时器采用新的计数 */
outportb(0x42,tone.c[0]); /* 计数低字节先送到定时器 */
outportb(0x42,tone.c[1]); /* 计数高字节后送到定时器 */
outportb(0x61, inportb(0x61) | 3 ); /* 使定时器到喇叭的输出有效 */

}
如下供参考的函数
NOSOUND(),为了不影响口地址
61H中的其他高位,应先输入口地


6lH的现有值.在屏蔽掉低
2位后再输出到口地址
61H。
void NOSOUND(void)
{

outportb(0x61,inportb(0x61) & 0xfc)); /* 使定时器到喇叭的输出无效 */ }

薛定谔之死猫 2008-06-02
  • 打赏
  • 举报
回复
这个直接使用I/O操作进行声音输出了,只能到主板喇叭吧,要通过耳麦输出,应该是经过驱动程序这层了

虽然操作系统的DOS虚拟机会为你的程序进行相应的转换,不过你操作的就是扬声器,而不是音频输出
独孤过儿 2008-06-02
  • 打赏
  • 举报
回复
没有TC编译器,爱莫能助~~~
jeff_nie 2008-06-02
  • 打赏
  • 举报
回复
MARK.
icansaymyabc 2008-06-02
  • 打赏
  • 举报
回复
我见过一种电脑,内置声卡和立体声喇叭的,没有主板扬声器,可插上耳机取代喇叭,开机的自检声音都从声卡发出。

你换一台这样的电脑问题就解决了。
yuewei1231 2008-06-02
  • 打赏
  • 举报
回复
学习了



本人开了个关于编程学习的论坛 欢迎大家捧场
www.bbs.cxrs.net
Clerk_9919 2008-06-02
  • 打赏
  • 举报
回复
楼上的说的很对!!!

主板上的扬声器发声,与耳机或音响发声的方法是不一样的,不然就不需要声卡了和声卡驱动了!!
K行天下 2008-06-02
  • 打赏
  • 举报
回复
同意楼上,你的代码 只是使主板的扬声器发声。
如果想要耳机听得到,可以使用API函数:sound,具体用法见MSDN

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧