[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]