Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Play.c
/* File: Play.c |
* Purpose: demonstrate Apple CD SC control |
* Date: 17 June 1988 |
* Comments: |
* This code is written for LightSpeed C version 2.15 |
* Create a project with this source plus MacTraps. |
* Requires some associated resources (in the file Play.r). |
* With this program on your hard disk, you can click |
* on a track on an Audio CD and the CD SC drive will |
* start audio play, beginning at that track and continuing |
* to the end of the disc. |
* |
* Revisions: |
* |
* Converted to converted to mpw 3.0 8/29 mb |
* |
* Build instructions: |
* |
* rez -c MBAU :RIncludes:Types.r Play.r -o Play |
* c Play.c -w |
* link Play.c.o -o Play -c aucd ¶ |
* "{CLibraries}"CRuntime.o ¶ |
* "{CLibraries}"CInterface.o ¶ |
* "{Libraries}"Interface.o |
* |
* |
*/ |
#include <types.h> /* Nearly always required */ |
#include <quickdraw.h> /* To access the qd globals */ |
#include <fonts.h> /* Only for InitFonts() trap */ |
#include <events.h> /* GetNextEvent(), ... */ |
#include <windows.h> /* GetNewWindow(), ... */ |
#include <dialogs.h> /* InitDialogs() and GetNewDialog() */ |
#include <menus.h> /* EnableItem(), DisableItem() */ |
#include <desk.h> /* SystemTask(), SystemClick() */ |
#include <TextEdit.h> |
#include <Resources.h> /* GetResource() */ |
#include <OSUtils.h> /* SysBeep() */ |
#include <ToolUtils.h> |
#include <SegLoad.h> |
#include <Strings.h> |
#include <Devices.h> |
#include <Files.h> |
#include <Packages.h> |
#include <Memory.h> |
#include <OSEvents.h> |
/* Some constants, from the CD SC Developer's Guide chapter 7 */ |
#define TRACKADDR 2 |
#define STEREO 9 |
#define INPROGRESS 0 |
/* Some commands, from the CD SC Developer's Guide chapter 7 */ |
#define APLAY 104 |
#define ASTOP 106 |
#define ASTATUS 107 |
/* The resource ID I use for my error dialog */ |
#define errorID 128 |
/* prototype function declarations. */ |
void Error(char *, short); |
void ExtractTrackNo(char *, short *); |
OSErr AStop(short, short); |
OSErr APlay(short, short); |
OSErr Play(char *, short); |
short GetDrvRefNum(short); |
void PlayOnStartup(short); |
Boolean AskAndPlay(void); |
void main(void); |
pascal void Debugger(/*void*/) extern 0xA9FF; |
/************************************************************************ |
* |
* Function: Error |
* |
* Purpose: Report an error to the user. |
* |
* Returns: nothing |
* |
* Side Effects: none. |
* |
* Description: Takes a string and a result code. Convert the result |
* into a pascal string using NumToString() and then just |
* do a switch to determine which friendly error message |
* to put up on the screen. ParamText() sets up the alert |
* so that it has the correct information. Use Alert() to |
* actually display the message to the user. |
* |
************************************************************************/ |
void |
Error(where, result) |
char *where; |
short result; |
{ |
DialogPtr dPtr; |
short itemhit; |
Str255 strResult; |
long longResult; |
longResult = result; |
NumToString(longResult, strResult); |
switch (result) |
{ |
case -56: |
ParamText(where, strResult, "\pSpecified drive number doesn't match any number in the drive queue.", "\p"); |
break; |
case -51: |
ParamText(where, strResult, "\pReference number specifies nonexistent access path.", "\p"); |
break; |
case -50: |
ParamText(where, strResult, "\pError in parameter list.", "\p"); |
break; |
case -43: |
ParamText(where, strResult, "\pFile not found.", "\p"); |
break; |
case -36: |
ParamText(where, strResult, "\pI/O error.", "\p"); |
break; |
case -35: |
ParamText(where, strResult, "\pNo such volume.", "\p"); |
break; |
case -21: |
ParamText(where, strResult, "\pBad unit number.", "\p"); |
break; |
default: |
ParamText(where, strResult, "\p", "\p"); |
break; |
} |
Alert(errorID, (ProcPtr) NULL); |
} |
/************************************************************************ |
* |
* Function: ExtractTrackNo |
* |
* Purpose: Extract track number in BCD from PString |
* |
* Returns: nothing |
* |
* Side Effects: *track gets a new value |
* |
* Description: Extract track number in BCD from PString "name". |
* "name" is always of the form "Track XX", where XX |
* ranges from " 1" (1 with a leading space) to "99" |
* (You can't have more than 99 tracks on a compact disc. |
* Bet you didn't know that, did you? Right in the "Yellow |
* Book" specification of compact disc encoding.) |
* |
************************************************************************/ |
void |
ExtractTrackNo(name, track) |
char *name; |
short *track; |
{ |
short size; |
short t; |
t = 0; |
size = *name; |
if (name[size-1] != ' ') |
t = (name[size-1] - '0') * 16; |
t += name[size] - '0'; |
*track = t; |
} |
/************************************************************************ |
* |
* Function: AStop |
* |
* Purpose: stop playing an audio track |
* |
* Returns: OSErr. Probably either |
* noErr everything's hunky-dory! |
* paramErr you messed up the call somehow. |
* |
* Side Effects: stops play. |
* |
* Description: The track that you pass in is the LAST track that you |
* want to have play. This means that if you wanted to |
* play only one track, you'd pass the same value to |
* this routine and APlay() [q.v.] |
* |
* Note that this routine isn't called in this sample, |
* but it's included for your enjoyment. |
* |
************************************************************************/ |
OSErr |
AStop(track, refNum) |
short track; |
short refNum; |
{ |
struct { |
short addrFormat; |
long address; |
} csParam; |
csParam.addrFormat = TRACKADDR; |
csParam.address = track; |
return (Control(refNum, ASTOP, &csParam)); |
} |
/************************************************************************ |
* |
* Function: APlay |
* |
* Purpose: start playing an audio track |
* |
* Returns: OSErr. Probably either |
* noErr everything's hunky-dory! |
* paramErr you messed up the call somehow. |
* |
* Side Effects: starts play. By default, this will play until the |
* end of the disc. |
* |
* Description: The track that you pass in is the first track that you |
* want to have play. |
* |
************************************************************************/ |
OSErr |
APlay(track, refNum) |
short track; |
short refNum; |
{ |
struct { |
short addrFormat; |
long address; |
short stopAddress; |
short playMode; |
} csParam; |
csParam.addrFormat = TRACKADDR; |
csParam.address = track; /* must be in BCD */ |
csParam.stopAddress = 0; |
csParam.playMode = STEREO; |
return (Control(refNum, APLAY, &csParam)); |
} |
/************************************************************************ |
* |
* Function: Play |
* |
* Purpose: play a track, given it's "filename" |
* |
* Returns: OSErr |
* whatever is returned by APlay() |
* |
* Side Effects: starts play of the audio track. |
* |
* Description: The two parameters passed in are the file name (which |
* will always be of the form "Track XX", XX varying from |
* " 1" to "99") and the driver reference number. Extract |
* the track number and use it to call APlay() [q.v.] |
* |
************************************************************************/ |
OSErr |
Play(name, driveNumber) |
char *name; |
short driveNumber; |
{ |
short trackno; |
OSErr result; |
ExtractTrackNo(name, &trackno); |
return( APlay(trackno, driveNumber) ); |
} |
/************************************************************************ |
* |
* Function: GetDrvRefNum |
* |
* Purpose: Get the driver reference number |
* |
* Returns: short. The driver reference number |
* |
* Side Effects: none. |
* |
* Description: PBHGetVInfo() will retrieve the driver reference |
* number, given the vRefNum associated with a file. |
* We acquired the vRefNum as something passed into |
* the program, either by SFGetFile() or by |
* GetAppFile(). |
* |
* We'll use the driver reference number in all our |
* control calls to the driver. |
* |
************************************************************************/ |
short |
GetDrvRefNum(vRefNum) |
short vRefNum; |
{ |
HParamBlockRec io; |
io.volumeParam.ioCompletion = NULL; |
io.volumeParam.ioNamePtr = NULL; |
io.volumeParam.ioVRefNum = vRefNum; |
io.volumeParam.ioVolIndex = 0; |
PBHGetVInfo(&io, false); |
return io.volumeParam.ioVDRefNum; |
} |
/************************************************************************ |
* |
* Function: PlayOnStartup |
* |
* Purpose: Play the files passed in to our application |
* |
* Returns: nothing |
* |
* Side Effects: plays some files. |
* |
* Description: Loop, using GetAppFiles() to get the next "file" |
* (actually audio CD track) to play. Continue until |
* we run out of files to play or until we get some |
* error while trying to play a track. |
* |
* Exercise to the programmer: |
* As this routine is currently written, it doesn't |
* handle opening multiple tracks at once. (e.g. the |
* user selects five tracks and opens them all.) Right |
* now, you'll only hear the last track (each Play() |
* command cancels the previous one.) |
* |
* Add a routine to check the status of the CD SC |
* drive (using AStatus) so that you wait for a track |
* to finish before starting the next track. |
* |
************************************************************************/ |
void |
PlayOnStartup(count) |
short count; |
{ |
short i; |
AppFile app; |
OSErr result; |
for (i = 0; i++<count; ) |
{ |
GetAppFiles(i, &app); |
if (app.fType == 'trak') |
{ |
result = Play((char *)app.fName, GetDrvRefNum(app.vRefNum)); |
if (result != noErr) |
Error("\pPlay returned", result); |
} |
} |
} |
/************************************************************************ |
* |
* Function: AskAndPlay |
* |
* Purpose: Prompt the user for a track and play it |
* |
* Returns: Boolean. Either: |
* true the user wants us to continue |
* false the user wants us to exit, or an error |
* occurred. |
* |
* Side Effects: may play a track. |
* |
* Description: Use SFGetFile() with a specific type ('trak') to get |
* a list of just audio CD tracks. If the user selects |
* an audio CD track, play it. |
* |
************************************************************************/ |
Boolean |
AskAndPlay() |
{ |
SFReply sf; |
short refnum; |
static Point where = {100,100}; |
static OSType sftl = 'trak'; |
Boolean result; |
OSErr errorCode; |
result = true; |
FlushEvents(everyEvent-diskMask,0); |
SFGetFile(where, "\pSelect Track to Play", (ProcPtr)NULL, |
1, &sftl, (ProcPtr)NULL, &sf); |
if (!sf.good) |
result = false; |
else |
{ |
errorCode = Play((char *)sf.fName, GetDrvRefNum(sf.vRefNum)); |
if (errorCode != noErr) |
{ |
Error("\pPlay returned", result); |
result = false; |
} |
} |
return result; |
} |
/************************************************************************ |
* |
* Function: main |
* |
* Purpose: The Master Cylinder. This is where we start. |
* |
* Returns: nothing. |
* |
* Side Effects: does whatever you tell it. |
* |
* Description: Do the standard Macintosh initialization. Following |
* all the boilerplate, use CountAppFiles() to see how |
* we were started. We could be started one of three |
* ways: |
* 1) The user opened our application. We will have |
* a count of zero. Go ask the user for a track. |
* 2) The user opened an audio CD track "file". We |
* will have a non-zero count. Go play the track(s) |
* that the user asked. |
* |
************************************************************************/ |
void |
main() |
{ |
short message, count; |
short refNum; |
MaxApplZone(); |
MoreMasters(); |
InitGraf(&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(0); |
InitCursor(); |
FlushEvents(everyEvent-diskMask,0); |
CountAppFiles(&message, &count); |
if (count) |
PlayOnStartup(count); |
else |
while (AskAndPlay()) |
; /* null loop */ |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14