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