home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / MKSM106.LZH / MKMSGCVT.LZH / MKMUSIC.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-12-10  |  7.6 KB  |  284 lines

  1. Unit MKMusic;
  2.  
  3. {$I MKB.Def}
  4.  
  5. {Base on code written by Gregory Arakelian and later modified
  6.  by Ted Lassagne and E Kosiewicz}
  7.  
  8. {
  9.      MKMusic - Copyright 1993 by Mark May - MK Software
  10.      You are free to use this code in your programs, however
  11.      it may not be included in Source/TPU function libraries
  12.      without my permission.
  13.  
  14.      Mythical Kingom Tech BBS (513)237-7737 HST/v32
  15.      FidoNet: 1:110/290
  16.      Rime: ->MYTHKING
  17.      You may also reach me at maym@dmapub.dma.org
  18. }
  19.  
  20.  
  21. Interface
  22.  
  23. Uses
  24. {$IFDEF WINDOWS}
  25.   MKWCrt;
  26. {$ELSE}
  27.   {$IFDEF OPRO}
  28.   OpCrt;
  29.   {$ELSE}
  30.   Crt;
  31.   {$ENDIF}
  32. {$ENDIF}
  33.  
  34. Type KeyProc = Procedure(Var Stop: Boolean);
  35. Type KeyPressProc = Function: Boolean;
  36.  
  37.  
  38. Procedure PlayInit;
  39. Procedure Play (TuneString:string);
  40. Procedure KeyNone(Var Stop: Boolean);
  41.  
  42. Const
  43.   MusicKeyProc: KeyProc = KeyNone;
  44.   MusicKeyPressed: KeyPressProc = KeyPressed;
  45.  
  46.  
  47. Implementation
  48.  
  49.  
  50. {$IFDEF WINDOWS}
  51. Uses WinTypes, WinProcs;
  52. {$ENDIF}
  53.  
  54.  
  55. Const
  56.     SharpOffset = 60;
  57.  
  58.  
  59. Const PitchArray: Array[1..120] of Word = (
  60.   28, 31, 33, 37, 41, 44, 49, 55, 62, 65,
  61.   73, 82, 87, 98, 110, 123, 131, 147, 165, 175,
  62.   196, 220, 247, 262, 294, 330, 349, 392, 440, 494,
  63.   523, 587, 659, 698, 784, 880, 988, 1047, 1175, 1319,
  64.   1397, 1568, 1760, 1976, 2093, 2349, 2637, 2794, 3136, 3520,
  65.   3951, 4186, 4699, 5274, 5588, 6272, 32139, 9738, 1934, 39659,
  66.   29, 33, 35, 39, 44, 46, 52, 58, 65, 69,
  67.   78, 87, 92, 104, 117, 131, 139, 156, 175, 185,
  68.   208, 233, 262, 277, 311, 349, 370, 415, 466, 523,
  69.   554, 622, 698, 740, 831, 932, 1047, 1109, 1245, 1397,
  70.   1480, 1661, 1865, 2093, 2217, 2489, 2794, 2960, 3322, 3729,
  71.   4186, 4435, 4978, 5588, 5920, 6645, 35669, 33772, 1772, 18119);
  72.  
  73.  
  74. Const
  75.   BaseOctave: Integer = 0;
  76.   Octave: Integer = 3;
  77.   GenNoteType: Integer = 4;
  78.   Tempo: Integer = 120;
  79.   PlayFrac: Byte = 7;
  80.  
  81. Var
  82.   vq: LongInt;         {Windows voice queue}
  83.   TmpPitch: LongInt;
  84.  
  85.  
  86. Procedure KeyNone(Var Stop: Boolean);
  87.   Begin
  88.   Stop := False;
  89.   End;
  90.  
  91.  
  92. Procedure PlayInit;
  93.   Begin
  94.   BaseOctave := 0;
  95.   Octave := 3;         {Third octave - starts with middle C}
  96.   GenNoteType := 4;    {Quarter note}
  97.   Tempo := 120;        {120 beats per minute}
  98.   PlayFrac := 7;       {Normal - note plays for 7/8 of time}
  99.   End;
  100.  
  101.  
  102.  
  103.  
  104. Procedure Play (TuneString:string);
  105.   Var
  106.     PlayTime: LongInt;
  107.     IdleTime: LongInt;
  108.     DotTime: LongInt;
  109.     NoteTime  : LongInt;
  110.     NoteType: Integer;
  111.     PitchIndex: Integer;
  112.     Position: Integer;
  113.     Number : Integer;
  114.     Code: Integer;
  115.     TuneStrLen: Integer;
  116.     Character: Char;
  117.     PlayDone: Boolean;
  118.  
  119.  
  120.   Procedure NVal(Pos:integer; var v, code: integer);
  121.   {Extracts a numeric value "v" from the tune string starting at
  122.    the index Pos.  The returned value in "code" is the number of
  123.    digits scanned plus one.}
  124.   Var
  125.     Posn:integer;
  126.  
  127.   Begin
  128.   v := 0;
  129.   posn := Pos;
  130.   while (posn <= TuneStrLen) and
  131.   (TuneString[posn] in ['0'..'9']) do
  132.     Begin
  133.     v := v*10 + ord(TuneString[posn]) - ord ('0');
  134.     Inc(posn);
  135.     End;
  136.   code := posn - Pos + 1;
  137.   End;
  138.  
  139.   {$IFDEF WINDOWS}
  140.   Procedure NoSound;
  141.     Begin
  142.     StopSound;
  143.     End;
  144.   {$ENDIF}
  145.  
  146.  
  147.  
  148.   Procedure CheckDots; {Checks for dots after note or pause}
  149.     Begin
  150.     While (Position <= TuneStrLen) and
  151.     (TuneString[Position] = '.') do
  152.       Begin
  153.       DotTime := DotTime + DotTime div 2;
  154.       inc(Position)
  155.       End;
  156.     End;
  157.  
  158.  
  159.   Begin {Play subroutine}
  160.   {$IFDEF WINDOWS}
  161.   vq := OpenSound;
  162.   {$ENDIF}
  163.   PlayDone := False;
  164.   CheckBreak := false;
  165.   TuneStrLen := length(TuneString);
  166.   Position := 1;
  167.   Repeat
  168.     NoteType := GenNoteType;
  169.     DotTime := 1000;
  170.     Character := upcase(TuneString[Position]);
  171.     Case Character Of
  172.       'A'..'G' : Begin
  173.                  PitchIndex := (ord(Character)-64)+Octave*7;
  174.                  If (Character='A') or (Character='B') Then
  175.                    PitchIndex := PitchIndex + 7;  {next octave}
  176.                  inc(Position);
  177.  
  178.                  {Check for sharp or flat}
  179.                  if Position <= TuneStrLen then
  180.                    case TuneString[Position] of
  181.                      '#','+': begin
  182.                               PitchIndex := PitchIndex+SharpOffset;
  183.                               inc(Position);
  184.                               end;
  185.                      '-': begin
  186.                           PitchIndex := PitchIndex+SharpOffset - 1;
  187.                           inc(Position);
  188.                           end;
  189.                      End;
  190.  
  191.                      {Check for length following note}
  192.                  if (Position <= TuneStrLen) and
  193.                  (TuneString[Position] in ['0'..'9']) then
  194.                    begin
  195.                    NVal(Position,NoteType,Code);
  196.                    inc(Position, Code - 1)
  197.                    end;
  198.  
  199.                    {Check for dots after note}
  200.                  CheckDots;
  201.  
  202.                  {Play the note}
  203.                  NoteTime := Round(DotTime/Tempo/NoteType*240);
  204.                  PlayTime := Round(NoteTime*PlayFrac/8);
  205.                  IdleTime := NoteTime-PlayTime;
  206.                  {$IFDEF WINDOWS}
  207.                  StopSound;
  208.                  TmpPitch := PitchArray[PitchIndex];
  209.                  SetVoiceSound(Vq, TmpPitch shl 16, 10000);
  210.                  StartSound;
  211.                  {$ELSE}
  212.                  Sound(PitchArray[PitchIndex]);
  213.                  {$ENDIF}
  214.                  Delay(PlayTime);
  215.                  if IdleTime <> 0 then
  216.                    begin
  217.                    NoSound;
  218.                    Delay(IdleTime)
  219.                    end;
  220.  
  221.                  if keypressed then
  222.                    MusicKeyProc(PlayDone);
  223.                  End;
  224.       'L' :  {Note length (1 thru 64).  "1" signifies a
  225.                      whole note and "64" a 64th note.}
  226.             Begin
  227.             NVal (Position+1,GenNoteType,Code);
  228.             if (GenNoteType < 1) or (GenNoteType > 64) then
  229.               GenNoteType := 4;
  230.             inc(Position, Code);
  231.             End;
  232.       'M' :  {Note length modifier - "S" for staccato,
  233.              "L" for legato, or "N" for normal.}
  234.             Begin
  235.             if Position < TuneStrLen then
  236.               begin
  237.               Case upcase(TuneString[Position+1]) Of
  238.                 'S' : PlayFrac := 6;
  239.                 'N' : PlayFrac := 7;
  240.                 'L' : PlayFrac := 8;
  241.                 End;
  242.               inc(Position, 2);
  243.               end;
  244.             End;
  245.       'O' :  {Octave specification (0 thru 7)}
  246.             Begin
  247.             NVal (Position+1,Octave,Code);
  248.             Octave := Octave+BaseOctave;
  249.             if Octave > 7 then
  250.               Octave := 3;
  251.             inc(Position, Code);
  252.             End;
  253.       'P' :  {Pause (rest) followed by optional value of
  254.                      1 thru 64, with "1" signifying a whole rest
  255.                      and "64" a 64th rest.}
  256.             Begin
  257.             NoSound;
  258.             NVal (Position+1,NoteType,Code);
  259.             if (NoteType < 1) or (NoteType > 64) then
  260.               NoteType := GenNoteType;
  261.               inc(Position, Code);
  262.               CheckDots;
  263.               IdleTime := DotTime Div Tempo * (240 Div NoteType);
  264.               Delay (IdleTime);
  265.               End;
  266.       'T' :  {Tempo - number of beats per minute (32 - 255)}
  267.             Begin
  268.             NVal (Position+1,Tempo,Code);
  269.             if (Tempo < 32) or (Tempo > 255) then
  270.               Tempo := 120;
  271.             inc(Position, Code);
  272.             End;
  273.       Else
  274.         inc(Position);   {Ignore spurious characters}
  275.       End;
  276.     Until ((Position > TuneStrLen) Or (PlayDone));
  277.     NoSound;
  278.     {$IFDEF WINDOWS}
  279.     CloseSound;
  280.     {$ENDIF}
  281.     End;
  282.  
  283. End.
  284.