home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / mar94 / disk / cdrom / cdda.lha / CDDA / CDDA.c < prev    next >
C/C++ Source or Header  |  1994-01-30  |  34KB  |  1,672 lines

  1. ;/*
  2. SC PARAMS=REGISTER NMINC MCCONS STREQ NOWVRET STRMERGE NOSTKCHK UTILLIB OPTIMIZE OPTTIME OPTINLINE MODIFIED IGNORE=73 CDDA.c
  3. SLINK CDDA.o TO CDDA LIB LIB:sc.lib LIB:amiga.lib SC SD ND NOICONS
  4. Quit
  5. */
  6.  
  7. /*
  8. **    CDDA - A program to replay digital audio data read from a
  9. **           Sony CD-ROM drive.
  10. **
  11. **    Copyright © 1993-1994 by Olaf `Olsen' Barthel
  12. **        This is a freeware release.
  13. */
  14.  
  15.     /* Avoid a nasty type conflict in older include files. */
  16.  
  17. #define CheckIO foo
  18.  
  19.     /* System includes */
  20.  
  21. #include <devices/scsidisk.h>
  22. #include <devices/trackdisk.h>
  23. #include <devices/audio.h>
  24.  
  25. #include <exec/execbase.h>
  26. #include <exec/memory.h>
  27.  
  28. #include <dos/dosextens.h>
  29. #include <dos/dostags.h>
  30. #include <dos/rdargs.h>
  31. #include <dos/dosasl.h>
  32.  
  33. #include <hardware/cia.h>
  34.  
  35. #include <clib/utility_protos.h>
  36. #include <clib/exec_protos.h>
  37. #include <clib/dos_protos.h>
  38. #include <clib/alib_protos.h>
  39. #include <clib/macros.h>
  40.  
  41. #include <pragmas/utility_pragmas.h>
  42. #include <pragmas/exec_pragmas.h>
  43. #include <pragmas/dos_pragmas.h>
  44.  
  45. #include <string.h>
  46.  
  47.     /* Get the CheckIO prototype right. */
  48.  
  49. #undef CheckIO
  50.  
  51. struct IORequest *CheckIO(struct IORequest *);
  52.  
  53.     /* The CIA A base address. */
  54.  
  55. #ifndef ciaa
  56. extern struct CIA __far ciaa;
  57. #endif    /* ciaa */
  58.  
  59.     /* Command line template. */
  60.  
  61. #define TEMPLATE    "DEVICE/K,UNIT/K/N,TRACK/N,FROM/K/N,TO/K/N,NUM/K/N,MAX/K/N,VERBOSE/S"
  62.  
  63.     /* The argument vector offsets. */
  64.  
  65. enum    {    ARG_DEVICE,ARG_UNIT,ARG_TRACK,ARG_FROM,ARG_TO,ARG_NUM,ARG_MAX,ARG_VERBOSE,
  66.  
  67.         ARGCOUNT
  68.     };
  69.  
  70.     /* Player task priority and stack size. */
  71.  
  72. #define CHILD_PRI    5
  73. #define CHILD_STACK    8192
  74.  
  75.     /* Default SCSI device name and unit number. */
  76.  
  77. #define SCSI_DEVICE    "scsi.device"
  78. #define SCSI_UNIT    2
  79.  
  80.     /* The signal mask associated with a MsgPort. */
  81.  
  82. #define PORTMASK(p)    (1L << ((struct MsgPort *)(p)) -> mp_SigBit)
  83.  
  84.     /* Some signal masks. */
  85.  
  86. #define SIG_HANDSHAKE    SIGF_SINGLE
  87. #define SIG_KILL    SIGBREAKF_CTRL_C
  88. #define SIG_SYNC    SIGBREAKF_CTRL_F
  89. #define SIG_CHILD    PORTMASK(ChildPort)
  90.  
  91.     /* The size of an audio data buffer and the
  92.      * number of blocks per packet (= 1 second of data).
  93.      */
  94.  
  95. #define BUFFER_SIZE    22050
  96. #define BLOCKS_PER_PKT    75
  97.  
  98.     /* Amiga audio channel allocation bits. */
  99.  
  100. #define LEFT0F        1
  101. #define RIGHT0F        2
  102. #define RIGHT1F        4
  103. #define LEFT1F        8
  104.  
  105.     /* SCSI command `test unit ready'. */
  106.  
  107. struct TestUnitReady
  108. {
  109.     UBYTE    Command,
  110.         Pad,
  111.         Reserved[3],
  112.         Control;
  113. };
  114.  
  115.     /* SCSI command `inquiry'. */
  116.  
  117. struct Inquiry
  118. {
  119.     UBYTE    Command,
  120.         Pad,
  121.         PageCode,
  122.         Reserved,
  123.         AllocationLength,
  124.         Control;
  125. };
  126.  
  127.     /* The data structure to be filled by the inquiry command. */
  128.  
  129. struct InquiryData
  130. {
  131.     UBYTE    PeripheralType,
  132.         DeviceTypeModifier,
  133.         Version,
  134.         Reserved[5],
  135.         Vendor[8],
  136.         Product[16],
  137.         Revision[4];
  138. };
  139.  
  140.     /* SCSI command `read table of contents'. */
  141.  
  142. struct ReadTOC
  143. {
  144.     UBYTE    Command,
  145.         Pad,
  146.         Reserved[4],
  147.         StartingTrack;
  148.     UBYTE    Alloc1,Alloc2;
  149.     UBYTE    Control;
  150. };
  151.  
  152.     /* The data structure to be filled in by the
  153.      * readtoc command.
  154.      */
  155.  
  156. struct FullTOC
  157. {
  158.     UWORD    DataLength;
  159.     UBYTE    FirstTrack,
  160.         LastTrack;
  161.  
  162.     struct
  163.     {
  164.         UBYTE    Reserved1,
  165.             Control,
  166.             TrackNumber,
  167.             Reserved2;
  168.         ULONG    Address;
  169.     } TOC[100];
  170. };
  171.  
  172.     /* Sony vendor unique command to read digital
  173.      * audio data.
  174.      */
  175.  
  176. struct ReadCDDA
  177. {
  178.     UBYTE        Command,
  179.             Pad;
  180.     ULONG        Address,
  181.             Count;
  182.     UBYTE        SubCode,
  183.             Control;
  184. };
  185.  
  186.     /* Digital audio data, as returned by the corresponding command. */
  187.  
  188. struct CDDASector
  189. {
  190.     struct CDDASample
  191.     {
  192.         UBYTE    LeftLSB,
  193.             LeftMSB,
  194.  
  195.             RightLSB,
  196.             RightMSB;
  197.     } Sample[588];
  198. };
  199.  
  200.     /* Handler->player task communications structure. */
  201.  
  202. struct AudioMessage
  203. {
  204.     struct Message         Message;
  205.     LONG             NumBlocks;
  206.     struct CDDASector    *Data;
  207. };
  208.  
  209.     /* Global library bases. */
  210.  
  211. struct ExecBase        *SysBase;
  212. struct DosLibrary    *DOSBase;
  213. struct Library        *UtilityBase;
  214.  
  215.     /* Command line arguments. */
  216.  
  217. struct RDArgs        *ArgsPtr;
  218. STRPTR            *Arg;
  219.  
  220.     /* Audio data. */
  221.  
  222. struct IOAudio        *AudioControl,
  223.             *AudioLeft,
  224.             *AudioRight;
  225. struct MsgPort        *AudioPort;
  226. BYTE            *ThisLeft,
  227.             *NextLeft,
  228.             *ThisRight,
  229.             *NextRight,
  230.             *AudioData;
  231. ULONG             Rate;
  232. LONG             FillCounter    = 0,
  233.              TotalPending    = 0;
  234. BOOL             AudioUsed    = FALSE,
  235.              AudioActive    = FALSE,
  236.              Verbose,
  237.              LED;
  238.  
  239.     /* Current sector and total number of sectors to read. */
  240.  
  241. LONG             Index,Total;
  242.  
  243.     /* SCSI device control data. */
  244.  
  245. struct MsgPort        *SCSIPort;
  246. struct IOExtTD        *SCSIRequest;
  247.  
  248. struct SCSICmd         SCSICmd;
  249. UBYTE             SenseBuffer[256];
  250.  
  251.     /* Data to be read from the device. */
  252.  
  253. struct FullTOC         FullTOC;
  254. struct InquiryData     InquiryData;
  255.  
  256.     /* Block queue access semaphore and number of
  257.      * packets in the queue.
  258.      */
  259.  
  260. struct SignalSemaphore     QueueSemaphore;
  261. LONG             QueueCount;
  262.  
  263.     /* Handler and player task data. */
  264.  
  265. struct Task        *Child;
  266. struct MsgPort        *ChildPort;
  267. struct Process        *Father;
  268. BOOL             FatherWaiting;
  269.  
  270.     /* Program version ID. */
  271.  
  272. STRPTR             VersionTag = "\0$VER: CDDA 1.3 (14.1.94)";
  273.  
  274.     /* Prototypes for this module. */
  275.  
  276. LONG __saveds        Main(VOID);
  277. VOID            SCSIExit(VOID);
  278. BOOL            SCSIInit(STRPTR Device,LONG Unit);
  279. VOID            AudioExit(VOID);
  280. BOOL            AudioInit(VOID);
  281. VOID            DeleteAudioMessage(struct AudioMessage *Message);
  282. struct AudioMessage *    CreateAudioMessage(LONG NumBlocks);
  283. VOID            StartAudio(VOID);
  284. VOID            ProcessAudio(VOID);
  285. VOID __saveds        ChildTask(VOID);
  286. VOID            CloseAll(VOID);
  287. BOOL            OpenAll(VOID);
  288. BYTE            ReadCDDASectors(APTR Buffer,LONG From,LONG Count);
  289. BYTE            TestUnitReady(VOID);
  290. BYTE            ReadTOC(VOID);
  291. BYTE            Inquire(VOID);
  292.  
  293.     /* Main():
  294.      *
  295.      *    The program entry point. No compiler startup code.
  296.      */
  297.  
  298. LONG __saveds
  299. Main()
  300. {
  301.     LONG Result = RETURN_FAIL;
  302.  
  303.         /* Open the resources. */
  304.  
  305.     if(OpenAll())
  306.     {
  307.         LONG             Blocks,MaxQueueSize;
  308.         struct AudioMessage    *Message;
  309.         BOOL             Stop        = FALSE,
  310.                      FirstMessage    = TRUE;
  311.  
  312.             /* Everything went fine so far. */
  313.  
  314.         Result = RETURN_OK;
  315.  
  316.             /* Get the maximum block queue size. */
  317.  
  318.         if(Arg[ARG_MAX])
  319.             MaxQueueSize = *(LONG *)Arg[ARG_MAX];
  320.         else
  321.             MaxQueueSize = 3;
  322.  
  323.             /* Safety check. */
  324.  
  325.         if(MaxQueueSize < 1)
  326.             MaxQueueSize = 1;
  327.  
  328.             /* Print the banner message. */
  329.  
  330.         FPrintf(Output(),"\33[1mCDDA\33[0m © Copyright 1993-1994 by Olaf `Olsen' Barthel, \33[4mAll rights reserved\33[0m\n");
  331.  
  332.             /* Play the tracks. */
  333.  
  334.         while(Total > 0)
  335.         {
  336.                 /* Stop playing? */
  337.  
  338.             if(CheckSignal(SIG_KILL))
  339.             {
  340.                 Stop = TRUE;
  341.  
  342.                 break;
  343.             }
  344.  
  345.                 /* Gain access to the block queue... */
  346.  
  347.             ObtainSemaphore(&QueueSemaphore);
  348.  
  349.                 /* More blocks in the queue than there
  350.                  * should be?
  351.                  */
  352.  
  353.             if(QueueCount > MaxQueueSize)
  354.             {
  355.                     /* Wait for the player task
  356.                      * to make room.
  357.                      */
  358.  
  359.                 Forbid();
  360.  
  361.                 ReleaseSemaphore(&QueueSemaphore);
  362.  
  363.                 SetSignal(0,SIG_HANDSHAKE);
  364.  
  365.                 FatherWaiting = TRUE;
  366.  
  367.                 Wait(SIG_HANDSHAKE);
  368.  
  369.                 FatherWaiting = FALSE;
  370.  
  371.                 Permit();
  372.             }
  373.             else
  374.                 ReleaseSemaphore(&QueueSemaphore);
  375.  
  376.                 /* Allocate another packet. */
  377.  
  378.             if(Message = CreateAudioMessage(Blocks = MIN(BLOCKS_PER_PKT,Total)))
  379.             {
  380.                     /* Read the data, we may need more than one
  381.                      * attempt if the drive feels unable to supply
  382.                      * the requested data immediately.
  383.                      */
  384.  
  385.                 while(ReadCDDASectors(Message -> Data,Index,Blocks))
  386.                 {
  387.                         /* Stop here? */
  388.  
  389.                     if(CheckSignal(SIG_KILL))
  390.                     {
  391.                         Stop = TRUE;
  392.  
  393.                         break;
  394.                     }
  395.  
  396.                         /* If in verbose mode, tell the user that
  397.                          * we are retrying to read the data.
  398.                          */
  399.  
  400.                     if(Verbose)
  401.                     {
  402.                         if(FirstMessage)
  403.                         {
  404.                             Printf("CDDA: Rereading sector #%ld\n",Index);
  405.  
  406.                             FirstMessage = FALSE;
  407.                         }
  408.                         else
  409.                             Printf("\033[ACDDA: Rereading sector #%ld\033[K\n",Index);
  410.                     }
  411.                 }
  412.  
  413.                     /* Read request aborted? */
  414.  
  415.                 if(Stop)
  416.                 {
  417.                         /* Clean up and exit. */
  418.  
  419.                     DeleteAudioMessage(Message);
  420.  
  421.                     break;
  422.                 }
  423.                 else
  424.                 {
  425.                         /* Add the data to the queue. */
  426.  
  427.                     PutMsg(ChildPort,&Message -> Message);
  428.  
  429.                     Total    -= Blocks;
  430.                     Index    += Blocks;
  431.                 }
  432.             }
  433.             else
  434.             {
  435.                     /* Stop here? */
  436.  
  437.                 if(CheckSignal(SIG_KILL))
  438.                 {
  439.                     Stop = TRUE;
  440.  
  441.                     break;
  442.                 }
  443.  
  444.                     /* If in verbose mode tell the user that
  445.                      * we will need to retry the memory
  446.                      * allocation.
  447.                      */
  448.  
  449.                 if(Verbose)
  450.                 {
  451.                     if(FirstMessage)
  452.                     {
  453.                         Printf("CDDA: Retrying memory allocation for sector #%ld\n",Index);
  454.  
  455.                         FirstMessage = FALSE;
  456.                     }
  457.                     else
  458.                         Pri