[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]
{
> - trying to produce a 400hz sound in one channel and a 404hz sound in
> another... How difficult will that be for me? Do I even need to invest
> in a book, or might someone have some code floating around ... *GRiN*
Well, I can help you for the PC Speaker, I've once picked this source up from a
Dutch pascal echo:------------------------------
}
Unit SoundU;
Interface
Uses
Dos;
Procedure DoubleSound(Freq1,Freq2,Duration,SampleFrequency:Real);
{Play two tones simulatisly: Does sort of:
Sound(Freq1) + Sound(Freq2)
Delay(Duration/SampeFrequency*1000)
NoSound;
}
Procedure Cli;
{ disable interrupt }
Inline($fa);
Procedure Sti;
{ enable interrupt }
Inline($fb);
Implementation
Type { general multitype record for typecasting }
mtype = Record
Case Byte Of
2: (o,s: Word);
4: (l: LongInt);
End;
Const
Clk8253 = 1193180; { Clock input to 8253A-5 timerchip }
Var
old_vector: Pointer; { pointer to original interrupt interrupt }
dacptr1,dacptr2: Word;{ pointer to start of buffer }
step1,step2: mtype; { table step value }
Frac1,Frac2: Word; { fractional part of pointer }
OnsShotTable: Array[0..255] Of Byte; { Table of Timer 2 ReLoad Values }
SineTable: Array[0..255] Of Byte; { Sine Table }
Timer0Reload: Word;
CountDown: Word;
factor: Real;
{$S-}
procedure Int8; Assembler;
asm
push ax
push bx
push cx
push ds
mov ax,Seg @Data
mov ds,ax
cmp CountDown,0 { Timeout ? }
jz @Exit
dec CountDown
mov bx,dacptr1 { Get first sample }
mov ax,step1.o
add Frac1,ax
adc bx,step1.s
mov dacptr1,bx
and bx,$ff
mov al,[bx+offset SineTable]
cbw
mov cx,ax
mov bx,dacptr2 { Get second sample }
mov ax,step2.o
add Frac2,ax
adc bx,step2.s
mov dacptr2,bx
and bx,$ff
mov al,[BX+Offset SineTable]
cbw
add ax,cx { Add samples }
sar ax,1 { Adjust }
add al,$80 { Signed to Absolute }
mov bx,Offset OnsShotTable { Now, lookup Timer 2 Reload value }
xlat
out $42,al { Reload timer channel 2 }
@Exit:
mov al,$20 { send End_Of_Interrupt }
out $20,al
pop ds
pop cx
pop bx
pop ax
sti { Position not critical }
iret
end;
{$S+}
Procedure DoubleSound(Freq1,Freq2,Duration,SampleFrequency:Real);
Var
I:Byte;
Begin
{INIT}
Timer0Reload:=Round(Clk8253/SampleFrequency);
SampleFrequency:=Round(Clk8253/Timer0Reload);
factor:=Clk8253/(SampleFrequency*(256+5));
For I:=0 To 255 Do OnsShotTable[I]:=1+Round(I*factor);
For I:=0 To 255 Do SineTable[I]:=Byte(Round(Sin((2*Pi*I)/256)*127));
{ Calculate first SineTable Stepvalue }
step1.l:=Round(65536.0*freq1*256.0/SampleFrequency);
dacptr1:=0;
Frac1:=0;
{ Calculate second SineTable Stepvalue }
step2.l:=Round(65536.0*freq2*256.0/SampleFrequency);
dacptr2:=0;
Frac2:=0;
{ Calculate Timeout value }
CountDown:=Round(SampleFrequency*duration);
{ OK, time to enable our int8 procedure }
GetIntVec(8,old_vector);
cli;
SetIntVec(8,@Int8);
{ initialize 8253 timer-chip }
{ 8255 PPI, Enable Speaker, Speaker input Gate = output from 8253 channel 2 }
port[$61]:=port[$61] Or $03;
port[$43]:=$90; { Channel 2, Read/Write only LSB, Mode 0=OneShot, Binary }
{ Set Interrupt 8 frequency (samplefrequency) }
port[$43]:=$36; { Channel 0, Read/Write LSB then MSB, Mode 3=SqrW, Binary }
port[$40]:=Lo(Timer0Reload); { LSB }
port[$40]:=Hi(Timer0Reload); { MSB }
sti; { Start PC Speak'ing }
Repeat
{ BEEP'ING }
Until CountDown=0;
cli;
SetIntVec(8,old_vector); { restore original int8 vector }
port[$43]:=$36;
port[$40]:=$00;
port[$40]:=$00;
sti;
end; { output_sound }
end.
[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]