求救 啊!!关于音乐的播放问题(有意思!270分)(270分)

  • 主题发起人 主题发起人 xingzhe_xr
  • 开始时间 开始时间
X

xingzhe_xr

Unregistered / Unconfirmed
GUEST, unregistred user!
小弟正在研究用机箱内的喇叭播放音乐(MEDI OR WAV)的问题……受阻……
特来请教各位高人!
我曾经找到一控件,他提供了一种发声方式(控件代码见后文)
PLAY(XXX,XXX);
OR
DOBLEEP(XXX,XXX);
但如果用这个去拼首歌就太…………
而且根本不知道XXX是哪个音……
所以想请教各位有无其他解决方法,谢谢!
如果可以提供一分
DOBLEEP(XXX,XXX)===(某个音)
的列表也行!

以下为控件代码
代码:
[:(!]
Unit BleepInt;
{ Version 4.2 }

{ Andy Preston - Apollo Developments, Swindon U.K. andy@apollod.freeserve.co.uk

HACKERS OF THE WORLD UNITE! HACKERS OF THE WORLD UNITE! HACKERS OF THE WORLD UNITE! HACKERS OF THE WORLD UNITE!

How to make your Delphi programs bleep like FRACTINT! See Demo1.pas/Demo1.dfm or Bleepint.htm for details
}

Interface

Type
TBleepType = (bOK, bInterrupt, bError);

Procedure ShutUp;
{ Added to help counter the effects ofdo
Bleep (Freq, -1).
If you are producing a tone, &
you want to stop withoutdo
ing another Bleep, call this procedure }

Proceduredo
Bleep (Freq : Word;
MSecs : Integer);
{ Duration of -1 means bleep until the next bleep sent, or ShutUp is called }

Procedure Bleep (BleepType : TBleepType);

Implementation

Uses
{$IFDEF WIN32} Windows, {$else
} WinProcs, {$ENDIF}
{$IFNDEF CONSOLE} Forms;
{$ENDIF} { Michl Ladislav suggested removing the Forms unit from 32-bit Console Apps, saving 130K }


{ -- --- -- --- -- --- -- --- -- --- -- --- -- --- Assembler Bits for Wind 3.x And '95 -- --- -- --- -- --- -- --- -- --- }

Procedure AsmShutUp;
{$IFDEF WIN32} Pascal;
{$ENDIF}
begin

Asm
In AL, $61 { Stop Bleeping }
And AL, $FC
Out $61, AL
end;

end;


Procedure AsmBeep (Freq : Word);
{$IFDEF WIN32} Pascal;
{$ENDIF}
Label
Skip;
begin

Asm
Push BX
In AL, $61
Mov BL, AL
And AL, 3
Jne Skip
Mov AL, BL
Or AL, 3
Out $61, AL
Mov AL, $B6
Out $43, AL
Skip: Mov AX, Freq
Out $42, AL
Mov AL, AH
Out $42, AL
Pop BX
end;

end;


{ -- --- -- --- -- --- -- --- -- --- -- --- -- --- Low Level Bits for Wind 3.x And '95 -- --- -- --- -- --- -- --- -- --- }

Procedure HardBleep (Freq : Word;
MSecs : Integer);
Var
{ Changed FirstTickCount from LongInt to DWord to counter P.Satyanarayana's Delphi 4 Warning - see below }
FirstTickCount : {$IFDEF WIN32} DWord {$else
} LongInt {$ENDIF};
begin

{ Michl Ladislav pointed out that having a delay when the bleep freq is out of range is a waste of 'stuff' so I've added
another begin
END }
If (Freq>=20) And (Freq<=5000) then
begin

AsmBeep (Word (1193181 Div LongInt(Freq)));
If MSecs>=0 then
begin

{ P.Satyanarayana Get's a warning under Delphi 4 here 'Comparing signed and unsigned types - widened both operands'
This should be cleared up by the fact that FirstTickCount is now a DWord under Win32 }
FirstTickCount:=GetTickCount;
{ Michl Ladislav suggested changing the old WHILEdo
to a REPEAT UNTIL so as to fit his modifications in easyer }
Repeat
{ Michl Ladislav suggested removing the Forms unit from 32-bit Console Apps, saving 130K }
{$IFNDEF CONSOLE} If MSecs>1000 then
Application.ProcessMessages;
{$ENDIF}
Until ((GetTickCount-FirstTickCount)>LongInt(MSecs));
AsmShutUp;
end;

end;

end;


{ -- --- -- --- -- --- -- --- -- --- -- --- -- --- -- --- Procedures for you to use -- --- -- --- -- --- -- --- -- --- -- --- }

Procedure Bleep (BleepType : TBleepType);
begin

Case BleepType of
bOK: begin

do
Bleep (1047,100);
do
Bleep (1109,100);
do
Bleep (1175,100);
end;

bInterrupt: begin

do
Bleep (2093,100);
do
Bleep (1976,100);
do
Bleep (1857,100);
end;

bError:do
Bleep (40,500);
end;

end;


{$IFDEF WIN32} Var SysWinNT : Boolean;
{$ENDIF}

Proceduredo
Bleep (Freq : Word;
MSecs : Integer);
begin

{$IFDEF WIN32} If SysWinNT then
Windows.Beep (Freq, MSecs) else
{$ENDIF}
HardBleep (Freq, MSecs);
end;


Procedure ShutUp;
begin

{$IFDEF WIN32} If SysWinNT then
Windows.Beep (1, 0) else
{$ENDIF}
AsmShutUp;
end;


{$IFDEF WIN32}

Procedure InitSysType;
Var
VersionInfo : TOSVersionInfo;
begin

VersionInfo.dwOSVersionInfoSize:=SizeOf (VersionInfo);
GetVersionEx (VersionInfo);
SysWinNt:=VersionInfo.dwPlatformID=VER_PLATFORM_WIN32_NT;
end;


Initialization
InitSysType;

{$ENDIF}

end.
 
这好像不太可能吧?!此控件提供的方法中的参数应该是频率和延时长度,但MIDI文件中
仅仅是乐器的编号、音值、时长等内容。而MIDI曲一般都是复音。
 
pc喇叭也就能放放单音,很久以前同事安装过一个“pc喇叭仿真声卡”的驱动,天啊,放出来
的声音噼里啪啦
 
那MEDI的单音播放也可以啊…………
 
放弃吧,你提供的控件只不过使机箱内的喇叭发出某一固定频率的波形(大概是方波),
但是,乐器中的某个音阶除了固定的频率还有很多特别的谐波,这样才能让我们区分出小
提琴的C和钢琴的C。
 
如果延迟只是0.1秒就不是方波了啊?
 
不,我们平时听的MP3或CD音乐是通过对正弦波(包括谐波)进行量化,比如44。1KHz
16bit,也就是说可以用方波近似得到正弦波。
你说的延迟0.1秒得到的仅仅是失真的方波,但这些方波的幅度、时长是固定的,而且仍然
无法得到谐波(这是非常重要的)。
 
继续说啊??
 
我以前曾经用c语言在dos下写过一个pc speaker 播放 wav的程序. 研究过一些.不过现在我用
2000了. 没有办法操作 pc speaker了. (
 
难道就没有人有办法了吗??
 
DOBleep (261,700);-------1
DOBleep (293,700);-------2
DOBleep (329,700);-------3
DOBleep (349,700);-------4
DOBleep (392,700);-------5
DOBleep (440,700);-------6
DOBleep (493,700);-------7



音调频率(HZ)=(15625*(2^音阶数))/(511-音调值)

音符 音调值
A 3
A# 31
B 58
C 83
C# 107
D 130
D# 151
E 172
F 191
F# 209
G 226
G# 242


音阶 范围(HZ)
0 31-61
1 61-122
2 122-244
3 244-488
4 489-977
5 978-1.95k
6 1.96-3.91k
7 3.910-7.81k
 
哦,这样行得通吗?我试试
 
非常遗憾,这是不可能的!
PC的破喇叭里只能产生可怜的方波!
 
利用一个原理可以让PC 喇叭放音乐的.
 
原理是这样的: 往某个端口的某个位置高电平 . PC Spk的输出就是高电平. 否则就是低电平.
循环控制的话, 就产生了方波. 循环频率变化的时候, 产生的方波就有音调的高低了.
利用这个原理可以是 spk 去模拟声卡输出不同的电平. 也就是让spk的纸盆有不同的震动幅度.
不再像前面所说的那样只有高低电平的变化了. 具体如下 : 要知道 从低电平变到高电平的时候这个过程是瞬间发生的.
而spk的纸盆变化却是个物理变化需要一定的时间. 在这短短的时间内. cpu可以向端口发出许多指令.
如果纸盆从从最低变到最高位置需要 0.01 ms 的话. 我们把最低到最高的位置划分为 256份.
想让纸盆震动到最大则需要 持续给端口高电平0.01ms . 如果只需要变化 128 ,也就是一半位置的话,就需要先给端口
发高电平. 等到纸盆快到128那一点的时候再发低电平. 这样纸盆就会停下来的.
基于这个原理.我们就可以让PC speaker 放出美妙的声音了.
 
看来不会有什么更好的答案了…………
 
后退
顶部