1 #include "3dc.h"
2 #include "inline.h"
3 #include "psndplat.h"
4 #include "cd_player.h"
5
6 #define UseLocalAssert Yes
7 #include "ourasert.h"
8
9 /* KJL 12:40:35 07/05/98 - This is code derived from Patrick's original stuff &
10 moved into it's own file. */
11
12 /* Patrick 10/6/97 -------------------------------------------------------------
13 CDDA Support
14 ----------------------------------------------------------------------------*/
15 #define NO_DEVICE -1
16 int cdDeviceID = NO_DEVICE;
17 int cdAuxDeviceID = NO_DEVICE;
18
19 /* Patrick 9/6/97 -------------------------------------------------------------
20 ----------------------------------------------------------------------------
21 CDDA Support
22 -----------------------------------------------------------------------------
23 -----------------------------------------------------------------------------*/
24 static int CDDASwitchedOn = 0;
25 static int CDDAIsInitialised = 0;
26 static int CDDAVolume = CDDA_VOLUME_DEFAULT;
27 CDOPERATIONSTATES CDDAState;
28
29 static DWORD PreGameCDVolume;//windows cd volume before the game started
30
31 static CDTRACKID TrackBeingPlayed;
32 static enum CDCOMMANDID LastCommandGiven;
33
34 extern HWND hWndMain;
35
36 int CDPlayerVolume; // volume control from menus
37
38 int CDTrackMax=-1; //highest track number on cd
39
CDDA_Start(void)40 void CDDA_Start(void)
41 {
42 CDDAVolume = CDDA_VOLUME_DEFAULT;
43 CDPlayerVolume = CDDAVolume;
44 CDDAState = CDOp_Idle;
45 CDDAIsInitialised = 0;
46 if(PlatStartCDDA()!=SOUND_PLATFORMERROR)
47 {
48 CDDAIsInitialised = 1;
49 CDDA_SwitchOn();
50 CDDA_ChangeVolume(CDDAVolume); /* init the volume */
51 CDDA_CheckNumberOfTracks();
52 }
53 LastCommandGiven = CDCOMMANDID_Start;
54 }
55
CDDA_End(void)56 void CDDA_End(void)
57 {
58 if(!CDDAIsInitialised) return;
59
60 CDDA_Stop();
61 PlatChangeCDDAVolume(CDDA_VOLUME_RESTOREPREGAMEVALUE);
62 PlatEndCDDA();
63 CDDA_SwitchOff();
64 CDDAIsInitialised = 0;
65
66 LastCommandGiven = CDCOMMANDID_End;
67 }
68
CDDA_Management(void)69 void CDDA_Management(void)
70 {
71 if(!CDDASwitchedOn) return; /* CDDA is off */
72 if(CDDAState==CDOp_Playing) return; /* already playing */
73 PlatCDDAManagement();
74 }
75
CDDA_Play(int CDDATrack)76 void CDDA_Play(int CDDATrack)
77 {
78 int ok;
79
80 if(!CDDASwitchedOn) return; /* CDDA is off */
81 if(CDDAState==CDOp_Playing) return; /* already playing */
82 if((CDDATrack<=0)||(CDDATrack>=CDTrackMax)) return; /* no such track */
83
84 ok = PlatPlayCDDA((int)CDDATrack);
85 if(ok!=SOUND_PLATFORMERROR)
86 {
87 CDDAState=CDOp_Playing;
88 LastCommandGiven = CDCOMMANDID_Play;
89 TrackBeingPlayed = CDDATrack;
90 }
91 }
CDDA_PlayLoop(int CDDATrack)92 void CDDA_PlayLoop(int CDDATrack)
93 {
94 int ok;
95
96 if(!CDDASwitchedOn) return; /* CDDA is off */
97 if(CDDAState==CDOp_Playing) return; /* already playing */
98 if((CDDATrack<=0)||(CDDATrack>=CDTrackMax)) return; /* no such track */
99
100 ok = PlatPlayCDDA((int)CDDATrack);
101 if(ok!=SOUND_PLATFORMERROR)
102 {
103 CDDAState=CDOp_Playing;
104 LastCommandGiven = CDCOMMANDID_PlayLoop;
105 TrackBeingPlayed = CDDATrack;
106 }
107 }
108
CheckCDVolume(void)109 extern void CheckCDVolume(void)
110 {
111 if (CDDAVolume != CDPlayerVolume)
112 {
113 CDDA_ChangeVolume(CDPlayerVolume);
114 }
115 }
CDDA_ChangeVolume(int volume)116 void CDDA_ChangeVolume(int volume)
117 {
118 if(!CDDASwitchedOn) return; /* CDDA is off */
119 if(volume<CDDA_VOLUME_MIN) return;
120 if(volume>CDDA_VOLUME_MAX) return;
121
122 if(CDDA_IsOn())
123 {
124 if(PlatChangeCDDAVolume(volume))
125 {
126 CDDAVolume=volume;
127 CDPlayerVolume = volume;
128 LastCommandGiven = CDCOMMANDID_ChangeVolume;
129 }
130 }
131 }
132
CDDA_GetCurrentVolumeSetting(void)133 int CDDA_GetCurrentVolumeSetting(void)
134 {
135 return CDDAVolume;
136 }
137
CDDA_Stop()138 void CDDA_Stop()
139 {
140 int ok;
141 if(!CDDASwitchedOn) return; /* CDDA is off */
142 if(CDDAState!=CDOp_Playing) return; /* nothing playing */
143 ok = PlatStopCDDA();
144 CDDAState=CDOp_Idle;
145 LastCommandGiven = CDCOMMANDID_Stop;
146 }
147
CDDA_SwitchOn()148 void CDDA_SwitchOn()
149 {
150 LOCALASSERT(!CDDA_IsPlaying());
151 if(CDDAIsInitialised) CDDASwitchedOn = 1;
152 }
153
CDDA_SwitchOff()154 void CDDA_SwitchOff()
155 {
156 if(!CDDASwitchedOn) return; /* CDDA is off already */
157 if(CDDA_IsPlaying()) CDDA_Stop();
158 CDDASwitchedOn = 0;
159 }
160
CDDA_IsOn()161 int CDDA_IsOn()
162 {
163 return CDDASwitchedOn;
164 }
165
CDDA_IsPlaying()166 int CDDA_IsPlaying()
167 {
168 if(CDDAState==CDOp_Playing)
169 {
170 LOCALASSERT(CDDASwitchedOn);
171 return 1;
172 }
173 return 0;
174 }
175
CDDA_CheckNumberOfTracks()176 int CDDA_CheckNumberOfTracks()
177 {
178 int numTracks=0;
179
180 if(CDDA_IsOn())
181 {
182 PlatGetNumberOfCDTracks(&numTracks);
183
184 //if there is only one track , then it probably can't be used anyway
185 if(numTracks==1) numTracks=0;
186
187 //store the maximum allowed track number
188 CDTrackMax=numTracks;
189 }
190 return numTracks;
191 }
192
193
194
195 /* win95 specific */
196
PlatStartCDDA(void)197 int PlatStartCDDA(void)
198 {
199 static void PlatGetCDDAVolumeControl(void);
200 DWORD dwReturn;
201 MCI_OPEN_PARMS mciOpenParms;
202
203 /* Initialise device handles */
204 cdDeviceID = NO_DEVICE;
205 cdAuxDeviceID = NO_DEVICE;
206
207 /* try to open mci cd-audio device */
208 mciOpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;
209 dwReturn = mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,(DWORD)(LPVOID)&mciOpenParms);
210 if(dwReturn)
211 {
212 /* error */
213 cdDeviceID = NO_DEVICE;
214 return SOUND_PLATFORMERROR;
215 }
216 cdDeviceID = mciOpenParms.wDeviceID;
217
218 /* now try to get the cd volume control, by obtaining the auxiliary device id for
219 the cd-audio player*/
220 PlatGetCDDAVolumeControl();
221 return 0;
222 }
223
224 /* this is a support function for PlatStartCDDA() */
225 #if 0
226 static void PlatGetCDDAVolumeControl(void)
227 {
228 MMRESULT mmres;
229 unsigned int numAuxDevs,i;
230
231 numAuxDevs = auxGetNumDevs();
232 /* search the auxilary device list for the cd player */
233 for(i=0;i<numAuxDevs;i++)
234 {
235 AUXCAPS devCaps;
236 mmres = auxGetDevCaps(i,&devCaps,sizeof(AUXCAPS));
237 if(mmres==MMSYSERR_NOERROR)
238 {
239 if((devCaps.wTechnology&AUXCAPS_CDAUDIO)&&(devCaps.dwSupport&AUXCAPS_VOLUME))
240 {
241 cdAuxDeviceID = i;
242 }
243 }
244 }
245 }
246 #else
PlatGetCDDAVolumeControl(void)247 static void PlatGetCDDAVolumeControl(void)
248 {
249 int i;
250 int numDev = mixerGetNumDevs();
251
252
253 //go through the mixer devices searching for one that can deal with the cd volume
254 for(i=0;i<numDev;i++)
255 {
256 HMIXER handle;
257 if(mixerOpen(&handle,i,0,0,MIXER_OBJECTF_MIXER ) == MMSYSERR_NOERROR )
258 {
259
260 //try to get the compact disc mixer line
261 MIXERLINE line;
262 line.cbStruct=sizeof(MIXERLINE);
263 line.dwComponentType=MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
264
265 if(mixerGetLineInfo(handle,&line,MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
266 {
267 MIXERLINECONTROLS lineControls;
268 MIXERCONTROL control;
269
270
271 lineControls.cbStruct=sizeof(MIXERLINECONTROLS);
272 lineControls.dwLineID=line.dwLineID;
273 lineControls.pamxctrl=&control;
274 lineControls.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME ;
275 lineControls.cControls=1;
276 lineControls.cbmxctrl=sizeof(MIXERCONTROL);
277
278 control.cbStruct=sizeof(MIXERCONTROL);
279
280
281 //try to get the volume control
282 if(mixerGetLineControls(handle,&lineControls,MIXER_GETLINECONTROLSF_ONEBYTYPE)==MMSYSERR_NOERROR)
283 {
284
285 MIXERCONTROLDETAILS details;
286 MIXERCONTROLDETAILS_UNSIGNED detailValue;
287
288 details.cbStruct=sizeof(MIXERCONTROLDETAILS);
289 details.dwControlID=control.dwControlID;
290 details.cChannels=1;
291 details.cMultipleItems=0;
292 details.cbDetails=sizeof(MIXERCONTROLDETAILS_UNSIGNED);
293 details.paDetails=&detailValue;
294
295 //get the current volume so that we can restore it later
296 if(mixerGetControlDetails(handle,&details,MIXER_GETCONTROLDETAILSF_VALUE)==MMSYSERR_NOERROR)
297 {
298 PreGameCDVolume = detailValue.dwValue;
299 mixerClose(handle);
300
301 return; //success
302 }
303 }
304 }
305
306
307 mixerClose(handle);
308 }
309
310 }
311
312 return;
313 }
314 #endif
315
316
PlatEndCDDA(void)317 void PlatEndCDDA(void)
318 {
319 DWORD dwReturn;
320
321 /* check the cdDeviceId */
322 if(cdDeviceID==NO_DEVICE) return;
323
324 dwReturn = mciSendCommand((UINT)cdDeviceID,MCI_CLOSE,MCI_WAIT,NULL);
325 cdDeviceID=NO_DEVICE;
326
327 /* reset the auxilary device handle */
328 cdAuxDeviceID = NO_DEVICE;
329 }
330
PlatPlayCDDA(int track)331 int PlatPlayCDDA(int track)
332 {
333 DWORD dwReturn;
334 MCI_SET_PARMS mciSetParms = {0,0,0};
335 MCI_PLAY_PARMS mciPlayParms = {0,0,0};
336 MCI_STATUS_PARMS mciStatusParms = {0,0,0,0};
337
338 /* check the cdDeviceId */
339 if(cdDeviceID==NO_DEVICE) return SOUND_PLATFORMERROR;
340
341 /* set the time format */
342 mciSetParms.dwTimeFormat = MCI_FORMAT_MSF;
343 dwReturn = mciSendCommand((UINT)cdDeviceID,MCI_SET,MCI_SET_TIME_FORMAT,(DWORD)(LPVOID) &mciSetParms);
344 if(dwReturn)
345 {
346 // NewOnScreenMessage("CD ERROR - TIME FORMAT");
347 /* error */
348 return SOUND_PLATFORMERROR;
349 }
350
351 /* find the length of the track... */
352 mciStatusParms.dwItem = MCI_STATUS_LENGTH;
353 mciStatusParms.dwTrack = track;
354 dwReturn = mciSendCommand((UINT)cdDeviceID,MCI_STATUS,MCI_STATUS_ITEM|MCI_TRACK,(DWORD)(LPVOID)&mciStatusParms);
355 if(dwReturn)
356 {
357 /* error */
358 // NewOnScreenMessage("CD ERROR - GET LENGTH");
359 return SOUND_PLATFORMERROR;
360 }
361
362 /* set the time format */
363 mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
364 dwReturn = mciSendCommand((UINT)cdDeviceID,MCI_SET,MCI_SET_TIME_FORMAT,(DWORD)(LPVOID) &mciSetParms);
365 if(dwReturn)
366 {
367 /* error */
368 // NewOnScreenMessage("CD ERROR - TIME FORMAT");
369 return SOUND_PLATFORMERROR;
370 }
371
372 /* play the track: set up for notification when track finishes, or an error occurs */
373 mciPlayParms.dwFrom=MCI_MAKE_TMSF(track,0,0,0);
374 mciPlayParms.dwTo=MCI_MAKE_TMSF(track, MCI_MSF_MINUTE(mciStatusParms.dwReturn),
375 MCI_MSF_SECOND(mciStatusParms.dwReturn),
376 MCI_MSF_FRAME(mciStatusParms.dwReturn));
377 mciPlayParms.dwCallback=(DWORD)hWndMain;
378 dwReturn = mciSendCommand((UINT)cdDeviceID,MCI_PLAY,MCI_FROM|MCI_TO|MCI_NOTIFY,(DWORD)(LPVOID)&mciPlayParms);
379 if(dwReturn)
380 {
381 /* error */
382 // NewOnScreenMessage("CD ERROR - PLAY");
383 return SOUND_PLATFORMERROR;
384 }
385 return 0;
386 }
387
PlatGetNumberOfCDTracks(int * numTracks)388 int PlatGetNumberOfCDTracks(int* numTracks)
389 {
390 DWORD dwReturn;
391 MCI_STATUS_PARMS mciStatusParms = {0,0,0,0};
392
393 /* check the cdDeviceId */
394 if(cdDeviceID==NO_DEVICE) return SOUND_PLATFORMERROR;
395 if(!numTracks) return SOUND_PLATFORMERROR;
396
397
398 /* find the number tracks... */
399 mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS ;
400 dwReturn = mciSendCommand((UINT)cdDeviceID,MCI_STATUS,MCI_STATUS_ITEM ,(DWORD)(LPVOID)&mciStatusParms);
401 if(dwReturn)
402 {
403 /* error */
404 return SOUND_PLATFORMERROR;
405 }
406
407 //number of tracks is in the dwReturn member
408 *numTracks=mciStatusParms.dwReturn;
409
410
411 return 0;
412
413 }
414
PlatStopCDDA(void)415 int PlatStopCDDA(void)
416 {
417 DWORD dwReturn;
418
419 /* check the cdDeviceId */
420 if(cdDeviceID==NO_DEVICE)
421 {
422 return SOUND_PLATFORMERROR;
423 }
424
425 /* stop the cd player */
426 dwReturn = mciSendCommand((UINT)cdDeviceID,MCI_STOP,MCI_WAIT,NULL);
427 if(dwReturn)
428 {
429 /* error */
430 return SOUND_PLATFORMERROR;
431 }
432 return 0;
433 }
434 #if 0
435 int PlatChangeCDDAVolume(int volume)
436 {
437 MMRESULT mmres;
438 unsigned int newVolume;
439
440 /* check the cdDeviceId */
441 if(cdDeviceID==NO_DEVICE) return SOUND_PLATFORMERROR;
442 /* check the mixer device id */
443 if(cdAuxDeviceID==NO_DEVICE) return SOUND_PLATFORMERROR;
444
445 /* scale and set the new volume */
446 {
447 int channelVolume;
448 channelVolume = VOLUME_CDDA_MINPLAT + WideMulNarrowDiv(volume,
449 (VOLUME_CDDA_MAXPLAT-VOLUME_CDDA_MINPLAT), (CDDA_VOLUME_MAX-CDDA_VOLUME_MIN));
450 if(channelVolume < VOLUME_CDDA_MINPLAT) channelVolume = VOLUME_CDDA_MINPLAT;
451 if(channelVolume > VOLUME_CDDA_MAXPLAT) channelVolume = VOLUME_CDDA_MAXPLAT;
452
453 /* set left and right channels (if there is only one channel,
454 should still work ok)*/
455 newVolume = channelVolume|(channelVolume<<16);
456 }
457 PlatGetCDDAVolumeControl();
458
459 mmres = auxSetVolume((UINT)cdAuxDeviceID,(DWORD)newVolume);
460 if(mmres==MMSYSERR_NOERROR) return 1;
461 else return SOUND_PLATFORMERROR;
462 }
463 #else
PlatChangeCDDAVolume(int volume)464 int PlatChangeCDDAVolume(int volume)
465 {
466 MMRESULT mmres;
467 unsigned int newVolume;
468 int i;
469 int numDev = mixerGetNumDevs();
470
471 /* check the cdDeviceId */
472 if(cdDeviceID==NO_DEVICE) return SOUND_PLATFORMERROR;
473
474 //go through the mixer devices searching for one that can deal with the cd volume
475 for(i=0;i<numDev;i++)
476 {
477 HMIXER handle;
478 if(mixerOpen(&handle,i,0,0,MIXER_OBJECTF_MIXER ) == MMSYSERR_NOERROR )
479 {
480
481 //try to get the compact disc mixer line
482 MIXERLINE line;
483 line.cbStruct=sizeof(MIXERLINE);
484 line.dwComponentType=MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
485
486 if(mixerGetLineInfo(handle,&line,MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
487 {
488 MIXERLINECONTROLS lineControls;
489 MIXERCONTROL control;
490
491
492 lineControls.cbStruct=sizeof(MIXERLINECONTROLS);
493 lineControls.dwLineID=line.dwLineID;
494 lineControls.pamxctrl=&control;
495 lineControls.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME ;
496 lineControls.cControls=1;
497 lineControls.cbmxctrl=sizeof(MIXERCONTROL);
498
499 control.cbStruct=sizeof(MIXERCONTROL);
500
501
502 //try to get the volume control
503 if(mixerGetLineControls(handle,&lineControls,MIXER_GETLINECONTROLSF_ONEBYTYPE)==MMSYSERR_NOERROR)
504 {
505
506 MIXERCONTROLDETAILS details;
507 MIXERCONTROLDETAILS_UNSIGNED detailValue;
508
509 details.cbStruct=sizeof(MIXERCONTROLDETAILS);
510 details.dwControlID=control.dwControlID;
511 details.cChannels=1;
512 details.cMultipleItems=0;
513 details.cbDetails=sizeof(MIXERCONTROLDETAILS_UNSIGNED);
514 details.paDetails=&detailValue;
515
516
517 if(volume==CDDA_VOLUME_RESTOREPREGAMEVALUE)
518 {
519 //set the volume to what it was before the game started
520 newVolume=PreGameCDVolume;
521 }
522 else
523 {
524 //scale the volume
525 newVolume = control.Bounds.dwMinimum + WideMulNarrowDiv(volume,
526 (control.Bounds.dwMaximum-control.Bounds.dwMinimum), (CDDA_VOLUME_MAX-CDDA_VOLUME_MIN));
527
528 if(newVolume<control.Bounds.dwMinimum) newVolume=control.Bounds.dwMinimum;
529 if(newVolume>control.Bounds.dwMaximum) newVolume=control.Bounds.dwMaximum;
530 }
531 //fill in the volume in the control details structure
532 detailValue.dwValue=newVolume;
533
534
535 mmres = mixerSetControlDetails(handle,&details,MIXER_SETCONTROLDETAILSF_VALUE);
536 mixerClose(handle);
537
538 if(mmres==MMSYSERR_NOERROR) return 1;
539 else return SOUND_PLATFORMERROR;
540
541 }
542 }
543
544
545 mixerClose(handle);
546 }
547
548 }
549
550 return SOUND_PLATFORMERROR;
551 }
552
553 #endif
554
555
556
557
PlatCDDAManagement(void)558 void PlatCDDAManagement(void)
559 {
560 /* does nothing for Win95: use call back instead */
561 }
562
PlatCDDAManagementCallBack(WPARAM flags,LONG deviceId)563 void PlatCDDAManagementCallBack(WPARAM flags, LONG deviceId)
564 {
565 extern CDOPERATIONSTATES CDDAState;
566
567 /* check the cdDeviceId */
568 if(cdDeviceID==NO_DEVICE) return;
569 /* compare with the passed device id */
570 if((UINT)deviceId!=(UINT)cdDeviceID) return;
571
572 if(flags&MCI_NOTIFY_SUCCESSFUL)
573 {
574 CDDAState = CDOp_Idle;
575 //NewOnScreenMessage("CD COMMAND RETURNED WITH SUCCESSFUL");
576 /* Play it again, sam */
577 if (LastCommandGiven == CDCOMMANDID_PlayLoop)
578 {
579 CDDA_PlayLoop(TrackBeingPlayed);
580 }
581 }
582 else if(flags&MCI_NOTIFY_FAILURE)
583 {
584 /* error while playing: abnormal termination */
585 //NewOnScreenMessage("CD COMMAND FAILED");
586 CDDAState = CDOp_Idle;
587 }
588 else if(flags&MCI_NOTIFY_SUPERSEDED)
589 {
590 //NewOnScreenMessage("CD COMMAND SUPERSEDED");
591 }
592 else if(flags&MCI_NOTIFY_ABORTED)
593 {
594 /* aborted or superceeded: try and stop the device */
595 //NewOnScreenMessage("CD COMMAND ABORTED(?)");
596 // CDDA_Stop();
597 }
598 else
599 {
600 //NewOnScreenMessage("CD COMMAND RETURNED WITH UNKNOWN MESSAGE");
601 }
602 }
603