PROGRAM DeskTopCDPlayer;

{********************************************
 **         DESKTOP CD PLAYER 1.4          **
 **                                        **
 **             by D. Amor '92             **
 **                                        **
 **       written in KICK-PASCAL v2.1      **
 ********************************************}

{$opt q}

USES ExecIO,Intuition,Graphics;

CONST CD_RESET    = 1;
      CD_MOTOR    = 9;
      CD_CNUM     =13;
      CD_CSTATE   =14;
      CD_ISROM    =37;
      CD_PLAYTRACK=43;
      CD_TOCMSF   =49;
      CD_SUBQMSF  =51;
      CD_PAUSE    =52;
      CD_STOPPLAY =53;
      CD_FADE     =57;
      nTOC        =50;
      mCD         =100;

TYPE Bord_Type = ARRAY [01..10] OF INTEGER;
     Scro_Type = ARRAY [01..20] OF INTEGER;
     Port_Type = ARRAY [00..01] OF ^MsgPort;
     ioRq_Type = ARRAY [00..01] OF ^IOStdReq;
     Stri_Type = ARRAY [00..05] OF STRING[23];
     Thre_Type = STRING[3];
     Grup_Type = STRING[30];
     Gru2_Type = STRING[23];
     Load_Type = FILE OF CHAR;
     InSh_Type = ARRAY [0..13] OF IntuiText;
     BoSh_Type = ARRAY [0..04] OF Bord_Type;

VAR BorderDatA              : BoSh_Type;                 STATIC;
    ITxt                    : InSh_Type;                 STATIC;
    BorderA                 : ARRAY [0..7] OF Border;    STATIC;
    GadgetA                 : ARRAY [0..13] OF Gadget;   STATIC;
    cdStatus                : ^ARRAY [0..50] OF BYTE;    STATIC;
    TOCArray                : ^ARRAY [0..8*nTOC] OF BYTE;STATIC;
    BaTiSo                  : ^ARRAY [0..mCD] OF Grup_Type;STATIC;
    CD_Titles               : ^ARRAY [1..20] OF Grup_Type;STATIC;
    GroCD                   : ^RECORD
                                 Group: Grup_Type;
                                 CD   : Grup_Type;
                                 Song : Array [0..25] OF Gru2_Type;
                               END; STATIC;
    Win                     : ^Window;                   STATIC;
    ReplyPort               : Port_Type;                 STATIC;
    ioReq                   : ioRq_Type;                 STATIC;
    TAttr0                  : TextAttr;                  STATIC;
    max,watch,song,display,x: BYTE;                      STATIC;
    Fehler1,Fehler2         : LONG;                      STATIC;
    ende,pause,fade,play,info,
    single,repeet,removed   : BOOLEAN;                   STATIC;
    Msg                     : ^IntuiMessage;             STATIC;
    AktGad                  : ^Gadget;                   STATIC;
    MDat                    : ^Scro_Type;                STATIC;
    MImage1                 : Image;                     STATIC;
    PropInfo1               : PropInfo;                  STATIC;
    MyText                  : Stri_Type;                 STATIC;
    con                     : PTR;                       STATIC;
    ErrorMessage            : ^STRING[180];              STATIC;
    singer,zahl,oldzahl,d1,d2 : INTEGER;                   STATIC;

PROCEDURE Print(t: Stri_Type; x,y: BYTE);

VAR it: IntuiText;
    i : BYTE;

BEGIN
  FOR i:=0 TO 5 DO
  BEGIN
    it:=IntuiText(1,0,1,0,0,NIL,t[I],NIL);
    PrintIText(Win^.RPort,^it,x,y+i*9);
  END;
END;

PROCEDURE WaitStartUp;

BEGIN
  Removed:=TRUE;
  MyText:=Stri_Type("0 Tracks  ","00:00     ","No Disc   ","","","");
  Print(MyText,88,42);
END;

PROCEDURE CD_Action(command: BYTE; offSet, laenge: LONG; data: PTR;
                    channel: BYTE);

VAR ioError: INTEGER;

BEGIN
  WITH ioReq[channel]^ DO
  BEGIN
    io_Command:=command;
    io_Flags:=0;
    io_Length:=laenge;
    io_Data:=data;
    io_OffSet:=offset;
  END;
  IF command=CD_PLAYTRACK THEN
  BEGIN
    SendIO(ioReq[channel]);
    ioError:=0
  END
  ELSE ioError:=DoIO(ioReq[channel]);
  IF ioError=-6 THEN WaitStartUp;
END;

PROCEDURE Clear(y1,y2: BYTE);

BEGIN
  SetAPen(Win^.RPort,0);
  RectFill(Win^.RPort,88,y1,263,y2);
  SetAPen(Win^.RPort,1);
END;

PROCEDURE ShowBottom;

BEGIN
  MyText:=Stri_Type("","","",GroCD^.Song[song],GroCD^.CD,GroCD^.Group);
  Print(MyText,88,42);
END;

PROCEDURE AddNill(VAR mins,secs: Thre_Type; VAR min,sec: BYTE);

BEGIN
  mins:=INTSTR(min);
  secs:=INTSTR(sec);
  IF min<10 THEN mins:="0"+mins;
  IF sec<10 THEN secs:="0"+secs;
END;

PROCEDURE InitText;

BEGIN
  MyText:=Stri_Type("CD-Audio:",
                    "Playtime:",
                    "Status  :",
                    "Title   :",
                    "Album   :",
                    "Group   :");
  Print(MyText,8,42);
END;

PROCEDURE StopText(max,min,sec: BYTE);

VAR mins,secs: STRING[3];

BEGIN
  Clear(42,94);
  AddNill(mins,secs,min,sec);
  MyText:=Stri_Type(INTSTR(max)+" Tracks",mins+":"+secs,"Stop",
                    GroCD^.Song[song],GroCD^.CD,GroCD^.Group);
  Print(MyText,88,42);
END;

PROCEDURE StartUp;

BEGIN
  Removed:=FALSE;
  CD_Action(CD_ISROM,0,0,NIL,0);
  CD_Action(CD_TOCMSF,0,nTOC,TOCArray,0);
  max:=TOCArray^[3];
  StopText(max,TOCArray^[5],TOCArray^[6]);
END;

PROCEDURE ShowAll(VAR min,sec: BYTE; VAR song: BYTE; VAR play: BOOLEAN;
                  scan: BOOLEAN);

VAR tracks,mins,secs: STRING[3];
    StopPlaying     : STRING[15];
    TrackName       : STRING[25];
    Spaces          : STRING[25];
    I               : BYTE;

BEGIN
  tracks:=INTSTR(song);
  StopPlaying:="Stop       ";
  AddNill(mins,secs,min,sec);
  IF play THEN StopPlaying:="Playing    ";
  IF scan THEN StopPlaying:="Scanning   ";
  TrackName:=GroCD^.Song[song];
  Spaces:="";
  IF LENGTH(TrackName)<25 THEN FOR I:=1 TO 25-LENGTH(TrackName) DO Spaces:=Spaces+" ";
  TrackName:=TrackName+Spaces;
  MyText:=Stri_Type("Track "+tracks+"  ",mins+":"+secs+" ",StopPlaying,
                    Trackname,GroCD^.CD,GroCD^.Group);
  Print(MyText,88,42);
END;

PROCEDURE CheckSec(VAR sec,sec2,min: BYTE);

BEGIN
  sec:=sec-sec2;
  IF sec>59 THEN
  BEGIN
    sec:=sec+60;
    DEC(min);
  END
END;

PROCEDURE GetTime(VAR max,min,sec: BYTE);

VAR song2,min2,sec2: BYTE;

BEGIN
  min2:=TOCArray^[(song SHL 3)+5];
  sec2:=TOCArray^[(song SHL 3)+6];
  IF song<max THEN song2:=(song SHL 3)+13
              ELSE song2:=5;
  min:=TOCArray^[song2];
  sec:=TOCArray^[SUCC(song2)];
  min:=min-min2;
  CheckSec(sec,sec2,min);
END;

PROCEDURE ShowTrack(VAR song: BYTE; VAR play: BOOLEAN);

VAR min,sec: BYTE;

BEGIN
  Clear(42,94);
  GetTime(max,min,sec);
  ShowAll(min,sec,song,play,FALSE);
END;

PROCEDURE ShowNothing;

BEGIN
  MyText:=Stri_Type("","No Display","","","","");
  Print(MyText,88,42);
END;

PROCEDURE StartPlayer(VAR play,Single: BOOLEAN; VAR Song: BYTE);

BEGIN
  CD_Action(CD_PLAYTRACK,Song,SUCC(Max),NIL,0);
  play:=TRUE;
  DELAY(10+SONG SHL 2);
END;

PROCEDURE PausePlayer(VAR Pause: BOOLEAN);

BEGIN
  MyText:=Stri_Type("","","Pause     ","","","");
  Print(MyText,88,42);
  IF Pause THEN CD_Action(CD_PAUSE,0,1,NIL,1)
           ELSE CD_Action(CD_PAUSE,0,0,NIL,1);
  Pause:=NOT Pause;
END;

PROCEDURE StopPlayer(VAR play: BOOLEAN);;

VAR a: LONG;

BEGIN
  AbortIO(ioReq[0]);
  a:=WaitIO(ioReq[0]);
  CD_Action(CD_STOPPLAY,0,0,NIL,0);
  play:=FALSE;
END;

PROCEDURE DimOffPlayer(VAR Fade: BOOLEAN);

BEGIN
  IF Fade THEN CD_Action(CD_FADE,0,150,NIL,1)
          ELSE CD_Action(CD_FADE,32767,150,NIL,1);
  Fade:=NOT Fade
END;

PROCEDURE Scroll_Fade(VAR PropInfo1: PropInfo; VAR OldZahl,Zahl: INTEGER);

BEGIN
  OldZahl:=Zahl;
  WITH PropInfo1 DO Zahl:=32767-VertPot DIV (SUCC(VertBody) SHL 1);
  IF Zahl<>OldZahl THEN CD_Action(CD_FADE,Zahl,1,NIL,1);
END;

PROCEDURE CheckPlayer;

BEGIN
  IF play THEN
  BEGIN
    StopPlayer(play);
    StartPlayer(play,single,song);
  END
  ELSE ShowTrack(song,play);
END;

PROCEDURE ShowTime(VAR song: BYTE; VAR play,single,repeet: BOOLEAN;
                   scan: BOOLEAN);

VAR min,sec,min2,sec2,I,J: BYTE;

BEGIN
  CD_Action(CD_SUBQMSF,0,0,CDStatus,1);
  IF single THEN BEGIN
                   DELAY(10);
                   IF song<>CDStatus^[2] THEN
                   BEGIN
                     StopPlayer(play);
                     IF Repeet THEN
                     BEGIN
                       CD_Action(CD_PLAYTRACK,song,0,NIL,0);
                       play:=TRUE;
                     END;
                   END;
                 END
                 ELSE song:=CDStatus^[2];
  min:=CDStatus^[9];
  sec:=CDStatus^[10];
  CASE Display OF
    1: BEGIN
         GetTime(max,min2,sec2);
         min:=min2-min;
         CheckSec(sec2,sec,min);
         sec:=sec2;
       END;
    2..3: IF NOT single THEN
          BEGIN
            min2:=TOCArray^[(song SHL 3)+5];
            sec2:=TOCArray^[(song SHL 3)+6];
            min:=min2+min;
            sec:=sec2+sec;
            IF sec>59 THEN
            BEGIN
              sec:=sec-60;
              INC(min);
            END;
            IF Display=3 THEN
            BEGIN
              min:=TOCArray^[5]-min;
              sec2:=TOCArray^[6];
              CheckSec(sec2,sec,min);
              sec:=sec2;
            END;
          END
          ELSE
          BEGIN
            Display:=4;
            ShowNothing;
          END;
    OTHERWISE;
  END;
  DELAY(5);
  IF Display<4 THEN ShowAll(min,sec,song,play,scan);
END;

PROCEDURE ScanIntoCD;

VAR i,j: BYTE;

  FUNCTION GetAnswer: BOOLEAN;

  VAR AktGad: ^Gadget;

  BEGIN
    ShowTime(i,play,single,repeet,TRUE);
    DELAY(40);
    msg:=Get_Msg(Win^.UserPort);
    AktGad:=Msg^.IAddress;
    GetAnswer:=(AktGad^.GadgetID=5);
  END;

BEGIN
  FOR i:=1 TO max DO
  BEGIN
    CD_Action(CD_FADE,32767,0,NIL,1);
    StartPlayer(play,single,i);
    FOR j:=1 TO 9 DO IF GetAnswer THEN Exit;
    CD_Action(CD_FADE,0,150,NIL,1);
    FOR j:=1 TO 3 DO IF GetAnswer THEN Exit;
    StopPlayer(play);
  END;
END;

PROCEDURE DisplayInfo(Win: p_Window);

VAR Con2 : PTR;
    BDatA: Bord_Type;
    BA   : Border;

BEGIN
  Con2:=OpenConsole(Win);
  WriteCon(Con2,""\n\n\n\n\e"0 p"\e"9C"\e"32mCDTV-Player 1.4"\e"31m"\n"  Written by Danny Amor in 1992"\n"    This program is "\e"32mFREEWARE"\e"31m!"\n"   Written in KICK-PASCAL v2.1");
  BDatA:=Bord_Type(1,54,266,54,266,2,267,1,267,54);
  BA:=Border(0,0,2,0,0,5,^BDatA,NIL);
  DrawBorder(Win^.RPort,^BA,3,41);
  AddGadget(Win,^GadgetA[13],NIL);
  RefreshGadgets(^GadgetA[13],Win,NIL);
  CloseConsole(Con2);
END;

PROCEDURE LoadFast(VAR Dat: Load_Type);

VAR J     : BYTE;
    Num2,B: INTEGER;
    AHA   : STRING[5];

BEGIN
  READLN(Dat,AHA);
  IF AHA[2]="#" THEN
  BEGIN
    DELETE(AHA,1,2);
    VAL(AHA,Num2,B);
    J:=1;
    WHILE J<=Num2 DO
    BEGIN
      READLN(Dat,AHA);
      INC(J);
    END;
  END;
END;

PROCEDURE LoadKaraoke(VAR bandnumber,songcount,Singer: INTEGER; CD: BOOLEAN);

VAR Dat: Load_Type;
    AHA: STRING[30];
    I,J: BYTE;
    B  : INTEGER;

BEGIN
  RESET(Dat,"CDTV-Player:CDTV-Player/Lyrics/A-ZMusix");
  IF ioResult=0 THEN
  BEGIN
    BUFFER(Dat,10000);
    READLN(Dat,AHA);
    IF AHA="#MUSIX" THEN
    BEGIN
      READLN(Dat,AHA);
      IF AHA[1]="#" THEN
      BEGIN
        DELETE(AHA,1,1);
        VAL(AHA,Singer,B);
        I:=1;
        WHILE I<=Singer DO
        BEGIN
          READLN(Dat,AHA);
          IF CD THEN
          BEGIN
            IF AHA=BaTiSo^[bandnumber] THEN
            BEGIN
              READLN(Dat,AHA);
              IF AHA[2]="#" THEN
              BEGIN
                DELETE(AHA,1,2);
                VAL(AHA,SongCount,B);
                J:=1;
                WHILE J<=SongCount DO
                BEGIN
                  READLN(Dat,AHA);
                  CD_Titles^[J]:=AHA;
                  INC(J);
                END;
              END;
              I:=Singer;
            END
            ELSE LoadFast(Dat);
          END
          ELSE
          BEGIN
            BaTiSo^[I]:=AHA;
            LoadFast(Dat);
          END;
          INC(I);
        END;
      END;
      CLOSE(Dat);
    END;
  END;
END;

PROCEDURE LoadSongLyrics(Number: BYTE);

VAR Dat        : Load_Type;
    Num1,Num2,Num3,B: INTEGER;
    AHA        : STRING[30];
    I,J,K      : BYTE;
    Fname      : STRING[90];

BEGIN
  Fname:="CDTV-Player:CDTV-Player/Lyrics/"+GroCD^.Group+".mx";
  RESET(Dat,Fname);
  IF ioResult=0 THEN
  BEGIN
    FOR I:=0 TO 25 DO GroCD^.Song[I]:="";
    BUFFER(Dat,10000);
    READLN(Dat,AHA);
    IF AHA[1]="#" THEN
    DELETE(AHA,1,1);
    VAL(AHA,Num3,B);
    BEGIN
      K:=1;
      WHILE K<=Number DO
      BEGIN
        READLN(Dat,AHA);
        READLN(Dat,AHA);
        WHILE AHA[1]<>"#" DO READLN(Dat,AHA);
        BEGIN
          DELETE(AHA,1,1);
          VAL(AHA,Num1,B);
          FOR I:=1 TO Num1 DO
          BEGIN
            REPEAT
              READLN(Dat,AHA);
            UNTIL AHA[2]="#";
            IF k=Number THEN
            BEGIN
              DELETE(AHA,1,2);
              GroCD^.Song[I]:=AHA;
            END;
          END;
        END
        INC(K);
      END;
      CLOSE(Dat);
    END;
  END;
END;

PROCEDURE Karaoke(VAR Singer: INTEGER);

VAR OLDOFFSET,OFFSET,SongCount,PropInt,Number  : INTEGER;
    Win2       : ^Window;
    Itx        : ARRAY [1..6] OF IntuiText;
    GA         : ARRAY [1..7] OF Gadget;
    TAtt       : TextAttr;
    PropInfo2  : PropInfo;
    MDat       : ^Scro_Type;
    MImage2    : Image;
    BDatA      : ARRAY [1..2] OF Bord_Type;
    BA         : ARRAY [1..2] OF Border;
    Ende2      : BOOLEAN;
    Msg2       : ^IntuiMessage;
    AktGad2    : ^Gadget;
    I          : BYTE;

  PROCEDURE PutOnGadgets(second: BOOLEAN; max: INTEGER);

  VAR I,K: BYTE;

  BEGIN
    IF max<6 THEN K:=max
             ELSE K:=6;
    FOR I:=1 TO K DO
    BEGIN
      IF second THEN ITx[I]:=IntuiText(1,0,0,0,0,^TAtt,CD_Titles^[I+OFFSET],NIL)
                ELSE ITx[I]:=IntuiText(1,0,0,0,0,^TAtt,BaTiSo^[I+OFFSET],NIL);
      GA[I]:=Gadget(NIL,4,(I SHL 3)-5,238,8,0,RELVERIFY+GADGIMMEDIATE,BOOLGADGET,NIL,NIL,^ITx[I],0,NIL,I,0);
      AddGadget(Win2,^GA[I],NIL);
    END;
  END;

  PROCEDURE MoveGadgets(second: BOOLEAN; max: INTEGER);

  VAR I,K      : BYTE;
      J,DIREC,L: INTEGER;
      UPDOWN   : SHORT;
      outerr   : BOOLEAN;
      outtex   : Grup_Type;

  BEGIN
    OLDOFFSET:=OFFSET;
    WITH PropInfo2 DO OFFSET:=VertPot DIV (SUCC(VertBody) SHL 1);
    IF OFFSET<>OLDOFFSET THEN
    BEGIN
      DIREC:=OFFSET-OLDOFFSET;
      L:=ABS(DIREC);
      UPDOWN:=DIREC DIV L;
      IF L<10 THEN
      FOR J:=0 TO PRED(L) DO
      BEGIN
        FOR I:=1 TO 8 DO
          ScrollRaster(Win2^.RPort,0,UPDOWN,4,3,238,50);
        IF UPDOWN>0 THEN
        BEGIN
          Move(Win2^.RPort,4,49);
          IF second THEN outtex:=CD_Titles^[OLDOFFSET+7+J]
                    ELSE outtex:=BaTiSo^[OLDOFFSET+7+J];
        END
        ELSE
        BEGIN
          Move(Win2^.RPort,4,9);
          IF second THEN outtex:=CD_Titles^[OLDOFFSET-J]
                    ELSE outtex:=BaTiSo^[OLDOFFSET-J];
        END;
        outerr:=GfxText(Win2^.RPort,outtex,LENGTH(outtex));
      END
      ELSE
      BEGIN
        FOR I:=1 TO 6 DO
          ScrollRaster(Win2^.RPort,0,UPDOWN SHL 3,4,3,238,50);
      END;
      IF max<6 THEN K:=max
               ELSE K:=6;
      FOR I:=1 TO K DO RemoveGadgets(Win2,^GA[I]);
      PutOnGadgets(second,max);
      RefreshGadgets(Win2^.FirstGadget,Win2,NIL);
    END;
  END;

BEGIN
  Win2:=Open_Window(Win^.LeftEdge+4,Win^.TopEdge+41,268,55,1,GADGETUP
                    OR GADGETDOWN OR MOUSEMOVE,ACTIVATE,NIL,NIL,0,0,0,0);
  SetAPen(Win2^.RPort,1);
  OFFSET:=0;  OLDOFFSET:=0;
  Ende2:=FALSE;
  TAtt:=TextAttr("topaz.font",8,0,99);
  IF Singer<7 THEN PropInt:=0
              ELSE PropInt:=$7FFF DIV (Singer-5);
  PropInfo2:=PropInfo(PROPBORDERLESS OR FREEVERT,0,0,0,PropInt,0,0,0,0,0,0);
  MDat:=PTR(Alloc_Mem(SIZEOF(Scro_Type),2));
  MDat^:=Scro_Type(8,24,24,3864,3096,3096,2072,24,24,32760,-16,-16384,
                   -16384,-16256,-16000,-16000,-14464,-16384,-16384,-32768);
  MImage2:=Image(0,0,13,10,2,MDat,3,0,NIL);
  PutOnGadgets(FALSE,Singer);
  GA[7]:=Gadget(NIL,246,4,13,47,GADGHNONE OR GADGIMAGE,GADGIMMEDIATE
                OR RELVERIFY OR FOLLOWMOUSE,PROPGADGET,^MImage2,NIL,
                NIL,0,^PropInfo2,7,0);
  AddGadget(Win2,^GA[7],NIL);
  BDatA[1]:=Bord_Type(262,2,244,2,244,51,243,52,243,2);
  BDatA[2]:=Bord_Type(244,52,262,52,262,3,263,2,263,52);
  BA[1]:=Border(0,0,2,0,0,5,^BDatA[1],^BA[2]);
  BA[2]:=Border(0,0,1,0,0,5,^BDatA[2],NIL);
  RefreshGadgets(Win2^.FirstGadget,Win2,NIL);
  DrawBorder(Win2^.RPort,^BA,-1,0);
  REPEAT
    Msg2:=Wait_Port(Win2^.UserPort);
    Msg2:=Get_Msg(Win2^.UserPort);
    CASE Msg2^.Class OF
    GADGETUP:
        BEGIN
          AktGad2:=Msg2^.IAddress;
          CASE AktGad2^.GadgetID OF
            1..6: BEGIN
                    number:=AktGad2^.GadgetID+OFFSET;
                    Ende2:=TRUE;
                  END;
               7: IF SINGER>6 THEN MoveGadgets(FALSE,Singer);
            OTHERWISE;
          END;
        END;
      MOUSEMOVE: IF (AktGad2^.GadgetID=7) AND (Singer>6) THEN MoveGadgets(FALSE,Singer);
      GADGETDOWN: AktGad2:=Msg2^.IAddress;
      OTHERWISE;
    END;
    Reply_Msg(Msg2);
  UNTIL Ende2;
  GroCD^.Group:=BaTiSo^[number];
  OFFSET:=0;  OLDOFFSET:=0;
  Ende2:=FALSE;
  FOR I:=1 TO 6 DO RemoveGadgets(Win2,^GA[I]);
  SetAPen(Win2^.RPort,0);
  RectFill(Win2^.RPort,4,3,238,50);
  SetAPen(Win2^.RPort,1);
  NEW(CD_Titles);
  LoadKaraoke(number,songcount,singer,TRUE);
  PutOnGadgets(TRUE,songcount);
  IF SongCount<7 THEN PropInt:=0
                 ELSE PropInt:=$7FFF DIV (SongCount-5);
  ModifyProp(^GA[7],Win2,NIL,PROPBORDERLESS OR FREEVERT,0,0,0,PropInt);
  RefreshGadgets(Win2^.FirstGadget,Win2,NIL);
  REPEAT
    Msg2:=Wait_Port(Win2^.UserPort);
    Msg2:=Get_Msg(Win2^.UserPort);
    CASE Msg2^.Class OF
    GADGETUP:
      BEGIN
        AktGad2:=Msg2^.IAddress;
        CASE AktGad2^.GadgetID OF
          1..6: BEGIN
                  number:=AktGad2^.GadgetID+OFFSET;
                  Ende2:=TRUE;
                END;
             7: IF SongCount>6 THEN MoveGadgets(TRUE,songcount);
          OTHERWISE;
        END;
      END;
    MOUSEMOVE: IF (AktGad2^.GadgetID=7) AND (SongCount>6) THEN MoveGadgets(TRUE,songcount);
    GADGETDOWN: AktGad2:=Msg2^.IAddress;
    OTHERWISE;
    END;
    Reply_Msg(Msg2);
  UNTIL Ende2;
  GroCD^.CD:=CD_Titles^[number];
  DISPOSE(CD_Titles);
  LoadSongLyrics(Number);
  Clear(68,94);
  ShowBottom;
  Close_Window(Win2);
END;

PROCEDURE DeviceCloser;

BEGIN
  IF play THEN StopPlayer(play);
  CloseDevice(ioReq[1]);
  CloseDevice(ioReq[0]);
  DeleteExtIO(ioReq[1]);
  DeleteExtIO(ioReq[0]);
  DeletePort(ReplyPort[1]);
  DeletePort(ReplyPort[0]);
END;

BEGIN
  Win:=Open_Window(50,0,300,128,1,_CLOSEWINDOW OR GADGETUP OR GADGETDOWN OR
                   MOUSEMOVE OR DISKREMOVED OR DISKINSERTED,WINDOWDRAG OR
                   WINDOWDEPTH OR WINDOWCLOSE OR ACTIVATE,
                   "CDTV-Player by D. Amor '92 ",NIL,0,0,0,0);
  ReplyPort[0]:=CreatePort("CD-Port0",0);
  ReplyPort[1]:=CreatePort("CD-Port1",0);
  ioReq[0]:=CreateExtIO(ReplyPort[0],64);
  ioReq[1]:=CreateExtIO(ReplyPort[1],64);
  Fehler1:=OpenDevice("cdtv.device",0,ioReq[0],0);
  Fehler2:=OpenDevice("cdtv.device",0,ioReq[1],0);
  IF (Fehler1=0) AND (Fehler2=0) THEN
  BEGIN
    AddExitServer(DeviceCloser);
    TAttr0:=TextAttr("topaz.font",8,0,99);
    ITxt:=InSh_Type(IntuiText(1,0,0,32,3,^TAttr0,"REW",NIL),
                    IntuiText(1,0,0,28,3,^TAttr0,"PLAY",NIL),
                    IntuiText(1,0,0,36,3,^TAttr0,"FF",NIL),
                    IntuiText(1,0,0,24,3,^TAttr0,"PAUSE",NIL),
                    IntuiText(1,0,0,28,3,^TAttr0,"STOP",NIL),
                    IntuiText(1,0,0,28,3,^TAttr0,"FADE",NIL),
                    IntuiText(1,0,0, 0,0,NIL,NIL,NIL),
                    IntuiText(1,0,0,16,3,^TAttr0,"DISPLAY",NIL),
                    IntuiText(1,0,0,20,3,^TAttr0,"SINGLE",NIL),
                    IntuiText(1,0,0,20,3,^TAttr0,"REPEAT",NIL),
                    IntuiText(1,0,0,28,3,^TAttr0,"SCAN",NIL),
                    IntuiText(1,0,0,28,3,^TAttr0,"INFO",NIL),
                    IntuiText(1,0,0,16,3,^TAttr0,"KARAOKE",NIL);
                    IntuiText(1,0,0,36,3,^TAttr0,"OK",NIL));
    MDat:=PTR(Alloc_Mem(SIZEOF(Scro_Type),2));
    MDat^:=Scro_Type(8,24,24,3864,3096,3096,2072,24,24,32760,-16,-16384,
                     -16384,-16256,-16000,-16000,-14464,-16384,-16384,-32768);
    MImage1:=Image(0,0,13,10,2,MDat,3,0,NIL);
    BorderDatA:=BoSh_Type(Bord_Type(1,1,1,12,0,13,0,0,86,0),
                          Bord_Type(86,13,86,1,87,0,87,13,1,13),
                          Bord_Type(2,41,2,95,3,94,3,41,268,41),
                          Bord_Type(269,95,269,41,268,42,268,95,3,95),
                          Bord_Type(272,11,272,125,273,124,273,11,290,11));
    BorderA[0]:=Border(0,0,2,0,0,5,^BorderDatA[0],^BorderA[1]);
    BorderA[1]:=Border(0,0,1,0,0,5,^BorderDatA[1],NIL);
    BorderA[2]:=Border(0,0,2,0,0,5,^BorderDatA[1],^BorderA[3]);
    BorderA[3]:=Border(0,0,1,0,0,5,^BorderDatA[0],NIL);
    BorderA[4]:=Border(0,0,2,0,0,5,^BorderDatA[2],^BorderA[5]);
    BorderA[5]:=Border(0,0,1,0,0,5,^BorderDatA[3],^BorderA[6]);
    BorderA[6]:=Border(0,0,2,0,0,5,^BorderDatA[4],NIL);
    PropInfo1:=PropInfo(FREEVERT,0,0,32767,0,0,0,0,0,0,0);
    FOR watch:=0 TO 2 DO
      GadgetA[watch]:=Gadget(^GadgetA[SUCC(watch)],4+watch*90,11,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[watch],0,NIL,SUCC(watch),0);
    GadgetA[3]:=Gadget(^GadgetA[4],4,26,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[3],0,NIL,4,0);
    GadgetA[4]:=Gadget(^GadgetA[5],94,26,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[4],0,NIL,5,0);
    GadgetA[5]:=Gadget(^GadgetA[6],184,26,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[5],0,NIL,6,0);
    GadgetA[6]:=Gadget(^GadgetA[7],274,11,21,115,GADGHBOX OR GADGIMAGE,GADGIMMEDIATE
                       OR RELVERIFY OR FOLLOWMOUSE,PROPGADGET,^MImage1,NIL,
                       NIL,0,^PropInfo1,7,0);
    GadgetA[7]:=Gadget(^GadgetA[8],4,97,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[7],0,NIL,8,0);
    GadgetA[8]:=Gadget(^GadgetA[9],94,97,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[8],0,NIL,9,0);
    GadgetA[9]:=Gadget(^GadgetA[10],184,97,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[9],0,NIL,10,0);
    GadgetA[10]:=Gadget(^GadgetA[11],94,112,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[10],0,NIL,11,0);
    GadgetA[11]:=Gadget(^GadgetA[12],184,112,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[11],0,NIL,12,0);
    GadgetA[12]:=Gadget(NIL,4,112,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[12],0,NIL,13,0);
    GadgetA[13]:=Gadget(NIL,90,37,88,14,GADGHIMAGE,RELVERIFY+GADGIMMEDIATE,BOOLGADGET,^BorderA[0],^BorderA[2],^ITxt[13],0,NIL,-1,0);
    watch:=AddGList(Win,^GadgetA[0],1,13,NIL);
    RefreshGList(^GadgetA[0],Win,NIL,13);
    DrawBorder(Win^.RPort,^BorderA[4],2,0);
    ende:=FALSE;    pause:=TRUE;
    fade:=TRUE;     repeet:=FALSE;
    play:=FALSE;    single:=FALSE;
    NEW(BaTiSo);
    NEW(TOCArray);
    NEW(CDStatus);
    NEW(GroCD);
    LoadKaraoke(d1,d2,singer,FALSE);
    Song:=1;        Display:=0;
    InitText;
    CD_Action(CD_CSTATE,0,0,NIL,0);
    CD_Action(CD_FADE,32767,0,NIL,1);
    IF ioReq[0]^.io_Actual=255 THEN WaitStartUp
                               ELSE StartUp;
    REPEAT
      REPEAT
        IF (NOT play) OR (display=4) OR Info THEN Msg:=Wait_Port(Win^.UserPort);
        Msg:=Get_Msg(Win^.UserPort);
        IF (watch=255) AND play AND pause THEN ShowTime(song,play,single,repeet,FALSE);
        INC(watch);
      UNTIL Msg<>NIL;
      CASE Msg^.Class OF
        _CLOSEWINDOW: Ende:=TRUE;
        DISKREMOVED: BEGIN
                       CD_Action(CD_CSTATE,0,0,NIL,0);
                       IF ioReq[0]^.io_Actual=255 THEN
                       BEGIN
                         WaitStartUp;
                         play:=FALSE;
                       END;
                     END;
        DISKINSERTED: BEGIN
                        CD_Action(CD_CSTATE,0,0,NIL,0);
                        IF (ioReq[0]^.io_Actual=0) AND removed THEN Startup;
                      END;
        GADGETUP: BEGIN
                    AktGad:=Msg^.IAddress;
                    CASE AktGad^.GadgetID OF
                      1: IF song>1 THEN
                         BEGIN
                           DEC(song);
                           CheckPlayer;
                         END;
                      2: IF NOT (play OR removed) THEN StartPlayer(play,single,song);
                      3: IF song<max THEN
                         BEGIN
                           INC(song);
                           CheckPlayer;
                         END;
                      4: PausePlayer(pause);
                      5: IF play THEN
                         BEGIN
                           StopPlayer(play);
                           StopText(max,TOCArray^[5],TOCArray^[6]);
                         END;
                      6: IF NOT removed THEN DimOffPlayer(fade);
                      7: IF NOT Fade THEN Scroll_Fade(PropInfo1,oldzahl,zahl)
                      8: IF NOT removed THEN
                         BEGIN
                           INC(Display);
                           CASE Display OF
                             4: ShowNothing;
                             5: BEGIN
                                  Clear(50,58);
                                  display:=0;
                                END;
                             OTHERWISE;
                           END;
                         END;
                      9: single:=NOT single;
                      10: repeet:=NOT repeet;
                      11: IF NOT (play OR Removed) THEN ScanIntoCD;
                      12: IF NOT info THEN
                          BEGIN
                            info:=TRUE;
                            DisplayInfo;
                          END;
                      13: Karaoke(singer);
                      14: IF info THEN
                          BEGIN
                            info:=FALSE;
                            RemoveGadgets(Win,^GadgetA[13]);
                            InitText;
                          END;
                      OTHERWISE
                    END;
                  END;
        MOUSEMOVE: IF AktGad^.GadgetID=7 THEN Scroll_Fade(PropInfo1,oldzahl,zahl);
        GADGETDOWN: AktGad:=Msg^.IAddress;
        OTHERWISE
      END;
      Reply_Msg(Msg);
    UNTIL Ende;
    DISPOSE(GroCD);
    DISPOSE(CDStatus);
    DISPOSE(TOCArray);
    DISPOSE(BaTiSo);
  END
  ELSE
  BEGIN
    con:=OpenConsole(win);
    NEW(ErrorMessage);
    ErrorMessage^:="I'm sorry! Can't find "\e"33m'cdtv.device'!"\e"31m"\n"This machine doesn't look like a"\n\e"33mCDTV"\e"31m or an "\e"33mA570/A670"\e"31m! In case I'm"\n"wrong please write to me."\n"See Doc.File!"\n;
    WriteCon(con,ErrorMessage^);
    CloseConsole(con);
    DISPOSE(ErrorMessage);
    play:=FALSE;
    Msg:=Wait_Port(Win^.UserPort);
    Msg:=Get_Msg(Win^.UserPort);
  END;
END.

