home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kompon / d2345 / BEEP004.ZIP / btOdeum.pas < prev    next >
Pascal/Delphi Source File  |  2001-05-27  |  33KB  |  906 lines

  1. (*
  2.  
  3. -----------------------------------------------------------------------------------------
  4.                                      STATE
  5. -----------------------------------------------------------------------------------------
  6.  THIS SOFTWARE IS FREEWARE AND IS PROVIDED AS IS AND COMES WITH NO WARRANTY OF ANY
  7.  KIND, EITHER EXPRESSED OR IMPLIED. IN NO EVENT WILL THE AUTHOR(S) BE LIABLE FOR
  8.  ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE.
  9. -----------------------------------------------------------------------------------------
  10.                                   INFORMATION
  11. -----------------------------------------------------------------------------------------
  12.  Description : btBeeper uses the PC speaker to produce various sounds.
  13.                In fact you can make it play entire songs.
  14.  
  15.                It contains many "preset" sounds. You can play them
  16.                just calling the PlayPresetSound method.
  17.  
  18.                Also it has the ability to play songs or sounds
  19.                written in a plain ascii file.
  20.  
  21.                I wrote it just for fun but I think it maybe usefull
  22.                in some situations ie. when a sound card is not present
  23.                or when you don't like to use .wav files
  24.  
  25.                The code is straightforward and well commented - I think
  26.  
  27.                I used some fucntions posted to a (don't remember) newsgroup
  28.                by jatkins@paktel.compulink.co.uk (John Atkins)
  29.  Tested      : Delphi 5 , Win2K
  30.  Author      : Theo Bebekis <bebekis@otenet.gr> 
  31.  More info   :
  32.  License     : Freeware
  33.  Thanks to   : John Atkins [jatkins@paktel.compulink.co.uk]
  34. -----------------------------------------------------------------------------------------
  35.                                      HISTORY
  36. -----------------------------------------------------------------------------------------
  37.  Version   Date          Changes - Additions                                By
  38. -----------------------------------------------------------------------------------------
  39.  0.01      25.09.1988    Initial Version                                    
  40.  0.02      24.10.1988    ElapsedMillisecFrom function
  41.                          The ElapsedMillisecFrom function added as a
  42.                          correction to BeepFor function. ElapsedMillisecFrom
  43.                          posted to me by John Herbster (johnh@petronworld.com)
  44.                          as a solution to GetTickCount Win API function
  45.                          problem. Beeper uses GetTickCount to calculate
  46.                          the time for beep durations
  47.  0.03      26.10.1988    1. FBeeping boolean field added to prevent calling a
  48.                             beeping function again while a beep is currently
  49.                             played
  50.                          2. Application.ProcessMessages call removed from the
  51.                             BeepFor function's while loop to prevent undesired
  52.                             sound effects if the owner form is receiving
  53.                             moving messages or a new form is created modally
  54.                             while a beep is played at the same time
  55.  0.04      21.05.2001    Added TSoundThread and the helper classes
  56.  0.05      27.05.2001    Added BeepSequence method for playing sequences of sounds
  57.                          The BeepSequence method provided by
  58.                          Friedrich Ing. Hajny [Cum_Hajny@compuserve.com]
  59. -----------------------------------------------------------------------------------------
  60.    
  61. *)
  62.  
  63.  
  64. unit btOdeum;
  65.  
  66. interface
  67.  
  68. uses
  69.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
  70.  
  71. const
  72.  { WinApi Help denotes that frequency for the PC speaker (the dwFreq parameter for
  73.    the Windows Beep function ) must be in the range 37 through 32,767 (0x25 through 0x7FFF).
  74.    Well, I think that frequency > 5000 is to hard and reedy. The pitch is to high for the PC speaker.
  75.    In addition I founded easier to use preset frequencies as musical tones  - see below - than
  76.    directly use a particular frequency.
  77.    Of course the human ear can distinguish sounds lesser than a half step, so you always the chance
  78.    to use such intervals when calling TbtBeeper methods }
  79.  LOW_FREQ   = 40;
  80.  HIGH_FREQ  = 5000;
  81.  
  82.  { Denotes a pseudo - frequency for the rests }
  83.  REST = 1;
  84.  
  85.  { I use five octaves with TbtBeeper. C_0, C, C_1, C_2 and C_3.
  86.    C_1 is the C note written on the first ledger line below the treble clef. That is the C in the
  87.    middle of a piano keyboard,  where the commercial sign usualle appears   }
  88.  C_0 = 65;                 C = 131;               C_1 = 261;                  C_2 = 523;                  C_3 = 1046;
  89.              Cp_0 = 69;                Cp = 138;                Cp_1 = 277;                 Cp_2 = 554;                 Cp_3 = 1109;
  90.              //Db_0 = Cp_0;              Db = Cp;                 Db_1 = Cp_1;                Db_2 = Cp_2;                Db_3 = Cp_3;
  91.  D_0 = 73;                 D = 149;               D_1 = 293;                  D_2 = 587;                  D_3 = 1174;
  92.              Dp_0 =78 ;                Dp = 155;                Dp_1 = 311;                 Dp_2 = 622;                 Dp_3 = 1244;
  93.              //Eb_0 = Dp_0;              Eb = Dp;                 Eb_1 = Dp_1;                Eb_2 = Dp_2;                Eb_3 = Dp_3;
  94.  E_0 = 82;                 E = 165;               E_1 = 329;                  E_2 = 659;                  E_3 = 1318;
  95.  F_0 = 87;                 F = 174;               F_1 = 349;                  F_2 = 698;                  F_3 = 1397;
  96.              Fp_0 = 92;                Fp = 189;                Fp_1 = 370;                 Fp_2 = 740;                 Fp_3 = 1480;
  97.              //Gb_0 = Fp_0;              Gb = Fp;                 Gb_1 = Fp_1;                Gb_2 = Fp_2;                Gb_3 = Fp_3;
  98.  G_0 = 98;                 G = 196;               G_1 = 392;                  G_2 = 784;                  G_3 = 1568;
  99.              Gp_0 = 104;               Gp = 207;                Gp_1 = 415;                 Gp_2 = 830;                 Gp_3 = 1661;
  100.              //Ab_0 = Fp_0;              Ab = Gp;                 Ab_1 = Gp_1;                Ab_2 = Gp_2;                Ab_3 = Gp_3;
  101.  A_0 = 110;                A = 220;               A_1 = 440;                  A_2 = 880;                  A_3 = 1760;
  102.              Ap_0 = 116;               Ap = 233;                Ap_1 = 466;                 Ap_2 = 932;                 Ap_3 = 1864;
  103.              //Bb_0 = Ap_0;              Bb = Ap;                 Bb_1 = Ap_1;                Bb_2 = Ap_2;                Bb_3 = Ap_3;
  104.  B_0 = 123;                B = 247;               B_1 = 494;                  B_2 = 988;                  B_3 = 1975;
  105.  
  106.  
  107.                                      //
  108.  aFreqs : array[0..60] of integer  =  (  65,    69,    73,     78,    82,     87,    92,    98,    104,   110,   116,    123,
  109.                                         131,   138,   149,    155,   165,    174,   189,   196,    207,   220,   233,    247,
  110.                                         261,   277,   293,    311,   329,    349,   370,   392,    415,   440,   466,    494,
  111.                                         523,   554,   587,    622,   659,    698,   740,   784,    830,   880,   932,    988,
  112.                                        1046,  1109,  1174,   1244,  1318,   1397,  1480,   1568,   1661,  1760,  1864,  1975,
  113.                                           1);
  114.  
  115. Tones : array[0..60] of string[4] = ( 'C_0', 'Cp_0', 'D_0', 'Dp_0', 'E_0', 'F_0', 'Fp_0', 'G_0', 'Gp_0', 'A_0', 'Ap_0', 'B_0',
  116.                                         'C',   'Cp',   'D',   'Dp',   'E',   'F',   'Fp',   'G',   'Gp',   'A',   'Ap',   'B',
  117.                                       'C_1', 'Cp_1', 'D_1', 'Dp_1', 'E_1', 'F_1', 'Fp_1', 'G_1', 'Gp_1', 'A_1', 'Ap_1', 'B_1',
  118.                                       'C_2', 'Cp_2', 'D_2', 'Dp_2', 'E_2', 'F_2', 'Fp_2', 'G_2', 'Gp_2', 'A_2', 'Ap_2', 'B_2',
  119.                                       'C_3', 'Cp_3', 'D_3', 'Dp_3', 'E_3', 'F_3', 'Fp_3', 'G_3', 'Gp_3', 'A_3', 'Ap_3', 'B_3',
  120.                                       'REST');
  121.  
  122. THE_END  = 'FINE';
  123.  
  124.  
  125.  
  126.  
  127.  
  128. type
  129.   TPresetSound = ( psOK,
  130.                    psError,
  131.                    psWelcome,
  132.                    psEmergency,
  133.                    psWrong,
  134.                    psCall,
  135.                    psOfficial,
  136.                    psDaze,
  137.                    psFall,
  138.                    psChord,
  139.                    psWhisle,
  140.                    psHanging,
  141.                    psClimb );
  142.  
  143.  
  144.   TBeatDuration = (bd_500, bd_1000, bd_1500, bd_2000);
  145.  
  146.  
  147. type
  148. (*--------------------------------------------------------------------------------*)
  149.   TbtBeeper = class(TComponent)
  150.   private
  151.     FBeatDuration  : TBeatDuration;
  152.     FDuration      : integer;
  153.     FDefaultSound  : TPresetSound;
  154.     SoundList      : TObject;
  155.     SoundThread    : TThread;
  156.     procedure SetBeatDuration(Value:TBeatDuration);
  157.   public
  158.     constructor Create(AOwner: TComponent); override;
  159.     destructor Destroy; override;
  160.     procedure PlayDefaultSound;
  161.     procedure PlayPresetSound(Sound:TPresetSound);
  162.     procedure BeepSequence(ToneAndMSecs: array of DWord);
  163.     procedure BeepFor(Tone : Word; MSecs : DWORD);
  164.     procedure Beep(Tone : Word);
  165.     procedure Pause;
  166.     procedure PauseFor(MSecs : DWORD);
  167.     procedure PlayTextFile(FileName, Song: string);
  168.   published
  169.     { BeatDuration affects only the Beep and the Pause methods}
  170.     property BeatDuration : TBeatDuration read FBeatDuration write SetBeatDuration default bd_1000;
  171.     property DefaultSound : TPresetSound  read FDefaultSound write FDefaultSound default psOK;
  172.   end;
  173.  
  174.  
  175. procedure Register;
  176. procedure StartBeep(Freq : Word);
  177. procedure StopBeep;
  178.  
  179.  
  180. implementation
  181.  
  182.  
  183.  
  184. type
  185.   EBeepError = class(Exception);
  186.  
  187.  
  188. (*----------------------------------------------------------------------------------*)
  189. procedure RaiseError(const Msg: string);
  190. begin
  191.   raise EBeepError.Create(Msg);
  192. end;
  193. (*----------------------------------------------------------------------------------*)
  194. procedure RaiseErrorFmt(const Msg: string; const Args: array of const);
  195. begin
  196.   raise EBeepError.CreateFmt(Msg, Args);
  197. end;
  198.  
  199.  
  200.  
  201.  
  202. { utilities }
  203. (*--------------------------------------------------------------------------------*)
  204. procedure Register;
  205. begin
  206.    RegisterComponents('BT Controls', [TbtBeeper]);
  207. end;
  208. {John Atkins [jatkins@paktel.compulink.co.uk] functions for playing beeps}
  209. (*--------------------------------------------------------------------------------*)
  210. function _GetPort(address:word):word;
  211. var
  212.  bValue: byte;
  213. begin
  214.   asm
  215.     mov dx, address
  216.     in al, dx
  217.     mov bValue, al
  218.   end;
  219.   Result := bValue;
  220. end;
  221. (*--------------------------------------------------------------------------------*)
  222. procedure _SetPort(address, Value:Word);
  223. var
  224.  bValue: byte;
  225. begin
  226.   bValue := Trunc(Value and 255);
  227.   asm
  228.     mov dx, address
  229.     mov al, bValue
  230.     out dx, al
  231.   end;
  232. end;
  233. (*--------------------------------------------------------------------------------*)
  234. procedure StartBeep(Freq : Word);
  235. var
  236.   B: Byte;
  237. begin
  238.   if (Freq >= LOW_FREQ) and (Freq <= HIGH_FREQ) then
  239.   begin
  240.     Freq := Word(1193181 div LongInt(Freq));
  241.     B := Byte(_GetPort($61));
  242.     if (B and 3) = 0 then
  243.     begin
  244.       _SetPort($61, Word(B or 3));
  245.       _SetPort($43, $B6);
  246.     end;
  247.     _SetPort($42, Freq);
  248.     _SetPort($42, Freq shr 8);
  249.   end;
  250. end;
  251. (*--------------------------------------------------------------------------------*)
  252. procedure StopBeep;
  253. var
  254.  Value: Word;
  255. begin
  256.   Value := _GetPort($61) and $FC;
  257.   _SetPort($61, Value);
  258. end;  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267. { TCmd }
  268. type
  269. (*--------------------------------------------------------------------------------*)
  270.   TCmd = class
  271.   public
  272.     Tone     : Word;
  273.     Duration : DWORD;
  274.     procedure DoSound;
  275.     constructor Create(Tone: Word; Duration: DWORD);      
  276.   end;   
  277.  
  278. (*--------------------------------------------------------------------------------*)
  279. constructor TCmd.Create(Tone: Word; Duration: DWORD);
  280. begin
  281.   inherited Create;
  282.   Self.Tone := Tone;
  283.   Self.Duration := Duration;
  284. end;
  285. (*--------------------------------------------------------------------------------
  286.  Description : generates a Tone a MSecs long
  287.  Notes       : The WinAPI Help states that the GetTickCount function retrieves the number of
  288.                milliseconds that have elapsed since Windows was started and because the
  289.                elapsed time is stored as a DWORD value, after 49.7 days of continuous use of the PC
  290.                the tick count recycles back to zero (that's what WinApi help says)
  291.  
  292.                So if we get the value for the StartTime and immediately after that the tick count
  293.                goes back to zero, because of the 49.7 days limit, we are getting an endless
  294.                loop with the next line
  295.  
  296.                while ( (GetTickCount - StartTime) < LongInt(Duration) ) do Application.ProcessMessages;
  297.  
  298.                Thanks to John Herbster (johnh@petronworld.com) who pointed all that to me and provided
  299.                the ElapsedMillisecFrom function I hope we 'll not have any further problem
  300.                with the GetTickCount and the 49.7 limit using:
  301.  
  302.                while ElapsedMillisecFrom(StartTime) < Duration do {play};
  303. ---------------------------------------------------------------------------------*)
  304. procedure TCmd.DoSound;
  305.   {-------------------------------------------------------------}
  306.   { ElapsedMillisecFrom by John Herbster (johnh@petronworld.com)}
  307.   function ElapsedMillisecFrom(StartMillisec: DWORD): DWORD;
  308.   const Magic = $80000000;
  309.   var
  310.    CurMS : DWORD;
  311.   begin
  312.     CurMS := GetTickCount;
  313.     If CurMS >= StartMillisec
  314.     then Result := CurMS - StartMillisec
  315.     else Result := (CurMS + Magic) - (StartMillisec - Magic);
  316.   end;
  317.    {-------------------------------------------------------------}
  318. var
  319.   StartTime : DWORD;
  320. begin
  321.  
  322.   if Tone = REST then
  323.   begin
  324.     StartTime:= GetTickCount;
  325.     while ElapsedMillisecFrom(StartTime) < Duration  do {pause};
  326.     Exit;
  327.   end;
  328.  
  329.  if (Win32Platform = VER_PLATFORM_WIN32_NT) then
  330.     Windows.Beep (Tone, Duration)
  331.  else begin
  332.    StartBeep(Tone);
  333.    StartTime := GetTickCount;
  334.    while ElapsedMillisecFrom(StartTime) < Duration do {play};
  335.    StopBeep;  
  336.  end;  
  337.  
  338. end;
  339.  
  340.  
  341.  
  342.  
  343. { TCriticalSection }
  344. type     
  345. (*--------------------------------------------------------------------------------*)
  346.   TCriticalSection = class (TObject)
  347.   private
  348.     FCS: TRTLCriticalSection;
  349.   public
  350.     constructor Create; 
  351.     destructor Destroy; override;
  352.     procedure Enter;
  353.     procedure Leave;
  354.   end;
  355.  
  356. (*--------------------------------------------------------------------------------*)
  357. constructor TCriticalSection.Create;
  358. begin
  359.   inherited Create;
  360.   InitializeCriticalSection(FCS);
  361. end;
  362. (*--------------------------------------------------------------------------------*)
  363. destructor TCriticalSection.Destroy;
  364. begin
  365.   DeleteCriticalSection(FCS);
  366.   inherited Destroy;
  367. end;
  368. (*--------------------------------------------------------------------------------*)
  369. procedure TCriticalSection.Enter;
  370. begin
  371.   EnterCriticalSection(FCS);
  372. end;
  373. (*--------------------------------------------------------------------------------*)
  374. procedure TCriticalSection.Leave;
  375. begin
  376.   LeaveCriticalSection(FCS);
  377. end;
  378.  
  379.  
  380.  
  381.  
  382.  
  383. { TProtected - TQueueList}
  384. type  
  385. (*--------------------------------------------------------------------------------*)
  386.   TProtected = class
  387.   protected
  388.     CS   : TCriticalSection;
  389.     List : TStringList;
  390.   public
  391.     constructor Create;
  392.     destructor Destroy; override;
  393.   end;
  394.  
  395.   TQueueAction = (qaPushTop, qaPushBottom, qaPop);       
  396. (*--------------------------------------------------------------------------------*)
  397.   TQueueList = class(TProtected)
  398.   private
  399.     Thread : TThread;
  400.     procedure AccessItem(var Obj: TObject; Action: TQueueAction);  // TQueueAction = (qaPushTop, qaPushBottom, qaPop);
  401.   public
  402.     constructor Create(T: TThread);
  403.     destructor Destroy; override;
  404.  
  405.     procedure Push(Obj: TObject);
  406.     procedure PushTop(Obj: TObject);
  407.     function  Pop: TObject;
  408.   end;
  409.  
  410.  
  411.  
  412. { TProtected }
  413. (*--------------------------------------------------------------------------------*)
  414. constructor TProtected.Create;
  415. begin
  416.   inherited Create;
  417.   CS := TCriticalSection.Create;
  418.   List := TStringList.Create;
  419. end;
  420. (*--------------------------------------------------------------------------------*)
  421. destructor TProtected.Destroy;
  422. begin
  423.   CS.Free;
  424.   List.Free;
  425.   inherited Destroy;
  426. end;
  427.  
  428.  
  429.  
  430. { TQueueList }
  431. (*--------------------------------------------------------------------------------*)
  432. constructor TQueueList.Create(T: TThread);
  433. begin
  434.   inherited Create;
  435.   Thread := T;
  436. end;
  437. (*--------------------------------------------------------------------------------*)
  438. destructor TQueueList.Destroy;
  439. begin
  440.   while List.Count > 0 do
  441.   begin
  442.     TCmd(List.Objects[0]).Free;
  443.     List.Delete(0);
  444.   end;
  445.   inherited Destroy;
  446. end;
  447. (*--------------------------------------------------------------------------------*)
  448. procedure TQueueList.AccessItem(var Obj: TObject; Action: TQueueAction);
  449. begin
  450.   CS.Enter;
  451.   try
  452.     case Action of
  453.       qaPushTop    : begin
  454.                        if List.Count = 0 then
  455.                          List.AddObject('', Obj)
  456.                        else List.InsertObject(0, '', Obj);
  457.  
  458.                        if Thread <> nil then
  459.                          if Thread.Suspended then
  460.                            Thread.Resume;  { resume the Thread if needed }
  461.                      end;
  462.       qaPushBottom : begin
  463.                        List.AddObject('', Obj);
  464.                        if Thread <> nil then
  465.                          if Thread.Suspended then
  466.                            Thread.Resume;  { resume the Thread if needed }
  467.                      end;
  468.       qaPop        : begin
  469.                        if List.Count = 0 then
  470.                        begin
  471.                          Obj := nil;
  472.                          Exit;
  473.                        end;
  474.                        Obj := TObject(List.Objects[0]);
  475.                        List.Delete(0);
  476.                      end;
  477.     end;
  478.   finally
  479.     CS.Leave;
  480.   end;
  481. end;
  482. (*--------------------------------------------------------------------------------*)
  483. function TQueueList.Pop: TObject;
  484. begin
  485.   AccessItem(Result, qaPop);
  486. end;
  487. (*--------------------------------------------------------------------------------*)
  488. procedure TQueueList.Push(Obj: TObject);
  489. begin
  490.   AccessItem(Obj, qaPushBottom);
  491. end;
  492. (*--------------------------------------------------------------------------------*)
  493. procedure TQueueList.PushTop(Obj: TObject);
  494. begin
  495.   AccessItem(Obj, qaPushTop);
  496. end;
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510. { TSoundThread }
  511. type
  512. (*--------------------------------------------------------------------------------*)
  513.   TSoundThread = class(TThread)
  514.   private
  515.     Beeper : TbtBeeper;
  516.   protected
  517.     procedure Execute; override;
  518.   public
  519.     constructor Create(Beeper : TbtBeeper);
  520.     procedure ResumeThread;
  521.     procedure SuspendThread;
  522.   end;
  523.  
  524.  
  525.  
  526. (*--------------------------------------------------------------------------------*)
  527. constructor TSoundThread.Create(Beeper : TbtBeeper);
  528. begin
  529.   inherited Create(True);       { Create thread suspended }
  530.   Priority        := tpNormal;
  531.   FreeOnTerminate := False;     { Thread does not free Itself when terminated }
  532.   Self.Beeper     := Beeper;
  533. end;
  534. (*--------------------------------------------------------------------------------*)
  535. procedure TSoundThread.ResumeThread;
  536. begin
  537.  if Suspended then Resume;
  538. end;
  539. (*--------------------------------------------------------------------------------*)
  540. procedure TSoundThread.SuspendThread;
  541. begin
  542.   if not Suspended then Suspend;
  543. end;
  544. (*--------------------------------------------------------------------------------*)
  545. procedure TSoundThread.Execute;
  546. var
  547.   Cmd : TCmd;
  548. begin   
  549.   while (Terminated = False) do
  550.   begin
  551.     Cmd := TCmd(TQueueList(Beeper.SoundList).Pop);  
  552.     if (Cmd = nil) then
  553.       SuspendThread
  554.     else begin
  555.       Cmd.DoSound;
  556.       Cmd.Free;
  557.     end;
  558.   end;
  559. end;
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566. { TbtBeeper }
  567. (*--------------------------------------------------------------------------------*)
  568. constructor TbtBeeper.Create(AOwner:TComponent);
  569. begin
  570.   inherited Create(AOwner);
  571.   FBeatDuration  := bd_1000;
  572.   FDuration      := 1000;
  573.   FDefaultSound  := psOK;
  574.   SoundThread    := TSoundThread.Create(Self);
  575.   SoundList      := TQueueList.Create(SoundThread);
  576. end;
  577. (*--------------------------------------------------------------------------------*)
  578. destructor TbtBeeper.Destroy;
  579. begin
  580.   SoundThread.Terminate;
  581.   repeat
  582.     Application.ProcessMessages;
  583.   until TSoundThread(SoundThread).Terminated;
  584.     
  585.   SoundThread.Free;
  586.   SoundList.Free;
  587.  
  588.   inherited Destroy;
  589. end;
  590. (*--------------------------------------------------------------------------------*)
  591. procedure TbtBeeper.PlayDefaultSound;
  592. begin
  593.   PlayPresetSound(FDefaultSound);
  594. end;
  595. (*--------------------------------------------------------------------------------
  596.  Description  : plays a sequence of sounds
  597.  Example call : BeepSequence([F_2, 200,
  598.                               B_1, 200,
  599.                               F_2, 200 ]);
  600.  Author       : Friedrich Ing. Hajny [Cum_Hajny@compuserve.com]
  601. ---------------------------------------------------------------------------------*)
  602. procedure TbtBeeper.BeepSequence(ToneAndMSecs: array of DWord);
  603. var
  604.   Inx: Integer;
  605. begin
  606.   if Length(ToneAndMSecs) = 0 then Exit;
  607.   for Inx := Low(ToneAndMSecs) to (Pred(High(ToneAndMSecs)) div 2) do   
  608.     TQueueList(SoundList).Push(TCmd.Create(ToneAndMSecs[Inx * 2], ToneAndMSecs[Succ(Inx * 2)]));
  609. end;
  610. (*--------------------------------------------------------------------------------*)
  611. procedure TbtBeeper.PlayPresetSound(Sound:TPresetSound);
  612. begin     
  613.  
  614.   case Sound of
  615.     psOK          : begin
  616.                       BeepFor (Ap_2,100);
  617.                       BeepFor (B_2, 100);
  618.                       BeepFor (C_3, 100);
  619.                     end;   
  620.     psError       : begin
  621.                       BeepFor (Fp_0,150);
  622.                       BeepFor (REST,200);
  623.                       BeepFor (C_0,500);
  624.                     end; 
  625.     psWelcome     : begin
  626.                       BeepFor (Ap_2,100);
  627.                       BeepFor (B_2, 100);
  628.                       BeepFor (C_3, 100);
  629.                       BeepFor (REST,100);
  630.                       BeepFor (C_3, 100);
  631.                       BeepFor (B_2, 100);
  632.                       BeepFor (Ap_2,100);
  633.                     end;   
  634.     psEmergency   : begin
  635.                       BeepFor (F_2,200);
  636.                       BeepFor (B_1, 200);
  637.                       BeepFor (F_2,200);
  638.                       BeepFor (B_1, 200);
  639.                       BeepFor (F_2,200);
  640.                       BeepFor (B_1, 200);
  641.                       BeepFor (F_2,200);
  642.                       BeepFor (B_1, 200);
  643.                     end; 
  644.     psWrong       : begin
  645.                       BeepFor (C_1,150);
  646.                       BeepFor (B,50);
  647.                       BeepFor (Ap,50);
  648.                       BeepFor (A,50);
  649.                       BeepFor (Gp,50);
  650.                       BeepFor (G,50);
  651.                       BeepFor (Fp,50);
  652.                       BeepFor (F,50);
  653.                       BeepFor (E,50);
  654.                       BeepFor (Dp,50);
  655.                       BeepFor (D,50);
  656.                       BeepFor (Cp,50);
  657.                       BeepFor (C,100);
  658.                       BeepFor (C_0,200);
  659.                     end;
  660.     psCall        : begin
  661.                       BeepFor (G,650);
  662.                       BeepFor (REST,100);
  663.                       BeepFor (E,500);
  664.                     end;
  665.     psOfficial    : begin
  666.                       BeepFor (G,200);
  667.                       BeepFor (REST,50);
  668.                       BeepFor (G,200);
  669.                       BeepFor (REST,50);
  670.                       BeepFor (G,200);
  671.                       BeepFor (REST,50);
  672.                       BeepFor (E,700);
  673.                       BeepFor (REST,100);
  674.                       BeepFor (C_1,200);
  675.                       BeepFor (REST,50);
  676.                       BeepFor (C_1,200);
  677.                       BeepFor (REST,50);
  678.                       BeepFor (C_1,200);
  679.                       BeepFor (REST,50);
  680.                       BeepFor (C,700);
  681.                     end;  
  682.     psDaze        : begin
  683.                       BeepFor (E_1,100);
  684.                       BeepFor (Dp_1,100);
  685.                       BeepFor (D_1,100);
  686.                       BeepFor (Dp_1,100);
  687.                       BeepFor (E_1,100);
  688.                       BeepFor (Dp_1,100);
  689.                       BeepFor (D_1,100);
  690.                       BeepFor (Dp_1,100);
  691.                       BeepFor (E_1,100);
  692.                       BeepFor (Dp_1,100);
  693.                       BeepFor (D_1,100);
  694.                       BeepFor (Dp_1,100);
  695.                     end;
  696.     psFall        : begin
  697.                       BeepFor (E_1,100);
  698.                       BeepFor (Dp_1,100);
  699.                       BeepFor (D_1,100);
  700.                       BeepFor (Dp_1,100);
  701.  
  702.                       BeepFor (F_1,100);
  703.                       BeepFor (E_1,100);
  704.                       BeepFor (Dp_1,100);
  705.                       BeepFor (E_1,100);
  706.  
  707.                       BeepFor (Fp_1,100);
  708.                       BeepFor (F_1,100);
  709.                       BeepFor (E_1,100);
  710.                       BeepFor (F_1,100);
  711.                     end;
  712.     psChord       : begin
  713.                       BeepFor (B_1,80);
  714.                       BeepFor (Ap_1,80);
  715.                       BeepFor (A_1,80);
  716.                       BeepFor (Gp_1,80);
  717.                       BeepFor (G_1,80);
  718.                       BeepFor (Fp_1,80);
  719.                       BeepFor (F_1,80);
  720.                       BeepFor (E_1,80);
  721.                       BeepFor (Dp_1,80);
  722.                       BeepFor (D_1,80);
  723.                       BeepFor (Cp_1,80);
  724.                       BeepFor (C_1,80);
  725.                     end;
  726.     psWhisle      : begin
  727.                       BeepFor (C_2,80);
  728.                       BeepFor (F_2,80);
  729.                       BeepFor (G_2,80);
  730.                       BeepFor (C_3,80);
  731.                     end;  
  732.     psHanging     : begin
  733.                       BeepFor (G_2,80);
  734.                       BeepFor (C_3,80);
  735.                       BeepFor (Gp_2,80);
  736.                       BeepFor (Cp_3,80);
  737.                       BeepFor (A_2,80);
  738.                       BeepFor (D_3,80);
  739.                       BeepFor (Ap_2,80);
  740.                       BeepFor (Dp_3,80);
  741.                       BeepFor (B_2,80);
  742.                       BeepFor (E_3,80);
  743.                       BeepFor (C_3,80);
  744.                       BeepFor (F_3,80);
  745.                     end;
  746.     psClimb       : begin
  747.                       BeepFor (C_1,80);
  748.                       BeepFor (Cp_1,80);
  749.                       BeepFor (D_1,80);
  750.                       BeepFor (Dp_1,80);
  751.                       BeepFor (E_1,80);
  752.                       BeepFor (F_1,80);
  753.                       BeepFor (Fp_1,80);
  754.                       BeepFor (G_1,80);
  755.                       BeepFor (Gp_1,80);
  756.                       BeepFor (A_1,80);
  757.                       BeepFor (Ap_1,80);
  758.                       BeepFor (B_1,80);
  759.                     end;
  760.   end;
  761.  
  762. end;
  763. (*--------------------------------------------------------------------------------*)
  764. procedure TbtBeeper.Beep(Tone : word);
  765. begin
  766.   BeepFor(Tone, FDuration);
  767. end;              
  768. (*--------------------------------------------------------------------------------*)
  769. procedure TbtBeeper.BeepFor(Tone : Word; MSecs : DWORD);
  770. begin
  771.   TQueueList(SoundList).Push(TCmd.Create(Tone, MSecs));
  772. end;  
  773. (*--------------------------------------------------------------------------------*)
  774. procedure TbtBeeper.Pause;
  775. begin
  776.   PauseFor(FDuration);
  777. end;     
  778. (*--------------------------------------------------------------------------------*)
  779. procedure TbtBeeper.PauseFor(MSecs : DWORD);
  780. begin
  781.   BeepFor(REST, MSecs);
  782. end;
  783. (*--------------------------------------------------------------------------------*)
  784. procedure TbtBeeper.SetBeatDuration(Value:TBeatDuration);
  785. begin
  786.   if Value <> FBeatDuration then           
  787.   begin
  788.     FBeatDuration := Value;
  789.     case Value of
  790.       bd_500  : FDuration := 500 ;
  791.       bd_1000 : FDuration := 1000;
  792.       bd_1500 : FDuration := 1500;
  793.       bd_2000 : FDuration := 2000;
  794.     end;
  795.   end;
  796. end;
  797. (*--------------------------------------------------------------------------------
  798.  Description : opens an ascii file and plays a song
  799.                This file can be written with any text editor like notepad.
  800.                The form of the file:
  801.                <song title>
  802.                <freq const>, <duration>,
  803.                <freq const>, <duration>,
  804.                <freq const>, <duration>,
  805.                .
  806.                .
  807.                .
  808.                FINE
  809.  Note        : see Songs.txt for an example
  810.                You can have more than one song in the same file
  811. ---------------------------------------------------------------------------------*)
  812. procedure TbtBeeper.PlayTextFile(FileName, Song: string);
  813. const
  814.   InValidChars = [#0..#47,#58..#64, #91..#94, #96, #123..#255];
  815. var
  816.  Stream            : TMemoryStream;
  817.  szFirst,
  818.  szLast,
  819.  szHolder          : PChar;
  820.  sTone,
  821.  sMSecs            : string;
  822.  i                 : integer;
  823. begin
  824.  
  825.  
  826.   Stream:=TMemoryStream.Create;
  827.   try                          
  828.     Stream.LoadFromFile(FileName);
  829.  
  830.     sTone  :='';
  831.     sMSecs :='';
  832.  
  833.     szFirst:= StrPos( Stream.Memory, PChar(Song) );
  834.  
  835.     if szFirst = nil  then
  836.     begin
  837.       RaiseErrorFmt('Can Not Locate Song %s in %s', [Song, FileName]);
  838.     end
  839.     else begin
  840.       GetMem(szHolder, 5);                                       // get mem for the holder PChar
  841.       try
  842.         Inc(szFirst, Length(Song) + 1);                          // move szFirst after song title
  843.         while True  do                                           // loop for ever
  844.         begin
  845.           while szFirst^ in InValidChars do Inc(szFirst);        // skip blanks
  846.           FillChar(szHolder^, 5, #0);                            // zero the szHolder
  847.           StrLCopy(szHolder, szFirst, 4);                        // get first 4 chars
  848.           if String(szHolder) = THE_END then Break;
  849.  
  850.           szLast:= StrScan( szFirst, ',' );                      // look for the next comma
  851.           if szLast = nil then                                   // if ok
  852.            RaiseError('Beeper: Wrong Char');
  853.  
  854.           FillChar(szHolder^, 5, #0);                            // zero the szHolder
  855.           StrLCopy(szHolder, szFirst, (szLast ) - szFirst);      // copy chars until szLast - 1 to szHolder
  856.           sTone:=StrPas(szHolder);                               // convert it to Pascal string
  857.           szFirst:=szLast + 1;                                   // move szFirst after next comma
  858.  
  859.           while szFirst^ in InValidChars do Inc(szFirst);        // skip blanks
  860.           szLast:= StrScan( szFirst, ',' );                      // look for the next comma
  861.           if szLast = nil then                                   // if ok
  862.            RaiseError('Beeper: Wrong Char');
  863.  
  864.           FillChar(szHolder^, 5, #0);                            // zero the szHolder
  865.           StrLCopy(szHolder, szFirst, (szLast) - szFirst);       // copy chars until szLast - 1 to szHolder
  866.           sMSecs:=StrPas(szHolder);                              // convert it to Pascal string
  867.           szFirst:=szLast + 1;                                   // move szFirst after next comma
  868.  
  869.           for i:= 0 to 60 do
  870.           if sTone = Tones[i] then                               // play the sound
  871.           begin
  872.             BeepFor(aFreqs[i], StrToInt(sMSecs));
  873.             Break;
  874.           end;
  875.         end;
  876.       finally
  877.         FreeMem(szHolder, 5);
  878.       end;
  879.     end;
  880.  
  881.   finally
  882.     Stream.Clear;
  883.     Stream.Free;
  884.   end;
  885. end; 
  886.  
  887.  
  888.  
  889.  
  890.  
  891.  
  892. end.
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901.  
  902.  
  903.  
  904.  
  905.  
  906.