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 >
Wrap
C/C++ Source or Header
|
1994-01-30
|
34KB
|
1,672 lines
;/*
SC PARAMS=REGISTER NMINC MCCONS STREQ NOWVRET STRMERGE NOSTKCHK UTILLIB OPTIMIZE OPTTIME OPTINLINE MODIFIED IGNORE=73 CDDA.c
SLINK CDDA.o TO CDDA LIB LIB:sc.lib LIB:amiga.lib SC SD ND NOICONS
Quit
*/
/*
** CDDA - A program to replay digital audio data read from a
** Sony CD-ROM drive.
**
** Copyright © 1993-1994 by Olaf `Olsen' Barthel
** This is a freeware release.
*/
/* Avoid a nasty type conflict in older include files. */
#define CheckIO foo
/* System includes */
#include <devices/scsidisk.h>
#include <devices/trackdisk.h>
#include <devices/audio.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <dos/rdargs.h>
#include <dos/dosasl.h>
#include <hardware/cia.h>
#include <clib/utility_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
#include <clib/macros.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <string.h>
/* Get the CheckIO prototype right. */
#undef CheckIO
struct IORequest *CheckIO(struct IORequest *);
/* The CIA A base address. */
#ifndef ciaa
extern struct CIA __far ciaa;
#endif /* ciaa */
/* Command line template. */
#define TEMPLATE "DEVICE/K,UNIT/K/N,TRACK/N,FROM/K/N,TO/K/N,NUM/K/N,MAX/K/N,VERBOSE/S"
/* The argument vector offsets. */
enum { ARG_DEVICE,ARG_UNIT,ARG_TRACK,ARG_FROM,ARG_TO,ARG_NUM,ARG_MAX,ARG_VERBOSE,
ARGCOUNT
};
/* Player task priority and stack size. */
#define CHILD_PRI 5
#define CHILD_STACK 8192
/* Default SCSI device name and unit number. */
#define SCSI_DEVICE "scsi.device"
#define SCSI_UNIT 2
/* The signal mask associated with a MsgPort. */
#define PORTMASK(p) (1L << ((struct MsgPort *)(p)) -> mp_SigBit)
/* Some signal masks. */
#define SIG_HANDSHAKE SIGF_SINGLE
#define SIG_KILL SIGBREAKF_CTRL_C
#define SIG_SYNC SIGBREAKF_CTRL_F
#define SIG_CHILD PORTMASK(ChildPort)
/* The size of an audio data buffer and the
* number of blocks per packet (= 1 second of data).
*/
#define BUFFER_SIZE 22050
#define BLOCKS_PER_PKT 75
/* Amiga audio channel allocation bits. */
#define LEFT0F 1
#define RIGHT0F 2
#define RIGHT1F 4
#define LEFT1F 8
/* SCSI command `test unit ready'. */
struct TestUnitReady
{
UBYTE Command,
Pad,
Reserved[3],
Control;
};
/* SCSI command `inquiry'. */
struct Inquiry
{
UBYTE Command,
Pad,
PageCode,
Reserved,
AllocationLength,
Control;
};
/* The data structure to be filled by the inquiry command. */
struct InquiryData
{
UBYTE PeripheralType,
DeviceTypeModifier,
Version,
Reserved[5],
Vendor[8],
Product[16],
Revision[4];
};
/* SCSI command `read table of contents'. */
struct ReadTOC
{
UBYTE Command,
Pad,
Reserved[4],
StartingTrack;
UBYTE Alloc1,Alloc2;
UBYTE Control;
};
/* The data structure to be filled in by the
* readtoc command.
*/
struct FullTOC
{
UWORD DataLength;
UBYTE FirstTrack,
LastTrack;
struct
{
UBYTE Reserved1,
Control,
TrackNumber,
Reserved2;
ULONG Address;
} TOC[100];
};
/* Sony vendor unique command to read digital
* audio data.
*/
struct ReadCDDA
{
UBYTE Command,
Pad;
ULONG Address,
Count;
UBYTE SubCode,
Control;
};
/* Digital audio data, as returned by the corresponding command. */
struct CDDASector
{
struct CDDASample
{
UBYTE LeftLSB,
LeftMSB,
RightLSB,
RightMSB;
} Sample[588];
};
/* Handler->player task communications structure. */
struct AudioMessage
{
struct Message Message;
LONG NumBlocks;
struct CDDASector *Data;
};
/* Global library bases. */
struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct Library *UtilityBase;
/* Command line arguments. */
struct RDArgs *ArgsPtr;
STRPTR *Arg;
/* Audio data. */
struct IOAudio *AudioControl,
*AudioLeft,
*AudioRight;
struct MsgPort *AudioPort;
BYTE *ThisLeft,
*NextLeft,
*ThisRight,
*NextRight,
*AudioData;
ULONG Rate;
LONG FillCounter = 0,
TotalPending = 0;
BOOL AudioUsed = FALSE,
AudioActive = FALSE,
Verbose,
LED;
/* Current sector and total number of sectors to read. */
LONG Index,Total;
/* SCSI device control data. */
struct MsgPort *SCSIPort;
struct IOExtTD *SCSIRequest;
struct SCSICmd SCSICmd;
UBYTE SenseBuffer[256];
/* Data to be read from the device. */
struct FullTOC FullTOC;
struct InquiryData InquiryData;
/* Block queue access semaphore and number of
* packets in the queue.
*/
struct SignalSemaphore QueueSemaphore;
LONG QueueCount;
/* Handler and player task data. */
struct Task *Child;
struct MsgPort *ChildPort;
struct Process *Father;
BOOL FatherWaiting;
/* Program version ID. */
STRPTR VersionTag = "\0$VER: CDDA 1.3 (14.1.94)";
/* Prototypes for this module. */
LONG __saveds Main(VOID);
VOID SCSIExit(VOID);
BOOL SCSIInit(STRPTR Device,LONG Unit);
VOID AudioExit(VOID);
BOOL AudioInit(VOID);
VOID DeleteAudioMessage(struct AudioMessage *Message);
struct AudioMessage * CreateAudioMessage(LONG NumBlocks);
VOID StartAudio(VOID);
VOID ProcessAudio(VOID);
VOID __saveds ChildTask(VOID);
VOID CloseAll(VOID);
BOOL OpenAll(VOID);
BYTE ReadCDDASectors(APTR Buffer,LONG From,LONG Count);
BYTE TestUnitReady(VOID);
BYTE ReadTOC(VOID);
BYTE Inquire(VOID);
/* Main():
*
* The program entry point. No compiler startup code.
*/
LONG __saveds
Main()
{
LONG Result = RETURN_FAIL;
/* Open the resources. */
if(OpenAll())
{
LONG Blocks,MaxQueueSize;
struct AudioMessage *Message;
BOOL Stop = FALSE,
FirstMessage = TRUE;
/* Everything went fine so far. */
Result = RETURN_OK;
/* Get the maximum block queue size. */
if(Arg[ARG_MAX])
MaxQueueSize = *(LONG *)Arg[ARG_MAX];
else
MaxQueueSize = 3;
/* Safety check. */
if(MaxQueueSize < 1)
MaxQueueSize = 1;
/* Print the banner message. */
FPrintf(Output(),"\33[1mCDDA\33[0m © Copyright 1993-1994 by Olaf `Olsen' Barthel, \33[4mAll rights reserved\33[0m\n");
/* Play the tracks. */
while(Total > 0)
{
/* Stop playing? */
if(CheckSignal(SIG_KILL))
{
Stop = TRUE;
break;
}
/* Gain access to the block queue... */
ObtainSemaphore(&QueueSemaphore);
/* More blocks in the queue than there
* should be?
*/
if(QueueCount > MaxQueueSize)
{
/* Wait for the player task
* to make room.
*/
Forbid();
ReleaseSemaphore(&QueueSemaphore);
SetSignal(0,SIG_HANDSHAKE);
FatherWaiting = TRUE;
Wait(SIG_HANDSHAKE);
FatherWaiting = FALSE;
Permit();
}
else
ReleaseSemaphore(&QueueSemaphore);
/* Allocate another packet. */
if(Message = CreateAudioMessage(Blocks = MIN(BLOCKS_PER_PKT,Total)))
{
/* Read the data, we may need more than one
* attempt if the drive feels unable to supply
* the requested data immediately.
*/
while(ReadCDDASectors(Message -> Data,Index,Blocks))
{
/* Stop here? */
if(CheckSignal(SIG_KILL))
{
Stop = TRUE;
break;
}
/* If in verbose mode, tell the user that
* we are retrying to read the data.
*/
if(Verbose)
{
if(FirstMessage)
{
Printf("CDDA: Rereading sector #%ld\n",Index);
FirstMessage = FALSE;
}
else
Printf("\033[ACDDA: Rereading sector #%ld\033[K\n",Index);
}
}
/* Read request aborted? */
if(Stop)
{
/* Clean up and exit. */
DeleteAudioMessage(Message);
break;
}
else
{
/* Add the data to the queue. */
PutMsg(ChildPort,&Message -> Message);
Total -= Blocks;
Index += Blocks;
}
}
else
{
/* Stop here? */
if(CheckSignal(SIG_KILL))
{
Stop = TRUE;
break;
}
/* If in verbose mode tell the user that
* we will need to retry the memory
* allocation.
*/
if(Verbose)
{
if(FirstMessage)
{
Printf("CDDA: Retrying memory allocation for sector #%ld\n",Index);
FirstMessage = FALSE;
}
else
Pri