/* play.c: */ #include "includes.h" #define VERSION "1.1 (04.01.1994)" #define HRDBLBF #define CDDA_BUFSIZE 2368 #define SUBCHANNEL_SIZE 16 #define STD_BUFSIZE 2048 #define SENSE_LENGTH 32 #define AUDIO_BUFSIZE ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/g_compression_factor/4) #define TOTAL_CDDA_BUFSIZE (g_buffers*2*CDDA_BUFSIZE) #define TOTAL_AUDIO_BUFSIZE (g_buffers*2*AUDIO_BUFSIZE) #define CDDA_STD_BUFSIZE (STD_BUFSIZE+SENSE_LENGTH) typedef short t_bool; typedef struct toc { char reserved1; unsigned char flags; unsigned char track_number; char reserved2; long address; } t_toc; typedef enum dtype {UNKNOWNDRIVE = 0, TOSHIBA, APPLECD300} t_drivetype; static char *TheVersion = "$VER: PlayCDDA " VERSION; t_bool g_called_from_cli; char g_scsi_device[80]; t_drivetype g_whatdrive = UNKNOWNDRIVE; int g_scsi_id; LONG g_memory_type = MEMF_CHIP; UBYTE *g_cdda_base = NULL; UBYTE *g_audio_base = NULL; UBYTE *g_std_buf_base = NULL; UBYTE *g_cdda_buf[2]; UBYTE *g_cdda_std_buf; UBYTE *g_audio_buf[2]; struct MsgPort *g_cdda_port = NULL; struct MsgPort *g_audio_port[2] = { NULL, NULL }; ULONG g_cdda_sigmask; ULONG g_audio_sigmask[2]; #ifndef HRDBLBF struct IOStdReq *g_scsireq = NULL; t_bool g_outstanding_cdda_request = FALSE; struct SCSICmd *g_scsicmd = NULL; UBYTE *g_sense_data; #else struct IOStdReq *g_scsireq[2] = {NULL, NULL}; t_bool g_outstanding_cdda_request[2] = {FALSE, FALSE}; struct SCSICmd *g_scsicmd[2] = {NULL, NULL}; UBYTE *g_sense_data[2]; #endif struct IOAudio *g_audioreq[2] = { NULL, NULL }; t_bool g_audio_device_open = FALSE; long g_period; int g_toc_length; t_toc g_toc[100]; short g_volume = 1; /* possible values for g_compression_factor: 2, 3, 4, 6, 7, 12, 14, 28, 49 */ unsigned short g_compression_factor = 2; unsigned short g_buffers = 4; /* user interface variables: */ #ifdef __SASC extern struct Library *DOSBase; #endif struct Library *IconBase = NULL; struct Library *IntuitionBase = NULL; struct Library *GadToolsBase = NULL; struct GfxBase *GfxBase = NULL; struct Screen *g_screen = NULL; void *g_visual_info = NULL; struct Window *g_window = NULL; struct Gadget *g_glist = NULL; t_bool g_bye = FALSE; char g_track_str[3] = { 0, 0, 0 }; char g_index_str[3] = { 0, 0, 0 }; char g_time_str[6] = { 0, 0, ':', 0, 0, 0 }; unsigned char g_track, g_index; unsigned char g_minute, g_seconds; enum gadget_ids { GID_SAMPLING_RATE = 21, GID_BUFFERS, GID_VOLUME, GID_PREV, GID_NEXT, GID_START, GID_STOP, GID_TRACK, GID_INDEX, GID_TIME, /* always last: */ GID_MAX }; struct Gadget *g_gadgets[GID_MAX]; #ifdef __SASC void __regargs __chkabort(void) { } #endif void Cleanup_User_Interface (void) { if (g_window) CloseWindow (g_window); if (g_glist) FreeGadgets (g_glist); if (g_visual_info) FreeVisualInfo (g_visual_info); if (g_screen) UnlockPubScreen (NULL, g_screen); if (GfxBase) CloseLibrary ((struct Library *) GfxBase); if (GadToolsBase) CloseLibrary (GadToolsBase); if (IntuitionBase) CloseLibrary (IntuitionBase); } void Cleanup_Audio (void) { if (g_cdda_base) { FreeMem (g_cdda_base, TOTAL_CDDA_BUFSIZE + 15); g_cdda_base = NULL; } if (g_audio_base) { FreeMem (g_audio_base, TOTAL_AUDIO_BUFSIZE + 15); g_audio_base = NULL; } if (g_audio_device_open) { CloseDevice ((struct IORequest *) g_audioreq[0]); g_audio_device_open = FALSE; } if (g_audio_port[0]) { DeleteMsgPort (g_audio_port[0]); g_audio_port[0] = NULL; } if (g_audio_port[1]) { DeleteMsgPort (g_audio_port[1]); g_audio_port[1] = NULL; } if (g_audioreq[0]) { FreeMem (g_audioreq[0], sizeof (struct IOAudio)); g_audioreq[0] = NULL; } if (g_audioreq[1]) { FreeMem (g_audioreq[1], sizeof (struct IOAudio)); g_audioreq[1] = NULL; } } void Cleanup (void) { #ifdef HRDBLBF int i; #endif Cleanup_Audio (); if (g_std_buf_base) FreeMem (g_std_buf_base, CDDA_STD_BUFSIZE + 15); #ifndef HRDBLBF if (g_scsicmd) FreeMem (g_scsicmd, sizeof (struct SCSICmd)); if (g_scsireq) { if (g_scsireq->io_Device) { if (g_outstanding_cdda_request) { AbortIO ((struct IORequest *) g_scsireq); WaitIO ((struct IORequest *) g_scsireq); } CloseDevice ((struct IORequest *) g_scsireq); } DeleteIORequest ((struct IORequest *) g_scsireq); } #else for (i = 0; i < 2; i++) { if (g_scsicmd[i]) FreeMem (g_scsicmd[i], sizeof (struct SCSICmd)); if (g_scsireq[i]) { if (g_scsireq[i]->io_Device) { if (g_outstanding_cdda_request[i]) { AbortIO ((struct IORequest *) g_scsireq[i]); WaitIO ((struct IORequest *) g_scsireq[i]); } CloseDevice ((struct IORequest *) g_scsireq[i]); } DeleteIORequest ((struct IORequest *) g_scsireq[i]); } } #endif if (g_cdda_port) DeleteMsgPort (g_cdda_port); Cleanup_User_Interface (); if (IconBase) CloseLibrary (IconBase); } void Fatal_Error (char *p_message, ...) { va_list arg; static struct EasyStruct req = { sizeof (struct EasyStruct), 0, (UBYTE *) "PlayCDDA Error", NULL, (UBYTE *) "Abort" }; va_start (arg, p_message); if (IntuitionBase) { req.es_TextFormat = (UBYTE *) p_message; EasyRequestArgs (NULL, &req, NULL, arg); } else if (g_called_from_cli) { VPrintf ((UBYTE *) p_message, (LONG *) arg); WriteChars ((UBYTE *) "\n", 1); } else Alert (0x0000CDDA); va_end (p_message); exit (1); } char *Open_User_Interface (void) { static struct TextAttr Topaz8 = { (UBYTE *) "topaz.font", 8, 0, 0, }; struct TextFont *font; int i, j; static char *labels[20] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" }; static char *sampling_rate_labels[] = { "22050 bps", /* 2 */ "14700 bps", /* 3 */ "11025 bps", /* 4 */ "7350 bps", /* 6 */ "6300 bps", /* 7 */ NULL }; static char *buffers_labels[] = { "2", "4", "8", "16", "32", "64", NULL }; static char *volume_labels[] = { "Low", "Medium", "High", NULL }; struct NewGadget ng; struct Gadget *gad; int topborder; if (!(IntuitionBase = OpenLibrary ((UBYTE *) "intuition.library", 37))) return "cannot open intuition.library"; if (!(GadToolsBase = OpenLibrary ((UBYTE *) "gadtools.library", 37))) return "cannot open gadtools.library"; if (!(GfxBase = (struct GfxBase *) OpenLibrary ((UBYTE *) "graphics.library", 37))) return "cannot open graphics.library"; /* does the font exist? */ if (!(font = OpenFont (&Topaz8))) return "cannot open topaz 8 font"; CloseFont (font); if (!(g_screen = LockPubScreen (NULL))) return "cannot lock default public screen"; if (!(g_visual_info = GetVisualInfo (g_screen, TAG_END))) return "GetVisualInfo() failed"; gad = CreateContext (&g_glist); topborder = g_screen->WBorTop + (g_screen->Font->ta_YSize + 1); ng.ng_Width = 20; ng.ng_Height = 12; ng.ng_TextAttr = &Topaz8; ng.ng_VisualInfo = g_visual_info; ng.ng_Flags = 0; for (i=0; i<5; i++) for (j=0; j<4; j++) { ng.ng_GadgetText = (UBYTE *) labels[i*4+j]; ng.ng_GadgetID = i*4 + j + 1; ng.ng_LeftEdge = 10 + j * 24; ng.ng_TopEdge = topborder + 2 + i * 16; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (BUTTON_KIND, gad, &ng, GA_Disabled, TRUE, TAG_END); } ng.ng_GadgetID = GID_PREV; ng.ng_GadgetText = (UBYTE *) "Prev"; ng.ng_Width = 44; ng.ng_LeftEdge = 10; ng.ng_TopEdge = topborder + 2 + 5 * 16; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END); ng.ng_GadgetID = GID_NEXT; ng.ng_GadgetText = (UBYTE *) "Next"; ng.ng_LeftEdge = 58; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END); ng.ng_GadgetID = GID_START; ng.ng_GadgetText = (UBYTE *) "Start"; ng.ng_LeftEdge = 120; ng.ng_TopEdge = topborder + 2 + 4 * 16; ng.ng_Width = 120; ng.ng_Height = 28; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END); ng.ng_GadgetID = GID_STOP; ng.ng_GadgetText = (UBYTE *) "Stop"; ng.ng_LeftEdge = 250; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END); ng.ng_GadgetText = (UBYTE *) "Sampling rate:"; ng.ng_GadgetID = GID_SAMPLING_RATE; ng.ng_Width = 120; ng.ng_Height = 12; ng.ng_LeftEdge = 250; ng.ng_TopEdge = topborder + 2; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (CYCLE_KIND, gad, &ng, GTCY_Labels, sampling_rate_labels, TAG_END); ng.ng_GadgetText = (UBYTE *) "Buffers: "; ng.ng_TopEdge += 16; ng.ng_GadgetID = GID_BUFFERS; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (CYCLE_KIND, gad, &ng, GTCY_Labels, buffers_labels, GTCY_Active, 1, TAG_END); ng.ng_GadgetText = (UBYTE *) "Volume: "; ng.ng_TopEdge += 16; ng.ng_GadgetID = GID_VOLUME; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (CYCLE_KIND, gad, &ng, GTCY_Labels, volume_labels, GTCY_Active, (int) g_volume-1, TAG_END); ng.ng_GadgetID = GID_TRACK; ng.ng_GadgetText = (UBYTE *) "Track"; ng.ng_Width = 25; ng.ng_Height = 12; ng.ng_LeftEdge = 170; ng.ng_TopEdge = topborder + 2 + 3 * 16; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (TEXT_KIND, gad, &ng, GTTX_Border, TRUE, TAG_END); ng.ng_GadgetID = GID_INDEX; ng.ng_GadgetText = (UBYTE *) "Index"; ng.ng_LeftEdge = 250; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (TEXT_KIND, gad, &ng, GTTX_Border, TRUE, TAG_END); ng.ng_GadgetID = GID_TIME; ng.ng_GadgetText = (UBYTE *) "Time"; ng.ng_Width = 50; ng.ng_LeftEdge = 320; g_gadgets[ng.ng_GadgetID] = gad = CreateGadget (TEXT_KIND, gad, &ng, GTTX_Border, TRUE, TAG_END); if (!gad) return "cannot create gadgets"; g_window = OpenWindowTags (NULL, WA_Title, TheVersion + 6, WA_Gadgets, g_glist, WA_Left, 20, WA_Top, 20, WA_Width, 385, WA_Height, topborder + 98, WA_IDCMP, IDCMP_CLOSEWINDOW | BUTTONIDCMP | CYCLEIDCMP, WA_PubScreen, g_screen, WA_DragBar, TRUE, WA_DepthGadget, TRUE, WA_CloseGadget, TRUE, WA_Activate, TRUE, WA_SmartRefresh, TRUE, TAG_END); if (!g_window) return "cannot open window"; return NULL; } void Alloc_Audio (void) { static UBYTE whichannel[] = { 1, 2, 4, 8 }; int i; /* allocate buffers: */ g_audio_base = AllocMem (TOTAL_AUDIO_BUFSIZE + 15, MEMF_PUBLIC | MEMF_CHIP); if (!g_audio_base) Fatal_Error ("cannot allocate memory"); g_cdda_base = AllocMem (TOTAL_CDDA_BUFSIZE + 15, MEMF_PUBLIC | g_memory_type); if (!g_cdda_base) Fatal_Error ("cannot allocate memory"); /* make the buffers quad-word aligned. This greatly helps * performance on '040-powered systems with DMA SCSI * controllers. */ g_cdda_buf[0] = (UBYTE *)(((long) g_cdda_base + 15) & ~15); g_audio_buf[0] = (UBYTE *)(((long) g_audio_base + 15) & ~15); g_cdda_buf[1] = g_cdda_buf[0] + g_buffers * CDDA_BUFSIZE; g_audio_buf[1] = g_audio_buf[0] + g_buffers * AUDIO_BUFSIZE; /* allocate message ports and IO requests: */ if (!(g_audio_port[0] = CreateMsgPort ()) || !(g_audio_port[1] = CreateMsgPort ())) Fatal_Error ("cannot allocate message ports"); g_audio_sigmask[0] = (1 << g_audio_port[0]->mp_SigBit); g_audio_sigmask[1] = (1 << g_audio_port[1]->mp_SigBit); if (!(g_audioreq[0] = AllocMem (sizeof (struct IOAudio), MEMF_PUBLIC | MEMF_CLEAR)) || !(g_audioreq[1] = AllocMem (sizeof (struct IOAudio), MEMF_PUBLIC | MEMF_CLEAR))) Fatal_Error ("cannot allocate memory"); /* open audio device: */ g_audioreq[0]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[0]; g_audioreq[0]->ioa_Request.io_Message.mn_Node.ln_Pri = 0; g_audioreq[0]->ioa_Request.io_Command = ADCMD_ALLOCATE; g_audioreq[0]->ioa_Request.io_Flags = ADIOF_NOWAIT; g_audioreq[0]->ioa_AllocKey = 0; g_audioreq[0]->ioa_Data = whichannel; g_audioreq[0]->ioa_Length = sizeof (whichannel); if (OpenDevice ((UBYTE *) AUDIONAME, 0, (struct IORequest *) g_audioreq[0], 0)) Fatal_Error ("cannot open audio.device\n"); g_audio_device_open = TRUE; *(g_audioreq[1]) = *(g_audioreq[0]); g_audioreq[0]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[0]; g_audioreq[1]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[1]; g_audioreq[0]->ioa_Data = (UBYTE *) g_audio_buf[0]; g_audioreq[1]->ioa_Data = (UBYTE *) g_audio_buf[1]; for (i=0; i<2; i++) { struct IOAudio *req = g_audioreq[i]; req->ioa_Request.io_Command = CMD_WRITE; req->ioa_Request.io_Flags = ADIOF_PERVOL; req->ioa_Length = g_buffers * AUDIO_BUFSIZE; req->ioa_Period = g_period; req->ioa_Volume = 64; req->ioa_Cycles = 1; } } void Alloc_CDROM (void) { #ifdef HRDBLBF int i; #endif g_std_buf_base = AllocMem (CDDA_STD_BUFSIZE + 15, MEMF_PUBLIC | MEMF_CHIP); if (!g_std_buf_base) Fatal_Error ("cannot allocate memory"); #ifndef HRDBLBF g_scsicmd = AllocMem (sizeof (struct SCSICmd), MEMF_PUBLIC | MEMF_CHIP); if (!g_scsicmd) Fatal_Error ("cannot allocate memory"); #else for (i = 0; i < 2; i++) { g_scsicmd[i] = AllocMem (sizeof (struct SCSICmd), MEMF_PUBLIC | MEMF_CHIP); if (!g_scsicmd[i]) Fatal_Error ("cannot allocate memory"); } #endif /* make the buffer quad-word aligned. This greatly helps * performance on '040-powered systems with DMA SCSI * controllers. */ g_cdda_std_buf = (UBYTE *)(((long) g_std_buf_base + 15) & ~15); #ifndef HRDBLBF g_sense_data = g_cdda_std_buf + STD_BUFSIZE; #else for (i = 0; i < 2; i++) g_sense_data[i] = g_cdda_std_buf + STD_BUFSIZE; #endif /* allocate message ports and IO requests: */ if (!(g_cdda_port = CreateMsgPort ())) Fatal_Error ("cannot allocate message port"); g_cdda_sigmask = (1 << g_cdda_port->mp_SigBit); #ifndef HRDBLBF if (!(g_scsireq = CreateIORequest (g_cdda_port, sizeof (struct IOStdReq)))) Fatal_Error ("cannot create IO request\n"); /* open SCSI device: */ g_scsireq->io_Device = NULL; if (OpenDevice ((UBYTE *) g_scsi_device, g_scsi_id, (struct IORequest *) g_scsireq, 0)) { if (g_called_from_cli) Fatal_Error ("Cannot open \"%s\", unit %ld", g_scsi_device, g_scsi_id); else Fatal_Error ("Cannot open \"%s\", unit %ld\n" "Please edit the tooltype entries\n" "in the PlayCDDA icon!", g_scsi_device, g_scsi_id); } #else for (i = 0; i < 2; i++) { if (!(g_scsireq[i] = CreateIORequest (g_cdda_port, sizeof (struct IOStdReq)))) Fatal_Error ("cannot create IO request\n"); /* open SCSI device: */ g_scsireq[i]->io_Device = NULL; if (OpenDevice ((UBYTE *) g_scsi_device, g_scsi_id, (struct IORequest *) g_scsireq[i], 0)) { if (g_called_from_cli) Fatal_Error ("Cannot open \"%s\", unit %ld", g_scsi_device, g_scsi_id); else Fatal_Error ("Cannot open \"%s\", unit %ld\n" "Please edit the tooltype entries\n" "in the PlayCDDA icon!", g_scsi_device, g_scsi_id); } } #endif } void Do_SCSI_Command (UBYTE *p_command, int p_length, short p_phase, int p_sync, int p_direction) { #ifndef HRDBLBF g_scsireq->io_Length = sizeof (struct SCSICmd); g_scsireq->io_Data = (APTR) g_scsicmd; g_scsireq->io_Command = HD_SCSICMD; if (p_phase == -1) { g_scsicmd->scsi_Data = (UWORD *) g_cdda_std_buf; g_scsicmd->scsi_Length = STD_BUFSIZE; } else { g_scsicmd->scsi_Data = (UWORD *) g_cdda_buf[p_phase]; g_scsicmd->scsi_Length = g_buffers * CDDA_BUFSIZE; } g_scsicmd->scsi_Flags = SCSIF_AUTOSENSE | p_direction; g_scsicmd->scsi_SenseData = (UBYTE *) g_sense_data; g_scsicmd->scsi_SenseLength = SENSE_LENGTH; g_scsicmd->scsi_SenseActual = 0; g_scsicmd->scsi_Command = (UBYTE *) p_command; g_scsicmd->scsi_CmdLength = p_length; if (p_sync) { int i = 0; do { DoIO ((struct IORequest *) g_scsireq); if (g_scsicmd->scsi_Status == 0) return; i++; } while (i < 2); Fatal_Error ("sync SCSI command failed"); } else { SendIO ((struct IORequest *) g_scsireq); g_outstanding_cdda_request = TRUE; } #else if (p_phase == -1) { p_phase = 0; g_scsicmd[p_phase]->scsi_Data = (UWORD *) g_cdda_std_buf; g_scsicmd[p_phase]->scsi_Length = STD_BUFSIZE; } else { g_scsicmd[p_phase]->scsi_Data = (UWORD *) g_cdda_buf[p_phase]; g_scsicmd[p_phase]->scsi_Length = g_buffers * CDDA_BUFSIZE; } g_scsireq[p_phase]->io_Length = sizeof (struct SCSICmd); g_scsireq[p_phase]->io_Data = (APTR) g_scsicmd[p_phase]; g_scsireq[p_phase]->io_Command = HD_SCSICMD; g_scsicmd[p_phase]->scsi_Flags = SCSIF_AUTOSENSE | p_direction; g_scsicmd[p_phase]->scsi_SenseData = (UBYTE *) g_sense_data[p_phase]; g_scsicmd[p_phase]->scsi_SenseLength = SENSE_LENGTH; g_scsicmd[p_phase]->scsi_SenseActual = 0; g_scsicmd[p_phase]->scsi_Command = (UBYTE *) p_command; g_scsicmd[p_phase]->scsi_CmdLength = p_length; if (p_sync) { int i = 0; do { DoIO ((struct IORequest *) g_scsireq[p_phase]); if (g_scsicmd[p_phase]->scsi_Status == 0) return; i++; } while (i < 2); Fatal_Error ("sync SCSI command failed"); } else { SendIO ((struct IORequest *) g_scsireq[p_phase]); g_outstanding_cdda_request[p_phase] = TRUE; } #endif } #ifndef HRDBLBF void Wait_CDROM_Command (void) #else void Wait_CDROM_Command (short p_phase) #endif { ULONG sig; #ifndef HRDBLBF sig = Wait (SIGBREAKF_CTRL_C | g_cdda_sigmask); if (sig & g_cdda_sigmask) { if (CheckIO ((struct IORequest *) g_scsireq)) { WaitIO ((struct IORequest *) g_scsireq); g_outstanding_cdda_request = FALSE; if (g_scsicmd->scsi_Status) Fatal_Error ("async SCSI command failed"); } } if (sig & SIGBREAKF_CTRL_C) exit (1); #else /* HR */ if (p_phase < 0 || p_phase > 1) Fatal_Error ("wrong p_phase argument for Wait_CDROM_Command"); if (g_outstanding_cdda_request[p_phase] != FALSE) { for (;;) { sig = Wait (SIGBREAKF_CTRL_C | g_cdda_sigmask); if (sig & g_cdda_sigmask) { if (CheckIO ((struct IORequest *) g_scsireq[p_phase])) { WaitIO ((struct IORequest *) g_scsireq[p_phase]); g_outstanding_cdda_request[p_phase] = FALSE; if (g_scsicmd[p_phase]->scsi_Status) Do_SCSI_Command (g_scsicmd[p_phase]->scsi_Command, g_scsicmd[p_phase]->scsi_CmdLength, p_phase, FALSE, SCSIF_READ); else break; } } if (sig & SIGBREAKF_CTRL_C) exit (1); } } #endif } void Start_CDROM_Read (short p_phase, long p_sector) { static UBYTE cmd[2][12] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0} }; if (p_phase < 0 || p_phase > 1) Fatal_Error ("Invalid p_phase argument for Start_CDROM_Read()"); cmd[p_phase][2] = (p_sector >> 24); cmd[p_phase][3] = ((p_sector >> 16) & 0xFF); cmd[p_phase][4] = ((p_sector >> 8) & 0xFF); cmd[p_phase][5] = (p_sector & 0xFF); if (g_whatdrive == APPLECD300) { cmd[p_phase][0] = 0xD8; cmd[p_phase][9] = g_buffers; Do_SCSI_Command (cmd[p_phase], 12, p_phase, FALSE, SCSIF_READ); } else if (g_whatdrive == TOSHIBA) { cmd[p_phase][0] = 0x28; cmd[p_phase][8] = g_buffers; Do_SCSI_Command (cmd[p_phase], 10, p_phase, FALSE, SCSIF_READ); } } #ifndef HRDBLBF void Wait_CDROM_Read (void) { Wait_CDROM_Command (); } #else void Wait_CDROM_Read (short p_phase) { Wait_CDROM_Command (p_phase); } #endif void Update_Track_Data (short p_num) { g_track_str[0] = '0' + (p_num >> 4); g_track_str[1] = '0' + (p_num & 15); GT_SetGadgetAttrs (g_gadgets[GID_TRACK], g_window, NULL, GTTX_Text, g_track_str, TAG_END); g_track = p_num; } void Update_Index_Data (short p_num) { g_index_str[0] = '0' + (p_num >> 4); g_index_str[1] = '0' + (p_num & 15); GT_SetGadgetAttrs (g_gadgets[GID_INDEX], g_window, NULL, GTTX_Text, g_index_str, TAG_END); g_index = p_num; } void Update_Time_Data (short p_min, short p_sec) { g_time_str[0] = '0' + (p_min >> 4); g_time_str[1] = '0' + (p_min & 15); g_time_str[3] = '0' + (p_sec >> 4); g_time_str[4] = '0' + (p_sec & 15); GT_SetGadgetAttrs (g_gadgets[GID_TIME], g_window, NULL, GTTX_Text, g_time_str, TAG_END); g_minute = p_min; g_seconds = p_sec; } void Convert_Buffer (short p_phase) { short i; short sum; BYTE *src = (BYTE *) g_cdda_buf[p_phase]; BYTE *dst = (BYTE *) g_audio_buf[p_phase]; BYTE *stop = src + (g_buffers * CDDA_BUFSIZE); short skip = ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/4); while (src < stop) { sum = 0; for (i=0; i 127) sum = 127; *dst++ = sum; skip -= g_compression_factor; if (!skip) { /* analyze Q-sub channel data: */ if (g_whatdrive == TOSHIBA) { if (src[1] == 1) { if (((UBYTE *) src)[2] != g_track) Update_Track_Data (((UBYTE *) src)[2]); if (((UBYTE *) src)[3] != g_index) Update_Index_Data (((UBYTE *) src)[3]); if (((UBYTE *) src)[5] != g_seconds || ((UBYTE *) src)[4] != g_minute) Update_Time_Data (((UBYTE *) src)[4], ((UBYTE *) src)[5]); } } else if (g_whatdrive == APPLECD300) { if (src[0] == 1) { if (((UBYTE *) src)[1] != g_track) Update_Track_Data (((UBYTE *) src)[1]); if (((UBYTE *) src)[2] != g_index) Update_Index_Data (((UBYTE *) src)[2]); if (((UBYTE *) src)[8] != g_seconds || ((UBYTE *) src)[7] != g_minute) Update_Time_Data (((UBYTE *) src)[7], ((UBYTE *) src)[8]); } } /* skip Q-sub channel data: */ src += SUBCHANNEL_SIZE; skip = ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/4); } } } void Start_Play_Audio (short p_phase) { BeginIO ((struct IORequest *) (g_audioreq[p_phase])); } void Wait_Play_Audio (short p_phase) { ULONG sig; sig = Wait (SIGBREAKF_CTRL_C | g_audio_sigmask[p_phase]); if (sig & g_audio_sigmask[p_phase]) { while (GetMsg (g_audio_port[p_phase]) == 0) ; } if (sig & SIGBREAKF_CTRL_C) exit (1); } #define FORMAT_CDDA 0x82 #define FORMAT_STD 0x00 void Select_Block_Format (int p_format) { static UBYTE cmd[6] = { 0x15, 0x10, 0, 0, 12, 0 }; static UBYTE mode[12] = { 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0 }; mode[4] = p_format; switch (p_format) { case FORMAT_CDDA: mode[10] = (CDDA_BUFSIZE >> 8); mode[11] = (CDDA_BUFSIZE & 0xFF); break; case FORMAT_STD: mode[10] = (STD_BUFSIZE >> 8); mode[11] = (STD_BUFSIZE & 0xFF); break; } memcpy (g_cdda_std_buf, mode, sizeof (mode)); Do_SCSI_Command (cmd, 6, -1, TRUE, SCSIF_WRITE); } void Read_Drive_Type (void) { static UBYTE cmd[6] = { 0x12, 0, 0, 0, 0, 0}; static char *applecd300string = "SONY CD-ROM CDU-8003"; static char *toshibastring = "TOSHIBA"; UBYTE *buf = g_cdda_std_buf; #if STD_BUFSIZE > 255 cmd[4] = 0xff; #else cmd[4] = STD_BUFSIZE & 0xff; #endif Do_SCSI_Command (cmd, 6, -1, TRUE, SCSIF_READ); if ((buf[0] & 0x1f) != 5) Fatal_Error ("not a CD-ROM device\n"); if (!memcmp(applecd300string, &buf[8], strlen(applecd300string))) { g_whatdrive = APPLECD300; } else if (!memcmp(toshibastring, &buf[8], strlen(toshibastring))) { g_whatdrive = TOSHIBA; } else Fatal_Error ("unsupported CD-ROM drive\n"); } void Read_TOC (void) { static UBYTE cmd[10] = { 0x43, 0, 0, 0, 0, 0, 1, STD_BUFSIZE >> 8, STD_BUFSIZE & 0xFF, 0, }; UBYTE *buf = g_cdda_std_buf; Do_SCSI_Command (cmd, 10, -1, TRUE, SCSIF_READ); g_toc_length = ((buf[0] << 8) + buf[1] - 2) / 8; memcpy (g_toc, buf + 4, 8 * g_toc_length); } void Enable_Track_Buttons (void) { int i, foo; for (i=0; i) */ foo = g_toc[i].track_number; if (foo <= 20 && !(g_toc[i].flags & 4)) { GT_SetGadgetAttrs (g_gadgets[g_toc[i].track_number], g_window, NULL, GA_Disabled, FALSE, TAG_END); } } } long Track_Address (int p_track) { int i; for (i=0; i> 4) * 10 + (g_track & 15); long res; track += p_offset; res = Track_Address (track); return res == -1 ? Track_Address (track - p_offset) : res; } void NTSC_or_PAL (void) { if (GfxBase->DisplayFlags & PAL) g_period = 3546895 / (44100 / g_compression_factor); else g_period = 3579545 / (44100 / g_compression_factor); } void Init_Idle_Mode (void) { GT_SetGadgetAttrs (g_gadgets[GID_STOP], g_window, NULL, GA_Disabled, TRUE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_START], g_window, NULL, GA_Disabled, FALSE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_SAMPLING_RATE], g_window, NULL, GA_Disabled, FALSE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_BUFFERS], g_window, NULL, GA_Disabled, FALSE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_PREV], g_window, NULL, GA_Disabled, TRUE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_NEXT], g_window, NULL, GA_Disabled, TRUE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_TRACK], g_window, NULL, GTTX_Text, "", TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_INDEX], g_window, NULL, GTTX_Text, "", TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_TIME], g_window, NULL, GTTX_Text, "", TAG_END); } void Init_Play_Mode (void) { GT_SetGadgetAttrs (g_gadgets[GID_STOP], g_window, NULL, GA_Disabled, FALSE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_START], g_window, NULL, GA_Disabled, TRUE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_SAMPLING_RATE], g_window, NULL, GA_Disabled, TRUE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_BUFFERS], g_window, NULL, GA_Disabled, TRUE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_PREV], g_window, NULL, GA_Disabled, FALSE, TAG_END); GT_SetGadgetAttrs (g_gadgets[GID_NEXT], g_window, NULL, GA_Disabled, FALSE, TAG_END); g_track = g_index = g_minute = g_seconds = 0xFF; } int Get_Intui_Message (long *p_sec_no) { struct IntuiMessage *imsg; struct Gadget *gad; ULONG class; UWORD code; if (imsg = GT_GetIMsg (g_window->UserPort)) { class = imsg->Class; code = imsg->Code; gad = (struct Gadget *) imsg->IAddress; GT_ReplyIMsg (imsg); switch (class) { case IDCMP_CLOSEWINDOW: { g_bye = TRUE; return TRUE; } case IDCMP_GADGETUP: if (gad->GadgetID <= 20) *p_sec_no = Track_Address (gad->GadgetID); else if (gad->GadgetID == GID_STOP) return TRUE; else if (gad->GadgetID == GID_VOLUME) g_volume = code + 1; else if (gad->GadgetID == GID_PREV) *p_sec_no = Next_Track (-1); else if (gad->GadgetID == GID_NEXT) *p_sec_no = Next_Track (+1); break; default: break; } } return FALSE; } #define INC_SEC(ptr,inc) *(ptr) += (inc) void main (int argc, char *argv[]) { short i=0; long sec_no; char *err; struct IntuiMessage *imsg; t_bool done; struct Gadget *gad; ULONG class; UWORD code; char *error_msg = NULL; atexit (Cleanup); g_called_from_cli = (argc > 0); if (g_called_from_cli) { static UBYTE* template = (UBYTE *) "DEVICE/A,UNIT/A/N,CHIP/S,FAST/S,DMA/S,ANY/S," "LOW/S,MEDIUM/S,HIGH/S"; enum Arg { ARG_DEVICE, ARG_UNIT, ARG_CHIP, ARG_FAST, ARG_DMA, ARG_ANY, ARG_LOW, ARG_MEDIUM, ARG_HIGH, ARGCOUNT }; static LONG args[ARGCOUNT]; struct RDArgs* rd; if (rd = ReadArgs (template, args, NULL)) { int cnt_mem = 0; int cnt_vol = 0; strcpy (g_scsi_device, (char*) (args[ARG_DEVICE])); g_scsi_id = args[ARG_UNIT]; if (args[ARG_CHIP]) g_memory_type = MEMF_CHIP, cnt_mem++; if (args[ARG_FAST]) g_memory_type = MEMF_FAST, cnt_mem++; if (args[ARG_DMA]) g_memory_type = MEMF_24BITDMA, cnt_mem++; if (args[ARG_ANY]) g_memory_type = MEMF_ANY, cnt_mem++; if (args[ARG_LOW]) g_volume = 1, cnt_vol++; if (args[ARG_MEDIUM]) g_volume = 2, cnt_vol++; if (args[ARG_HIGH]) g_volume = 3, cnt_vol++; FreeArgs (rd); if (cnt_mem > 1) Fatal_Error ("Only ONE memory option may be used!"); if (cnt_vol > 1) Fatal_Error ("Only ONE volume option may be used!"); } else Fatal_Error ("Args do not match template %s\n", template); strcpy (g_scsi_device, argv[1]); g_scsi_id = atoi (argv[2]); } else { char *str; UBYTE **toolarray; struct WBStartup *wbench_msg; struct DiskObject *dobj; if (!(IconBase = OpenLibrary ((UBYTE *) "icon.library", 37))) exit (1); wbench_msg = (struct WBStartup *) argv; dobj = GetDiskObject ((UBYTE *) wbench_msg->sm_ArgList->wa_Name); if (!dobj) exit (1); toolarray = (UBYTE **) dobj->do_ToolTypes; str = (char *) FindToolType (toolarray, (UBYTE *) "DEVICE"); if (!str) error_msg = "Tool type DEVICE is missing"; strcpy (g_scsi_device, str); str = (char *) FindToolType (toolarray, (UBYTE *) "UNIT"); if (!str) error_msg = "Tool type UNIT is missing"; g_scsi_id = atoi (str); str = (char *) FindToolType (toolarray, (UBYTE *) "MEMORY"); if (str) { if (strcmp (str, "CHIP") == 0) g_memory_type = MEMF_CHIP; else if (strcmp (str, "FAST") == 0) g_memory_type = MEMF_FAST; else if (strcmp (str, "DMA") == 0) g_memory_type = MEMF_24BITDMA; else if (strcmp (str, "ANY") == 0) g_memory_type = MEMF_ANY; else error_msg = "Invalid MEMORY tool type"; } str = (char *) FindToolType (toolarray, (UBYTE *) "VOLUME"); if (str) { if (strcmp (str, "LOW") == 0) g_volume = 1; else if (strcmp (str, "MEDIUM") == 0) g_volume = 2; else if (strcmp (str, "HIGH") == 0) g_volume = 3; else error_msg = "Invalid VOLUME tool type"; }; FreeDiskObject (dobj); } err = Open_User_Interface (); if (err) Fatal_Error ("ERROR: %s", err); if (error_msg) Fatal_Error ("%s", error_msg); Alloc_CDROM (); Read_Drive_Type (); if (g_whatdrive == TOSHIBA) Select_Block_Format (FORMAT_CDDA); Read_TOC (); Enable_Track_Buttons (); if (!First_Track ()) Fatal_Error ("This is no audio disk"); while (!g_bye) { Init_Idle_Mode (); done = FALSE; while (!done) { Wait (1 << g_window->UserPort->mp_SigBit); while (imsg = GT_GetIMsg (g_window->UserPort)) { class = imsg->Class; code = imsg->Code; gad = (struct Gadget *) imsg->IAddress; GT_ReplyIMsg (imsg); switch (class) { case IDCMP_CLOSEWINDOW: Select_Block_Format (FORMAT_STD); exit (0); case IDCMP_GADGETUP: if (gad->GadgetID <= 20) { sec_no = Track_Address (gad->GadgetID); done = TRUE; } else if (gad->GadgetID == GID_START) { sec_no = Track_Address (First_Track ()); done = TRUE; } else if (gad->GadgetID == GID_VOLUME) g_volume = code + 1; else if (gad->GadgetID == GID_SAMPLING_RATE) { static short factors[] = { 2, 3, 4, 6, 7 }; g_compression_factor = factors[code]; } else if (gad->GadgetID == GID_BUFFERS) { static short buffers[] = { 2, 4, 8, 16, 32, 64 }; g_buffers = buffers[code]; } break; default: break; } } } Init_Play_Mode (); NTSC_or_PAL (); Alloc_Audio (); Start_CDROM_Read (0, sec_no); #ifndef HRDBLBF Wait_CDROM_Read (); #else Wait_CDROM_Read (0); #endif INC_SEC (&sec_no, g_buffers); Start_CDROM_Read (1, sec_no); Convert_Buffer (0); #ifndef HRDBLBF Wait_CDROM_Read (); #else Wait_CDROM_Read (1); #endif Convert_Buffer (1); Start_Play_Audio (0); Start_Play_Audio (1); INC_SEC (&sec_no, g_buffers); Start_CDROM_Read (0, sec_no); for (;;) { /* HERE: scsi-request i is active, play-audio i is active and play-audio 1-i is queued */ if (Get_Intui_Message (&sec_no)) break; #ifndef HRDBLBF Wait_CDROM_Read (); #else Wait_CDROM_Read (i); #endif INC_SEC (&sec_no, g_buffers); Start_CDROM_Read (1-i, sec_no); Wait_Play_Audio (i); Convert_Buffer (i); Start_Play_Audio (i); i = 1-i; } #ifndef HRDBLBF Wait_CDROM_Read (); #else Wait_CDROM_Read (0); Wait_CDROM_Read (1); #endif Wait_Play_Audio (i); Wait_Play_Audio (1-i); Cleanup_Audio (); } if (g_whatdrive == TOSHIBA) Select_Block_Format (FORMAT_STD); exit (0); }