/* MODULE DE GESTION DU CD pour WIN95 en mode MCI UBI SOUND STUDIOS Olivier Amiaud */ /***************************************************************************** Prototype de la fonction de gestion d'erreur void SND_fn_vDisplayError(unsigned short uwErrNum,char *message) Liste des erreurs ----------------- E_uwSndCDLoadTrack E_uwSndCDStatus E_uwSndCDSet E_uwSndCDPlay E_uwSndCDStop E_uwSndCDNotifyFailure E_uwSndCDNotifyAborted E_uwSndCDNotifySuperseded E_uwSndCDCreateThread E_uwSndCDClose E_uwSndCDFade ******************************************************************************/ #include #include #include #include #include "SNDinc.h" #include "sndres.h" #include "sndwin95.h" //#include "sndmusct.h" #include "sndCD.h" #if defined(_DLL_COMPILATION_MODE) #include "SNDDLL.h" #endif #include "sndthrd.h" //#include "snderr.h" //#include "sndmem.h" #ifndef DISABLE_CD //#define CD_MCI //---------------------------------- //- Partie concernant le CD mixer - //---------------------------------- static MIXERCAPS mixerCapsCD; static HMIXER hMixerCD; static UINT mixerIdentifierCD; static UINT uiNbrMixersCD; static DWORD dwNbrAudioLinesCD; static MIXERLINE mixerLineCD; static MIXERLINECONTROLS mixerLineControlsCD; static MIXERCONTROL mixerControlCD; static MIXERCONTROLDETAILS mixerControlDetailsCD; static MIXERCONTROLDETAILS_UNSIGNED valeurCD; static BOOL CDControlAvailable = FALSE; //---------------------------------- //- Partie concernant le CD driver - //---------------------------------- #define MSG_ERR_CD "CD Device Error" #define MSG_ERR_CD_FILE "CD File Error" #define MSG_ERR_CD_NOT_READY "CD Not Ready" #define MSG_ERR_BAD_CD_ID_TRACK "Bad CD Track Number" #define SND_CD_NOT_IN_CD_PLAYER 10 #define SND_CD_NOT_THE_GOOD_ONE_AND_NOT_AUDIO 11 #define SND_CD_NOT_THE_GOOD_ONE_BUT_AUDIO 12 #define SND_CD_USED_BY_A_PROGRAM 13 #define FADE_AND_STOP_CD 12 #define NB_MAX_CD_TRACKS 20 #define NB_CD_TRACKS 12 #define OFFSET_CD_VOICE 0x3000 #define MASK_OFFSET_CD_VOICE 0x0FFF #define NO_CD_VOICE 0x127 #define CD_UNAVAILABLE 0x0004 #define CD_STATE_NORMAL 1 #define CD_STATE_USED 2 #define CD_STATE_ALL_TRACKS 3 #define CD_STATE_UNUSED 4 #define TIMER_CD 34 #define VOL_MAX_CD 60 #define SND_MAKE_TMSF(t,m,s,f) ((DWORD)t)|(((DWORD)m)<<8)|(((DWORD)s)<<16)|(((DWORD)f)<<24) #define SND_TMSF_T(tmsf) ((BYTE)(tmsf)) #define SND_TMSF_M(tmsf) ((BYTE)(((WORD)(tmsf)) >> 8)) #define SND_TMSF_S(tmsf) ((BYTE)((tmsf)>>16)) #define SND_TMSF_F(tmsf) ((BYTE)((tmsf)>>24)) #define SND_TMSF_MS(tmsf) \ ((((((((tmsf & 0xff00) >> 8) * 60) + ((tmsf & 0xff0000) >> 16)) * 75) + ((tmsf & 0xff000000)>>24)) * 1000) / 75) // VARIABLES GLOBALES EXTERNES // TYPEDEF LOCAUX // Definition ensemble des pistes du jeu typedef struct _tdstCDTrack { SndBool bLoop; int iNbLoops; DWORD tmsfStartTrack; DWORD tmsfEndTrack; DWORD dwStartingFrame; DWORD dwEndingFrame; DWORD dwStartLoopingFrame; DWORD dwEndLoopingFrame; tduRefRes uCDTrack; } tdstCDTrack; // Definition piste active a l'instant t typedef struct _tdstActiveCDTrack { SndBool bActive; SndBool bPaused; // le CD a été mi sen pause long lPausePos; // Postition physique de la pause SndBool bLoop; int iNbLoops; long lVoice; long lIndexVoice; unsigned long ulTrackLengthInMs; SoundParam * pstSoundParam; long lPrio; SND_td_pfn_vSoundCallback pfnSoundCallback; long lParSoundCallback; } tdstActiveCDTrack; // Definition data necessaire au driver typedef struct _stCDDriver { SndBool bCdDriverOk; SndBool bRequestCdDriver; unsigned char ucState; MCIDEVICEID uiCdDeviceId; long lNbCdTracks; int iLastCDVolume; } tdstCDDriver; // ------------------------------------------- // VARIABLES GLOBALES LOCALES static SndBool bCDFadeIn = FALSE; static UINT uiTimerCDFadeIn;// Gestion du fade-in static unsigned long ulCountDownFadeIn; static unsigned long ulTimerPeriodFadeIn; static long lNbIterFadeIn; static SndBool bCDFadeOut= FALSE; static UINT uiTimerCDFadeOut;// Gestion du fade-out static unsigned long ulCountDownFadeOut; static unsigned long ulTimerPeriodFadeOut; static long lNbIterFadeOut; static unsigned char ucFacteurVolume;// Volume global CD // Pistes CD du jeu et piste active static tdstCDTrack stCDTracks[NB_MAX_CD_TRACKS]; static tdstActiveCDTrack stActiveCDTrack; static tdstCDDriver stCDDriver;// CD driver static int iNbCdTracks; static char texte_erreur[1024]; // ------------------------------------------- // HANDLE ET ID DE THREADS ET FENETRES static HWND hSndCdWnd;// handle de la fenetre de gestion de messages du CD static DWORD dwCDThreadId; static HANDLE hCDThread=NULL; static HANDLE hCDThreadCallBack; static DWORD dwCDThreadIdCallBack; //********************************************************************** BIDOUILLE CD PLAYER // ------------------------------------------- // VARIABLES CONCERNANT LA GESTION DES THREADS UINT SND_PLAYCD_MSG; UINT SND_STOPCD_MSG; UINT SND_LOADCD_MSG; UINT SND_PAUSECD_MSG; UINT SND_RESUMECD_MSG; UINT SND_NEXTTRACKCD_MSG; UINT SND_DESINITCD_MSG; UINT SND_RELEASECD_MSG; UINT SND_RESTORECD_MSG; UINT SND_GETPOSCD_MSG; static DWORD dw_a5_Params[5]; static DWORD dw_a2_threadParams[2]; #endif //DISABLE_CD // ------------------------------------------- // PROTOTYPES DES FONCTIONS LOCALES SndBool SND_fn_bLoadCDTrack(tdstBlockResourceMem * pstPtr,int); SndBool SND_fn_bUnloadCDTrack(int i); SndBool SND_fn_bMediaPresent(void); long SND_fn_lGetActiveCdTrack(void); long SND_fn_lGetCurrentCdMode(void); long SND_fn_lGetCDLength(void); long SND_fn_lGetCdTrack(tdxId Id); long SND_fn_lGetCurrentCdPosition(void); void SND_fn_vCloseCDDoor(void); int SND_fn_iMixerInitCD(void); int SND_fn_iMixerDesInitCD(void); DWORD SND_fn_dwGetCDMax(void); DWORD SND_fn_dwGetCDMin(void); DWORD SND_fn_dwGetCDValue(void); void SND_fn_vSetCDValue(DWORD val); void SND_CALL SND_fn_vReleaseDriverCDThread(); void SND_CALL SND_fn_vRestoreDriverCDThread(); // prototypes des fonctions appelees par le thread int SND_fn_iInitCDThread(); SndBool SND_fn_bLoadCDTrackThread(tdstBlockResourceMem * pstPtr,int numTrack); void SND_fn_vDesInitCDThread(void); long SND_fn_lPlayCDThread(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback); void SND_fn_vStopCDThread(long voice); long SND_fn_lNextCDTrackThread(); void SND_fn_vPauseCDThread(long voice); void SND_fn_vResumeCDThread(long voice); SndReal SND_CALL SND_fn_rGetPosCDThread(long voice); LRESULT CALLBACK SND_fn_vCdMSG(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam); //#ifdef CD_MCI //----------------------------------------------------------- // ConvertRsvDiskToMem // // But : Convertir un BlockResourceDisk en Mem // Entrées : reference au structs ressources mem et disk // Sorties : neant //------------------------------------------------------------ void SND_CALL SND_fn_vConvertResDiskToMemCD(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem,void * ptrBegin) { #ifndef DISABLE_CD HANDLE hEventSynchro; mem->Id=disk->Id; mem->eType=disk->eType; mem->eStorage=disk->eStorage; mem->ucVolume=disk->ucVolume; mem->bIsLoaded=TRUE; //partie spécifique au type de ressource mem->uRes.stCD.bVolable = disk->uRes.stCD.bVolable; mem->uRes.stCD.wTrackId = disk->uRes.stCD.wTrackId; mem->uRes.stCD.bLoop = disk->uRes.stCD.bLoop; mem->uRes.stCD.ulStartingFrame = disk->uRes.stCD.ulStartingFrame; mem->uRes.stCD.ulEndingFrame = disk->uRes.stCD.ulEndingFrame; if (mem->uRes.stCD.bLoop) { mem->uRes.stCD.ulStartLoop = disk->uRes.stCD.ulStartLoop; mem->uRes.stCD.ulEndLoop = disk->uRes.stCD.ulEndLoop; mem->uRes.stCD.iNbLoops = disk->uRes.stCD.iNbLoops; } else { mem->uRes.stCD.ulStartLoop = mem->uRes.stCD.ulEndLoop = 0; mem->uRes.stCD.iNbLoops = 0; } if (stCDDriver.bCdDriverOk) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); dw_a5_Params[0] = (DWORD)mem; dw_a5_Params[1] = (DWORD)iNbCdTracks++; if (!PostThreadMessage(dwCDThreadId,(UINT)SND_LOADCD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDLoadTrack,"PostThreadMessage Load Track"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); } #endif //DISABLE_CD } SndBool SND_CALL SND_fn_bLoadResScriptCd(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem) { #ifndef DISABLE_CD SND_fn_vConvertResDiskToMemCD(disk,mem,NULL); return TRUE; #else //DISABLE_CD return FALSE; #endif //DISABLE_CD } SndBool SND_CALL SND_fn_bLoadResBinaryCd(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem,char *pDataBloc) { #ifndef DISABLE_CD SND_fn_vConvertResDiskToMemCD(disk,mem,NULL); #endif //DISABLE_CD return FALSE; } #ifndef DISABLE_CD //----------------------------------------------------------- // SND_fn_bMediaPresent // // But : Dire si le CD est dans le lecteur // Entrées : neant // Sorties : True,False //------------------------------------------------------------ SndBool SND_fn_bMediaPresent() { MCI_STATUS_PARMS status; MCIERROR mciReturn; // Mode actuel de la piste status.dwItem = MCI_STATUS_MEDIA_PRESENT; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); return (0); } return(status.dwReturn); } //----------------------------------------------------------- // SND_fn_lGetTypeCd(short Id) // // But : Donne le type d'une piste du CDROM // Entrées : Id de la piste a tester // Sorties : Type (MCI_CDA_TRACK_AUDIO ou MCI_CDA_TRACK_OTHER ou 0) //------------------------------------------------------------ long SND_fn_lGetTypeCdTrack(short Id) { MCI_STATUS_PARMS status; MCIERROR mciReturn; // Mode actuel de la piste status.dwItem = MCI_CDA_STATUS_TYPE_TRACK; status.dwTrack = Id; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM|MCI_TRACK,(DWORD)(LPVOID)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); return (0); } return(status.dwReturn); } //----------------------------------------------------------- // SND_fn_lGetNbCdTracks() // // But : Donne le nombre de pistes du CD // Entrées : neant // Sorties : nb pistes //------------------------------------------------------------ long SND_fn_lGetNbCdTracks() { MCI_STATUS_PARMS status; MCIERROR mciReturn; status.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); return (0); } return(status.dwReturn); } //----------------------------------------------------------- // SND_fn_lTimerIn() // // But : Callback de gestion du temps pour les fade-in. // Entrées : neant // Sorties : neant //------------------------------------------------------------ void CALLBACK SND_fn_lCDTimerIn(UINT IDEvent,UINT msg,DWORD par,DWORD dw1,DWORD dw2) { if (!stActiveCDTrack.bPaused && stActiveCDTrack.bActive) if (bCDFadeIn) { if (lNbIterFadeIn--) SND_fn_vSetCDValue(ucFacteurVolume++); else { bCDFadeIn = FALSE; ulCountDownFadeIn = 0; } } } //----------------------------------------------------------- // SND_fn_lTimerOut() // // But : Callback de gestion du temps pour les fade-in. // Entrées : neant // Sorties : neant //------------------------------------------------------------ void CALLBACK SND_fn_lCDTimerOut(UINT IDEvent,UINT msg,DWORD par,DWORD dw1,DWORD dw2) { unsigned long ulRealTime = 0; if (!stActiveCDTrack.bPaused && stActiveCDTrack.bActive) if (bCDFadeOut) { ulCountDownFadeOut += ulTimerPeriodFadeOut; ulRealTime = stActiveCDTrack.ulTrackLengthInMs - lNbIterFadeOut * ulTimerPeriodFadeOut; if (ulCountDownFadeOut > ulRealTime) { SND_fn_vSetCDValue(ucFacteurVolume); if (ucFacteurVolume-- == 0) { bCDFadeOut = FALSE; ulCountDownFadeOut = 0; if (par == FADE_AND_STOP_CD) { SND_fn_vStopCD(0); PostMessage(hSndCdWnd,MM_MCINOTIFY,MCI_NOTIFY_SUCCESSFUL,0); } } } } } //----------------------------------------------------------- // SND_fn_iCdThreadCallBack // // But : Procédure de la thread qui contient la fenetre qui traite les messages MCI // Entrées : void * : paramètre inutilisé // Sorties : void //------------------------------------------------------------ int WINAPI SND_fn_iCDThreadCallBack(long arglist) { long * pArg = (void *)arglist; SND_td_pfn_vSoundCallback pfnCallback = (SND_td_pfn_vSoundCallback)pArg[0]; long lParCallback = pArg[1]; SND_fn_vEnterCriticalSectionThreadSnd(); if (pfnCallback != NULL) (*pfnCallback)(lParCallback); SND_fn_vQuitCriticalSectionThreadSnd(); return (0); } //----------------------------------------------------------- // SND_fn_vCdMSG // // But : Effectuer la gestion des messages du CD // Entrées : Messages et leurs parametres // Sorties : Ok ou Failed //------------------------------------------------------------ LRESULT CALLBACK SND_fn_vCdMSG(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { char texte[256]; long current_mode; SECURITY_ATTRIBUTES sa; switch(message) { case WM_CREATE : break; case WM_COMMAND : break; case WM_TIMER : break; case MM_MCINOTIFY : switch (wParam) { case MCI_NOTIFY_FAILURE: sprintf(texte,"MM_MCINOTIFY FAILURE wpar=%d lpar=%d",wParam,lParam); SND_fn_vDisplayError(E_uwSndCDNotifyFailure,texte); break; case MCI_NOTIFY_ABORTED: //sprintf(texte,"MM_MCINOTIFY ABORTED wpar=%d lpar=%d",wParam,lParam); //SND_fn_vDisplayError(E_uwSndCDNotifyAborted,texte); break; case MCI_NOTIFY_SUPERSEDED: sprintf(texte,"MM_MCINOTIFY SUPERSEDED wpar=%d lpar=%d",wParam,lParam); SND_fn_vDisplayError(E_uwSndCDNotifySuperseded,texte); break; case MCI_NOTIFY_SUCCESSFUL: current_mode = SND_fn_lGetCurrentCdMode(); switch (current_mode) { case MCI_MODE_STOP : if (!stActiveCDTrack.bPaused) { if ((stActiveCDTrack.bLoop)&&(stActiveCDTrack.iNbLoops--)) { SND_fn_lPlayCDThread( stCDTracks[stActiveCDTrack.lVoice].uCDTrack, stActiveCDTrack.pstSoundParam, stActiveCDTrack.lPrio, stActiveCDTrack.pfnSoundCallback, stActiveCDTrack.lParSoundCallback); } else { if (uiTimerCDFadeIn) timeKillEvent(uiTimerCDFadeIn); if (uiTimerCDFadeOut) timeKillEvent(uiTimerCDFadeOut); stActiveCDTrack.bPaused = FALSE; stActiveCDTrack.bActive = FALSE; stActiveCDTrack.bLoop = FALSE; stActiveCDTrack.lVoice = NO_CD_VOICE; stActiveCDTrack.pstSoundParam = NULL; stActiveCDTrack.lPrio = 0; if (stActiveCDTrack.pfnSoundCallback) { sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; dw_a2_threadParams[0] = (DWORD)stActiveCDTrack.pfnSoundCallback; dw_a2_threadParams[1] = (DWORD)stActiveCDTrack.lParSoundCallback; if (!(hCDThreadCallBack = CreateThread(&sa,0,(LPTHREAD_START_ROUTINE)SND_fn_iCDThreadCallBack,(LPVOID)dw_a2_threadParams,0,&dwCDThreadIdCallBack))) SND_fn_vDisplayError(E_uwSndCDCreateThread,""); stActiveCDTrack.pfnSoundCallback = NULL; stActiveCDTrack.lParSoundCallback = 0; } } } break; case MCI_MODE_PAUSE : break; case MCI_MODE_PLAY : break; case MCI_MODE_NOT_READY : break; default : break; } break; } return 0; case WM_DESTROY: if (uiTimerCDFadeIn) timeKillEvent(uiTimerCDFadeIn); if (uiTimerCDFadeOut) timeKillEvent(uiTimerCDFadeOut); PostQuitMessage(0); break; default: return DefWindowProc(hwnd,message,wParam,lParam); } return 0; } //----------------------------------------------------------- // SND_fn_iErreurInit // // But : Initialisation de la fenetre de dialogue // des erreurs a l'init du driver Midi // Entrées : constantes numero d'erreur // Sorties : code de retour de la boite de dialogue //------------------------------------------------------------ /* int SND_CALL SND_fn_iErreurInitCD() { int ret; ret=Erm_fn_iMessageBox(hwndMainSnd,"Insert a CD or\nClose the application using your CD and try again ...\nelse you'll not be able to hear any music","CD-Driver Problem",MB_ABORTRETRYIGNORE|MB_TOPMOST); switch (ret) { case IDABORT: return INIT_FAILED; case IDIGNORE: return INIT_IGNORE; case IDRETRY: return INIT_RETRY; default: return INIT_IGNORE; } } */ //----------------------------------------------------------- // SND_fn_iCdThreadProc // // But : Procédure de la thread qui contient la fenetre qui traite les messages MCI // Entrées : void * : paramètre inutilisé // Sorties : void //------------------------------------------------------------ int __stdcall SND_fn_iCDThreadProc(HANDLE arglist) { MSG msg; WNDCLASS wcCdWndClass; DWORD * pdwParams; PeekMessage(&msg,NULL,0,0,PM_NOREMOVE); if (SND_fn_iInitCDThread() == C_INIT_FAILED) { stCDDriver.bCdDriverOk = FALSE; stCDDriver.ucState = CD_STATE_USED; ExitThread(C_INIT_FAILED); } //definit la window-classe wcCdWndClass.hInstance = SND_hGlobalInst; wcCdWndClass.lpszClassName = "SoundAcpCd"; wcCdWndClass.lpfnWndProc = SND_fn_vCdMSG;//fonction associée à la fonction wcCdWndClass.style=0; wcCdWndClass.hIcon=0; wcCdWndClass.hCursor=0; wcCdWndClass.lpszMenuName='\0'; wcCdWndClass.cbClsExtra=0; wcCdWndClass.cbWndExtra=0; wcCdWndClass.hbrBackground=0; //enregistrement de la classe CdWnd if (!RegisterClass(&wcCdWndClass)) SND_fn_vDisplayError(E_uwSndCDRegisterWndClass,""); SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL); //création de la fenetre cd hSndCdWnd = CreateWindow(wcCdWndClass.lpszClassName,"CdWindow",WS_OVERLAPPEDWINDOW,0,0,0,0,HWND_DESKTOP,NULL,SND_hGlobalInst,NULL); // synchro d'initialisation du thread et de la pompe a messages quand tout c'est bien passé SetEvent(arglist); while (GetMessage(&msg,NULL,0,0)) { if (msg.message == SND_PLAYCD_MSG) { pdwParams = (DWORD *)msg.wParam; pdwParams[0] = SND_fn_lPlayCDThread(*(tduRefRes *)pdwParams[0],(SoundParam *)pdwParams[1],(long)pdwParams[2] ,(SND_td_pfn_vSoundCallback)pdwParams[3] ,(long)pdwParams[4] ); // on debloque le thread appelant SetEvent((HANDLE)msg.lParam); } else if (msg.message == SND_STOPCD_MSG) { pdwParams = (DWORD *)msg.wParam; SND_fn_vStopCDThread((long)pdwParams[0]); // on debloque le thread appelant SetEvent((HANDLE)msg.lParam); } else if (msg.message == SND_LOADCD_MSG) { pdwParams = (DWORD *)msg.wParam; pdwParams[0] = SND_fn_bLoadCDTrackThread((tdstBlockResourceMem *)pdwParams[0],(int)pdwParams[1]); // on debloque le thread appelant SetEvent((HANDLE)msg.lParam); } else if (msg.message == SND_PAUSECD_MSG) { pdwParams = (DWORD *)msg.wParam; SND_fn_vPauseCDThread((long)pdwParams[0]); SetEvent((HANDLE)msg.lParam); } else if (msg.message == SND_RESUMECD_MSG) { pdwParams = (DWORD *)msg.wParam; SND_fn_vResumeCDThread((long)pdwParams[0]); SetEvent((HANDLE)msg.lParam); } else if (msg.message == SND_NEXTTRACKCD_MSG) { pdwParams = (DWORD *)msg.wParam; pdwParams[0] = SND_fn_lNextCDTrackThread(); // on debloque le thread appelant SetEvent((HANDLE)msg.lParam); } else if (msg.message == SND_DESINITCD_MSG) { SND_fn_vDesInitCDThread(); SetEvent((HANDLE)msg.lParam); ExitThread(0); } else if (msg.message == SND_RELEASECD_MSG) { SND_fn_vReleaseDriverCDThread(); SetEvent((HANDLE)msg.lParam); } else if (msg.message == SND_RESTORECD_MSG) { SND_fn_vRestoreDriverCDThread(); SetEvent((HANDLE)msg.lParam); } if (msg.message == SND_GETPOSCD_MSG) { pdwParams = (DWORD *)msg.wParam; pdwParams[0] = (DWORD) SND_fn_rGetPosCDThread((long)pdwParams[0]); // on debloque le thread appelant SetEvent((HANDLE)msg.lParam); } else { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0; } #endif //DISABLE_CD //----------------------------------------------------------- // SND_fn_iInitCd // // But : Realiser l'init bas niveau du driver midi // Entrées : neant // Sorties : C_INIT_OK ou C_INIT_FAILED //------------------------------------------------------------ int SND_CALL SND_fn_iInitCD(SND_tdstInitStruct *pInitStruct) { #ifndef DISABLE_CD DWORD dwExitCode = 0; HANDLE hEventSynchro; HANDLE hHandlesForWait[2]; SECURITY_ATTRIBUTES sa; #if defined(_DLL_COMPILATION_MODE) SND_DllInitEntryPoints_StaticFunctions((HMODULE)pInitStruct->hProcessInstance ); #endif stCDDriver.bCdDriverOk = CD_UNAVAILABLE; uiTimerCDFadeIn = uiTimerCDFadeOut = 0; // Init toutes pistes CD //init de hwndSnd et hinst ,et SND_hResourceHandle: hwndMainSnd=pInitStruct->hMainWindow; SND_hGlobalInst=pInitStruct->hProcessInstance; if (SND_g_hResourceHandle==NULL) SND_g_hResourceHandle=SND_hGlobalInst; // on init les points d'entree fonctions externes DLL #ifdef _DLL_COMPILATION_MODE SND_DllInitEntryPoints_StaticFunctions((HMODULE)SND_hGlobalInst); #endif // on enregistre les differents types de messages recus par le thread SND_PLAYCD_MSG = RegisterWindowMessage("PlayCd"); SND_STOPCD_MSG = RegisterWindowMessage("StopCd"); SND_LOADCD_MSG = RegisterWindowMessage("LoadCd"); SND_PAUSECD_MSG = RegisterWindowMessage("PauseCd"); SND_RESUMECD_MSG = RegisterWindowMessage("ResumeCd"); SND_NEXTTRACKCD_MSG = RegisterWindowMessage("NextTrackCd"); SND_DESINITCD_MSG = RegisterWindowMessage("DesinitCd"); SND_RELEASECD_MSG = RegisterWindowMessage("ReleaseCd"); SND_RESTORECD_MSG = RegisterWindowMessage("RestoreCd"); SND_GETPOSCD_MSG = RegisterWindowMessage("GetPosCd"); // on cree le thread de gestion CD l'ID du thread est dwCDThreadId sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); while (TRUE) { if (!(hCDThread = CreateThread(&sa,0,(LPTHREAD_START_ROUTINE)SND_fn_iCDThreadProc,hEventSynchro,0,&dwCDThreadId))) { SND_fn_vDisplayError(E_uwSndCDCreateThread,""); return C_INIT_FAILED; } else { hHandlesForWait[0] = hEventSynchro; hHandlesForWait[1] = hCDThread; // on attend la synchronisation d'init., l'attente se termine quand un des deux events arrive WaitForMultipleObjects(2,hHandlesForWait,FALSE,INFINITE); GetExitCodeThread(hCDThread,&dwExitCode); if (dwExitCode == STILL_ACTIVE) { stCDDriver.bCdDriverOk = TRUE; CloseHandle(hEventSynchro); return C_INIT_OK; } else { if (dwExitCode == C_INIT_FAILED) { CloseHandle(hCDThread); hCDThread=NULL; switch (SND_fn_iErreurInit(0)) { case INIT_IGNORE: // on joue sans CD CloseHandle(hEventSynchro); return C_INIT_FAILED; case INIT_RETRY: // on reinit jusqu'a appli utilisatrice libere driver break; case INIT_FAILED: // on sort du program stCDDriver.bCdDriverOk = FALSE; CloseHandle(hEventSynchro); exit(0); } } } } } return C_INIT_OK; #else return C_INIT_FAILED; #endif //DISABLE_CD } #ifndef DISABLE_CD //----------------------------------------------------------- // SND_fn_iInitCdThread // // But : Realiser l'init bas niveau du driver midi // Entrées : neant // Sorties : C_INIT_OK ou C_INIT_FAILED //------------------------------------------------------------ int SND_fn_iInitCDThread() { int i; MCI_OPEN_PARMS open; MCI_SET_PARMS set; MCIERROR mciReturn; MCI_SYSINFO_PARMS sysinfo; long lOpeningMode = 0; stCDDriver.bCdDriverOk = CD_UNAVAILABLE; uiTimerCDFadeIn = uiTimerCDFadeOut = 0; // Init toutes pistes CD for (i=0;iId != Id) && (++i < NB_MAX_CD_TRACKS)); if ((i == NB_MAX_CD_TRACKS) || ((!i)&&(!stCDTracks[i].uCDTrack.pstPtr))) return (NO_CD_VOICE); else return (i); } //----------------------------------------------------------- // SND_fn_lGetActiveTrack // // But : Renvoie la voie active // Entrées : neant // Sorties : voie bas niveau active, NO_CD_VOICE sinon //------------------------------------------------------------ long SND_fn_lGetActiveCdTrack() { return (stActiveCDTrack.lVoice); } //----------------------------------------------------------- // SND_fn_lGetCurrentMode // // But : Renvoie la callback midi // Entrées : neant // Sorties : Mode du device correspondant a la voie //------------------------------------------------------------ long SND_fn_lGetCurrentCdMode() { MCI_STATUS_PARMS status; MCIERROR mciReturn; if (stCDDriver.bCdDriverOk) { // Mode actuel de la piste status.dwItem = MCI_STATUS_MODE; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); return (0); } return(status.dwReturn); } else return (0); } //----------------------------------------------------------- // SND_fn_lGetCDLength // // But : Renvoie la longueur totale d'un CD // Entrées : neant // Sorties : longueur totale du CD //------------------------------------------------------------ long SND_fn_lGetCDLength() { MCI_STATUS_PARMS status; MCIERROR mciReturn; if (stCDDriver.bCdDriverOk) { // Mode actuel de la piste status.dwItem = MCI_STATUS_LENGTH; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); return (0); } return(status.dwReturn); } else return (0); } //----------------------------------------------------------- // SND_fn_l_GetCurrentPosition // // But : Renvoie la position courante de lecture // de la voie active // Entrées : neant // Sorties : position en millisecondes //------------------------------------------------------------ long SND_fn_lGetCurrentCdPosition() { MCI_STATUS_PARMS status; MCIERROR mciReturn; // Mode actuel de la piste status.dwItem = MCI_STATUS_MODE; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); return (0); } if ((status.dwReturn == MCI_MODE_PLAY)||(status.dwReturn == MCI_MODE_STOP)) { // Si la piste est en mode play ou en pause status.dwItem = MCI_STATUS_POSITION; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); return (0); } return (status.dwReturn); } else return (0); } //----------------------------------------------------------- // SND_ulGetCDTrackLengthInMs // // But : Calcule la duree exacte de la piste en millisecondes // Entrées : La voie active // Sorties : La position en tmsf //------------------------ unsigned long SND_fn_ulGetCDTrackLengthInMs(unsigned long ulVoice) { unsigned long ulTrackLength = 0, debut = 0, fin = 0, ulRealLength; unsigned long debutLoop = 0, finLoop = 0; debut = SND_TMSF_MS(stCDTracks[ulVoice].dwStartingFrame); fin = SND_TMSF_MS(stCDTracks[ulVoice].dwEndingFrame); debutLoop = SND_TMSF_MS(stCDTracks[ulVoice].dwStartLoopingFrame); finLoop = SND_TMSF_MS(stCDTracks[ulVoice].dwEndLoopingFrame); ulTrackLength = SND_TMSF_MS(stCDTracks[ulVoice].tmsfEndTrack); if (fin) if (debut) ulRealLength = fin - debut; else ulRealLength = fin; else if (debut) ulRealLength = ulTrackLength - debut; else ulRealLength = ulTrackLength; if (stActiveCDTrack.bLoop && stActiveCDTrack.iNbLoops > 0) { if (debutLoop && finLoop) ulRealLength += (stActiveCDTrack.iNbLoops) * (finLoop - debutLoop); else if (debutLoop) ulRealLength += (stActiveCDTrack.iNbLoops) * (fin - debutLoop); else ulRealLength += (stActiveCDTrack.iNbLoops) * (finLoop - debut); } return (ulRealLength); } //----------------------------------------------------------- // SND_fn_ulInitFadeCD // // But : Initialise les variables de fading // Entrées : // Sorties : //------------------------ void SND_fn_ulInitFadeCD( unsigned long ulFadeInDuration, unsigned long ulFadeOutDuration) { lNbIterFadeIn = VOL_MAX_CD; lNbIterFadeOut = VOL_MAX_CD; if (ulFadeInDuration+ulFadeOutDuration < stActiveCDTrack.ulTrackLengthInMs) { bCDFadeIn = (SndBool)ulFadeInDuration; bCDFadeOut = (SndBool)ulFadeOutDuration; if (bCDFadeIn) { ulTimerPeriodFadeIn = ulFadeInDuration / lNbIterFadeIn; ulCountDownFadeIn = 0; ucFacteurVolume = 0; // init du timer cross-fade uiTimerCDFadeIn = timeSetEvent(ulTimerPeriodFadeIn,10,(LPTIMECALLBACK)SND_fn_lCDTimerIn,(DWORD)0,TIME_PERIODIC); } if (bCDFadeOut) { ulTimerPeriodFadeOut = ulFadeOutDuration / lNbIterFadeIn; ulCountDownFadeOut = 0; if (!bCDFadeIn) { ucFacteurVolume = VOL_MAX_CD; } // init du timer cross-fade uiTimerCDFadeOut = timeSetEvent(ulTimerPeriodFadeOut,10,(LPTIMECALLBACK)SND_fn_lCDTimerOut,(DWORD)0,TIME_PERIODIC); } SND_fn_vSetCDValue(ucFacteurVolume); } else { SND_fn_vSetCDValue(VOL_MAX_CD); SND_fn_vDisplayError(E_uwSndCDFade,"Bad Fading Parameters"); } } //----------------------------------------------------------- // SND_fn_dwCalculateFrom // // But : Calcule le point de depart du play // Entrées : La voie active // Sorties : La position en tmsf //------------------------------------------------------------ DWORD SND_fn_dwCalculateFrom(long lVoice) { DWORD dwFrom = 0; tdstCDTrack * pstActiveCDTrack = &stCDTracks[lVoice]; // ce n'est pas le premier tour de boucle if (stActiveCDTrack.iNbLoops < pstActiveCDTrack->iNbLoops) { // le debut de boucle est different de zero if (pstActiveCDTrack->dwStartLoopingFrame) dwFrom = pstActiveCDTrack->dwStartLoopingFrame; else // le debut de boucle est egal a zero if (pstActiveCDTrack->dwStartingFrame) dwFrom = pstActiveCDTrack->dwStartingFrame; } else // premier tour if (pstActiveCDTrack->dwStartingFrame) dwFrom = pstActiveCDTrack->dwStartingFrame; dwFrom |= pstActiveCDTrack->tmsfStartTrack; return dwFrom; } //----------------------------------------------------------- // SND_fn_dwCalculateTo // // But : // But : Calcule le point de fin du play // Entrées : La voie active // Sorties : La position en tmsf //------------------------------------------------------------ DWORD SND_fn_dwCalculateTo(long lVoice) { DWORD dwTo = 0; tdstCDTrack * pstActiveCDTrack = &stCDTracks[lVoice]; // cas du dernier tour de boucle, l'indice est a zero if (!stActiveCDTrack.iNbLoops) { // on finit la lecture soit sur la fin de trame, soit sur la fin de piste if (pstActiveCDTrack->dwEndingFrame) dwTo = pstActiveCDTrack->dwEndingFrame; else dwTo = pstActiveCDTrack->tmsfEndTrack; } else // cas des n-1 premiers tours, on boucle sur la fin de bouclage if (pstActiveCDTrack->dwEndLoopingFrame) dwTo = pstActiveCDTrack->dwEndLoopingFrame; else // pas de fin de bouclage, on boucle sur la fin de trame ou de piste if (pstActiveCDTrack->dwEndingFrame) dwTo = pstActiveCDTrack->dwEndingFrame; else dwTo = pstActiveCDTrack->tmsfEndTrack; dwTo |= pstActiveCDTrack->tmsfStartTrack; return dwTo; } #endif //DISABLE_CD //----------------------------------------------------------- // SND_fn_lPlayCD // // But : Joue la ressource CD res // Entrées : La ressource, parametres son, la priorite et // la callback // Sorties : voie allouee pour jouee la ressource //------------------------------------------------------------ long SND_CALL SND_fn_lPlayCD(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback) { #ifndef DISABLE_CD HANDLE hEventSynchro; if (stCDDriver.bCdDriverOk) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); dw_a5_Params[0] = (DWORD)&res; dw_a5_Params[1] = (DWORD)par; dw_a5_Params[2] = (DWORD)prio; dw_a5_Params[3] = (DWORD)fn_callback; dw_a5_Params[4] = (DWORD)par_callback; if (!PostThreadMessage(dwCDThreadId,(UINT)SND_PLAYCD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDPlay,"PostThreadMessage"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); // dans ce cas, on retourne le numero de voie dans dw_a5_Params[0] return (dw_a5_Params[0] | OFFSET_CD_VOICE); } else #endif //DISABLE_CD return (C_PLAY_FAILED); } #ifndef DISABLE_CD //----------------------------------------------------------- // SND_fn_lPlayCD // // But : Joue la ressource CD res // Entrées : La ressource, parametres son, la priorite et // la callback // Sorties : voie allouee pour jouee la ressource //------------------------------------------------------------ long SND_fn_lPlayCDThread(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback) { MCIERROR mciReturn; long lVoice = 0,lIndexVoice; MCI_PLAY_PARMS play; if (stCDDriver.bCdDriverOk) { // ceci correspond au premier play d'une piste bouclante if (stActiveCDTrack.lVoice == NO_CD_VOICE) { lVoice = SND_fn_lGetCdTrack(res.pstPtr->Id); debut: lIndexVoice = SND_fn_lGetCdTrack(res.pstPtr->Id); // on recharge la ressource au cas ou elle aurait ete modifiée par l'editeur if (!SND_fn_bLoadCDTrackThread(res.pstPtr,lIndexVoice)) return (C_PLAY_FAILED); stActiveCDTrack.bLoop = stCDTracks[lIndexVoice].bLoop; stActiveCDTrack.iNbLoops = stCDTracks[lIndexVoice].iNbLoops; stActiveCDTrack.lIndexVoice = lIndexVoice; stActiveCDTrack.lVoice = lVoice; stActiveCDTrack.bActive = TRUE; stActiveCDTrack.bPaused = FALSE; stActiveCDTrack.lPrio = prio; stActiveCDTrack.pstSoundParam = par; stActiveCDTrack.pfnSoundCallback=fn_callback; stActiveCDTrack.lParSoundCallback=par_callback; stActiveCDTrack.ulTrackLengthInMs = SND_fn_ulGetCDTrackLengthInMs(lIndexVoice); } else { // on a un ressource bouclante qui en est a son deuxieme tout minimum if ((stActiveCDTrack.bActive && stActiveCDTrack.bLoop)&& (stActiveCDTrack.iNbLoops != stCDTracks[stActiveCDTrack.lIndexVoice].iNbLoops)) lVoice = stActiveCDTrack.lVoice; // on a une ressource pas bouclante mais il y a eu un play sans stop de la ressource precedente else { // on doit reallouer la meme voix pour la ressource suivante lVoice = stActiveCDTrack.lVoice; SND_fn_vStopCDThread(stActiveCDTrack.lVoice); goto debut; } } play.dwCallback = (DWORD)hSndCdWnd; if (stCDDriver.ucState == CD_STATE_ALL_TRACKS) { if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_PLAY,MCI_NOTIFY,(DWORD)(LPVOID)&play)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDPlay,texte_erreur); return (C_PLAY_FAILED); } } else { play.dwFrom = SND_fn_dwCalculateFrom(stActiveCDTrack.lIndexVoice); play.dwTo = SND_fn_dwCalculateTo(stActiveCDTrack.lIndexVoice); if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_PLAY,MCI_FROM|MCI_TO|MCI_NOTIFY,(DWORD)(LPVOID)&play)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDPlay,texte_erreur); return (C_PLAY_FAILED); } } return (lVoice | OFFSET_CD_VOICE); } else return (C_PLAY_FAILED); } //----------------------------------------------------------- // SND_fn_lPlayCDWithFade // // But : Joue la ressource CD res avec un fade // Entrées : La ressource, parametres son, la priorite et // la callback // Sorties : voie allouee pour jouee la ressource //------------------------------------------------------------ long SND_CALL SND_fn_lPlayCDWithFade(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback,unsigned long ulFadeIn,unsigned long ulFadeOut) { long result; result = SND_fn_lPlayCD(res,par,prio,fn_callback,par_callback); SND_fn_ulInitFadeCD(ulFadeIn,ulFadeOut); return (result); } #endif //DISABLE_CD //----------------------------------------------------------- // SND_fn_vStopCd // // But : Stopper une voie // Entrées : la voie a stopper // Sorties : neant //------------------------------------------------------------ void SND_CALL SND_fn_vStopCD(long voice) { #ifndef DISABLE_CD HANDLE hEventSynchro; dw_a5_Params[0] = (DWORD)voice; if (stCDDriver.bCdDriverOk) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); if (!PostThreadMessage(dwCDThreadId,(UINT)SND_STOPCD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDStop,"PostThreadMessage Resume"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); } #endif //DISABLE_CD } #ifndef DISABLE_CD //----------------------------------------------------------- // SND_fn_vStopCdThread // // But : Stopper une voie // Entrées : la voie a stopper // Sorties : neant //------------------------------------------------------------ void SND_fn_vStopCDThread(long voice) { MCIERROR mciReturn; MCI_GENERIC_PARMS stop; SECURITY_ATTRIBUTES sa; long lRealVoice = voice & MASK_OFFSET_CD_VOICE; if ((stCDDriver.bCdDriverOk) && (lRealVoice < NB_MAX_CD_TRACKS)) { stop.dwCallback = (DWORD)hSndCdWnd; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STOP,MCI_WAIT,(DWORD)NULL)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStop,texte_erreur); } sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; dw_a2_threadParams[0] = (DWORD)stActiveCDTrack.pfnSoundCallback; dw_a2_threadParams[1] = (DWORD)stActiveCDTrack.lParSoundCallback; if (!(hCDThreadCallBack = CreateThread(&sa,0,(LPTHREAD_START_ROUTINE)SND_fn_iCDThreadCallBack,(LPVOID)dw_a2_threadParams,0,&dwCDThreadIdCallBack))) SND_fn_vDisplayError(E_uwSndCDCreateThread,""); // Desinit piste CD active stActiveCDTrack.bPaused = FALSE; stActiveCDTrack.bActive = FALSE; stActiveCDTrack.bLoop = FALSE; stActiveCDTrack.lVoice = NO_CD_VOICE; stActiveCDTrack.pstSoundParam = NULL; stActiveCDTrack.lPrio = 0; } } //----------------------------------------------------------- // SND_fn_vStopCdWithFade // // But : Stopper une voie en faisant un fade // Entrées : la voie a stopper // Sorties : neant //------------------------------------------------------------ void SND_CALL SND_fn_vStopCDWithFade(long voice,unsigned long ulFadeOutDuration) { lNbIterFadeOut = SND_fn_dwGetCDValue(); bCDFadeOut = (SndBool)ulFadeOutDuration; if (lNbIterFadeOut) ulTimerPeriodFadeOut = ulFadeOutDuration / lNbIterFadeOut; else ulTimerPeriodFadeOut = 100; ulCountDownFadeOut = 0; // Si le timer etait deja programme pour un fade out alors, on le reprogramme // on passe un parametre special pour la callback FADE_AND_STOP_CD if (uiTimerCDFadeOut != 0) timeKillEvent(uiTimerCDFadeOut); uiTimerCDFadeOut = timeSetEvent(ulTimerPeriodFadeOut,10,(LPTIMECALLBACK)SND_fn_lCDTimerOut,(DWORD)FADE_AND_STOP_CD,TIME_PERIODIC); stActiveCDTrack.ulTrackLengthInMs = ulFadeOutDuration; } #endif //DISABLE_CD //----------------------------------------------------------- // SND_fn_vPauseCd // // But : Pauser une voie // Entrées : la voie a pauser // Sorties : true,false //------------------------------------------------------------ void SND_CALL SND_fn_vPauseCD(long voice) { #ifndef DISABLE_CD HANDLE hEventSynchro; dw_a5_Params[0] = (DWORD)voice; if (stCDDriver.bCdDriverOk) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); if (!PostThreadMessage(dwCDThreadId,(UINT)SND_PAUSECD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDPlay,"PostThreadMessage Pause"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); } #endif //DISABLE_CD } #ifndef DISABLE_CD //----------------------------------------------------------- // SND_fn_vPauseCdThread // // But : Pauser une voie // Entrées : la voie a pauser // Sorties : true,false //------------------------------------------------------------ void SND_fn_vPauseCDThread(long voice) { MCIERROR mciReturn; MCI_GENERIC_PARMS pause; if (stCDDriver.bCdDriverOk) { pause.dwCallback = (DWORD)hSndCdWnd; // if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STOP,MCI_NOTIFY,(DWORD)&pause)) // on sauve la position avant la pause stActiveCDTrack.lPausePos = SND_fn_lGetCurrentCdPosition(); if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_PAUSE,MCI_WAIT,(DWORD)&pause)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStop,texte_erreur); return; } stActiveCDTrack.bPaused = TRUE; } } #endif //DISABLE_CD //----------------------------------------------------------- // SND_fn_vResumeCd // // But : Resumer une voie // Entrées : la voie a resumer // Sorties : True,false //------------------------------------------------------------ void SND_CALL SND_fn_vResumeCD(long voice) { #ifndef DISABLE_CD HANDLE hEventSynchro; dw_a5_Params[0] = (DWORD)voice; if (stCDDriver.bCdDriverOk) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); if (!PostThreadMessage(dwCDThreadId,(UINT)SND_RESUMECD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDPlay,"PostThreadMessage Resume"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); } #endif //DISABLE_CD } #ifndef DISABLE_CD //----------------------------------------------------------- // SND_fn_vResumeCd // // But : Resumer une voie // Entrées : la voie a resumer // Sorties : True,false //------------------------------------------------------------ void SND_fn_vResumeCDThread(long voice) { MCIERROR mciReturn; MCI_PLAY_PARMS playresume; if (stCDDriver.bCdDriverOk) { playresume.dwCallback = (DWORD)hSndCdWnd; if (stActiveCDTrack.bPaused) if (stCDDriver.ucState == CD_STATE_ALL_TRACKS) { if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_PLAY,MCI_NOTIFY,(DWORD)(LPVOID)&playresume)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDPlay,texte_erreur); return; } } else { playresume.dwTo = SND_fn_dwCalculateTo(stActiveCDTrack.lVoice); // on restaure la position sauve lors du pause playresume.dwFrom = stActiveCDTrack.lPausePos; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_PLAY,MCI_FROM|MCI_TO|MCI_NOTIFY,(DWORD)(LPVOID)&playresume)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDPlay,texte_erreur); return; } /* if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_RESUME,MCI_NOTIFY,(DWORD)(LPVOID)&playresume)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDPlay,texte_erreur); }*/ } stActiveCDTrack.bPaused = FALSE; } } //----------------------------------------------------------- // SND_fn_vNextCDTrack // // But : passe a la voie suivante // Entrées : neant // Sorties : Id de la track suivante //------------------------------------------------------------ long SND_CALL SND_fn_lNextCDTrack() { HANDLE hEventSynchro; if (stCDDriver.bCdDriverOk) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); if (!PostThreadMessage(dwCDThreadId,(UINT)SND_NEXTTRACKCD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDPlay,"PostThreadMessage"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); // dans ce cas, on retourne le numero de voie dans dw_a5_Params[0] return (dw_a5_Params[0]); } else return (0); } //----------------------------------------------------------- // SND_fn_vNextCDTrack // // But : passe a la voie suivante // Entrées : neant // Sorties : Id de la track suivante //------------------------------------------------------------ long SND_fn_lNextCDTrackThread() { MCIERROR mciReturn; MCI_SEEK_PARMS seek; MCI_STATUS_PARMS status; MCI_PLAY_PARMS play; DWORD dwTrackNumber; if (stCDDriver.bCdDriverOk) { status.dwItem = MCI_STATUS_CURRENT_TRACK; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); return (0L); } seek.dwCallback = (DWORD)hSndCdWnd; dwTrackNumber = (status.dwReturn+1) % SND_fn_lGetNbCdTracks(); seek.dwTo = MCI_MAKE_TMSF(dwTrackNumber,0,0,0); if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_SEEK,MCI_TO|MCI_NOTIFY,(DWORD)&seek)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDSeek,texte_erreur); return (0L); } play.dwCallback = (DWORD)hSndCdWnd; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_PLAY,MCI_NOTIFY,(DWORD)&play)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDPlay,texte_erreur); return (0L); } return (dwTrackNumber); } else return (0L); } //----------------------------------------------------------- // SND_fn_bLoadCdTrack // // But : Charge une ressource CD, a partir du block ressource // au depart ou lorsqu'elle est modifiée // Entrées : Le block ressource et le nom du fichier midi // Sorties : true,false //------------------------------------------------------------ SndBool SND_fn_bLoadCDTrack(tdstBlockResourceMem * pstPtr,int numTrack) { HANDLE hEventSynchro; if (stCDDriver.bCdDriverOk) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); dw_a5_Params[0] = (DWORD)pstPtr; dw_a5_Params[1] = (DWORD)numTrack; if (!PostThreadMessage(dwCDThreadId,(UINT)SND_LOADCD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDLoadTrack,"PostThreadMessage"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); // dans ce cas, on retourne le numero de voie dans dw_a5_Params[0] return (dw_a5_Params[0]); } else return (FALSE); } //----------------------------------------------------------- // SND_fn_bLoadCdTrackThread // // But : Charge une ressource CD, a partir du block ressource // au depart ou lorsqu'elle est modifiée // Entrées : Le block ressource et le nom du fichier midi // Sorties : true,false //------------------------------------------------------------ SndBool SND_fn_bLoadCDTrackThread(tdstBlockResourceMem * pstPtr,int numTrack) { MCI_STATUS_PARMS status; MCIERROR mciReturn; DWORD dwS,dwSL,dwFL,dwF; status.dwTrack = pstPtr->uRes.stCD.wTrackId; if (stCDDriver.lNbCdTracks >= (long)status.dwTrack) { //----------------------------------------------------------------- // Calcul du debut et de la fin de la piste stockes dans stCDTrack //----------------------------------------------------------------- stCDTracks[numTrack].tmsfStartTrack = SND_MAKE_TMSF(status.dwTrack,0,0,0); status.dwCallback = status.dwReturn = 0; status.dwItem = MCI_STATUS_LENGTH; if (mciReturn=mciSendCommand(stCDDriver.uiCdDeviceId,MCI_STATUS,MCI_STATUS_ITEM|MCI_TRACK,(DWORD) (LPMCI_STATUS_PARMS)&status)) { mciGetErrorString(mciReturn,texte_erreur,sizeof(texte_erreur)); SND_fn_vDisplayError(E_uwSndCDStatus,texte_erreur); } else stCDTracks[numTrack].tmsfEndTrack = status.dwReturn << 8 | status.dwTrack; //----------------------------------------------------------------- // Sauvegarde des bornes du play global //----------------------------------------------------------------- if (pstPtr->uRes.stCD.ulStartingFrame) stCDTracks[numTrack].dwStartingFrame = pstPtr->uRes.stCD.ulStartingFrame | stCDTracks[numTrack].tmsfStartTrack; else stCDTracks[numTrack].dwStartingFrame = stCDTracks[numTrack].tmsfStartTrack; if (pstPtr->uRes.stCD.ulEndingFrame) stCDTracks[numTrack].dwEndingFrame = pstPtr->uRes.stCD.ulEndingFrame | stCDTracks[numTrack].tmsfStartTrack; else stCDTracks[numTrack].dwEndingFrame = stCDTracks[numTrack].tmsfEndTrack; stCDTracks[numTrack].dwStartLoopingFrame = pstPtr->uRes.stCD.ulStartLoop | stCDTracks[numTrack].tmsfStartTrack; stCDTracks[numTrack].dwEndLoopingFrame = pstPtr->uRes.stCD.ulEndLoop | stCDTracks[numTrack].tmsfStartTrack; dwS = SND_TMSF_MS(stCDTracks[numTrack].dwStartingFrame); dwSL = SND_TMSF_MS(stCDTracks[numTrack].dwStartLoopingFrame); dwFL = SND_TMSF_MS(stCDTracks[numTrack].dwEndLoopingFrame); dwF = SND_TMSF_MS(stCDTracks[numTrack].dwEndingFrame); if ((dwSL < dwS)||(dwSL > dwFL)) stCDTracks[numTrack].dwStartLoopingFrame = 0; if ((dwFL < dwSL)||(dwFL > dwF)) stCDTracks[numTrack].dwEndLoopingFrame = 0; //----------------------------------------------------------------- // Sauvegarde des parametres utiles a la gestion de la piste active //----------------------------------------------------------------- // on sauve une reference a la ressource dans la liste des piste midi stCDTracks[numTrack].uCDTrack.pstPtr = pstPtr; stCDTracks[numTrack].bLoop = pstPtr->uRes.stCD.bLoop; stCDTracks[numTrack].iNbLoops = pstPtr->uRes.stCD.iNbLoops; return TRUE; } else { //SND_fn_vDisplayError(E_uwSndCDNbTracks,MSG_ERR_BAD_CD_ID_TRACK); return FALSE; } } //----------------------------------------------------------- // SND_fn_bUnloadCdTrack // // But : Decharge une piste midi, a partir de la voie // Entrées : La voie a decharger // Sorties : true,false //------------------------------------------------------------ SndBool SND_fn_bUnloadCDTrack(int i) { return TRUE; } #endif //DISABLE_CD //#endif //CD_MCI //waitforsingleobject //----------------------------------------------------------- //----------------------------------------------------------- //----------------------------------------------------------- //----------------------------------------------------------- //----------------------------------------------------------- // GESTION DU MIXER CD //----------------------------------------------------------- //----------------------------------------------------------- //----------------------------------------------------------- //----------------------------------------------------------- //----------------------------------------------------------- int SND_fn_iMixerInitCD() { #ifndef DISABLE_CD uiNbrMixersCD = mixerGetNumDevs(); //OK if (uiNbrMixersCD == 0) { SND_fn_vDisplayError(E_uwSndMixerNoMixer,""); return 1; } if(mixerGetID((HMIXEROBJ)0,&mixerIdentifierCD,MIXER_OBJECTF_MIXER) !=MMSYSERR_NOERROR) { SND_fn_vDisplayError(E_uwSndMixerNoId,""); return 1; } if(mixerOpen(&hMixerCD,mixerIdentifierCD,0,0,MIXER_OBJECTF_MIXER/* MIXER_OBJECTF_HWAVEOUT*/) != MMSYSERR_NOERROR) { SND_fn_vDisplayError(E_uwSndMixerOpen,""); return 1; } if(mixerGetDevCaps((UINT)hMixerCD,&mixerCapsCD,sizeof(MIXERCAPS)) != MMSYSERR_NOERROR) { SND_fn_vDisplayError(E_uwSndMixerCapacities,""); return 1; } dwNbrAudioLinesCD = mixerCapsCD.cDestinations; //============== // MIXERLINE CD //============== mixerLineCD.cbStruct = sizeof(MIXERLINE); mixerLineCD.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC; if (mixerGetLineInfo((HMIXEROBJ)hMixerCD,&mixerLineCD,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) { //return MIXER_ERR_GETLINEINFOCD; CDControlAvailable = FALSE; } else { CDControlAvailable = TRUE; } //===================== // MIXERLINECONTROL CD //===================== mixerLineControlsCD.cbStruct = sizeof(MIXERLINECONTROLS); mixerLineControlsCD.dwLineID = mixerLineCD.dwLineID; mixerLineControlsCD.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mixerLineControlsCD.cControls = 1; mixerLineControlsCD.cbmxctrl = sizeof(MIXERCONTROL); mixerLineControlsCD.pamxctrl =(MIXERCONTROL *) &mixerControlCD; if(mixerGetLineControls((HMIXEROBJ)hMixerCD,&mixerLineControlsCD,MIXER_GETLINECONTROLSF_ONEBYTYPE|MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) { // return MIXER_ERR_GETLINECONTROLSCD; CDControlAvailable = FALSE; } else { CDControlAvailable = TRUE; } //============================ // MIXERLINECONTROLDETAILS CD //============================ mixerControlDetailsCD.cbStruct = sizeof(MIXERCONTROLDETAILS); mixerControlDetailsCD.dwControlID = mixerControlCD.dwControlID; mixerControlDetailsCD.cChannels = 1/*mixerLineCD.cChannels 1*/; mixerControlDetailsCD.cMultipleItems = mixerControlCD.cMultipleItems; mixerControlDetailsCD.cbDetails =sizeof(MIXERCONTROLDETAILS_UNSIGNED); mixerControlDetailsCD.paDetails= &valeurCD; #endif //DISABLE_CD return 0; } DWORD SND_fn_dwGetCDMax() { #ifndef DISABLE_CD return mixerControlCD.Bounds.dwMaximum; #else return 0; #endif //DISABLE_CD } DWORD SND_fn_dwGetCDMin() { #ifndef DISABLE_CD return mixerControlCD.Bounds.dwMinimum; #else return 0; #endif //DISABLE_CD } //======================================= //void SND_fn_dwGetCDValue(DWORD val) //======================================= // Positionne le volume du CD en % // val entre 0 et 100 //======================================= DWORD SND_fn_dwGetCDValue() { #ifndef DISABLE_CD DWORD inc; DWORD result; if (CDControlAvailable) { inc = (SND_fn_dwGetCDMax()-SND_fn_dwGetCDMin())/100; if(mixerGetControlDetails((HMIXEROBJ)hMixerCD,&mixerControlDetailsCD,MIXER_GETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) return 1; result = (valeurCD.dwValue - SND_fn_dwGetCDMin())/inc; //snd_assert(result>=0); snd_assert(result<=100); return result; } else #endif //DISABLE_CD return 0; } //======================================= //void SND_fn_vSetCDValue(DWORD val) //======================================= // Positionne le volume du CD en % // val entre 0 et 100 //======================================= void SND_fn_vSetCDValue(DWORD val) { #ifndef DISABLE_CD // val est en pourcentage DWORD inc; if (CDControlAvailable) { //snd_assert(val>=0); snd_assert(val<=100); inc = (SND_fn_dwGetCDMax()-SND_fn_dwGetCDMin())/100; val = (val* inc) + SND_fn_dwGetCDMin(); snd_assert(val>=SND_fn_dwGetCDMin()); snd_assert(val<=SND_fn_dwGetCDMax()); valeurCD.dwValue = val; if(mixerSetControlDetails((HMIXEROBJ)hMixerCD,&mixerControlDetailsCD,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) { //return 1; } } #endif //DISABLE_CD } BOOL SND_fn_bIsCDControlAvailable() { #ifndef DISABLE_CD return CDControlAvailable; #else return FALSE; #endif //DISABLE_CD } int SND_fn_iMixerDesInitCD() { #ifndef DISABLE_CD if(mixerClose(hMixerCD) != MMSYSERR_NOERROR) { SND_fn_vDisplayError(E_uwSndMixerDesinit,""); return 1; } #endif //DISABLE_CD return 0; } /*-------------------------------------------------- relache-reprise a chaud des drives ---------------------------------------------------------*/ #define PAUSED_BY_RESTORE_RELEASE 2 void SND_CALL SND_fn_vReleaseDriverCDThread() { #ifndef DISABLE_CD // si le Cd n'est pas deja en pause, on le pause mais pause type 2 if (! stActiveCDTrack.bPaused) { SND_fn_vPauseCDThread(stActiveCDTrack.lVoice); stActiveCDTrack.bPaused = (BOOL)PAUSED_BY_RESTORE_RELEASE; } #endif //DISABLE_CD } void SND_CALL SND_fn_vReleaseDriverCD() { #ifndef DISABLE_CD HANDLE hEventSynchro; if (stCDDriver.bCdDriverOk && stActiveCDTrack.bActive) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); if (!PostThreadMessage(dwCDThreadId,(UINT)SND_RELEASECD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDStop,"PostThreadMessage Release"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); } #endif //DISABLE_CD } void SND_CALL SND_fn_vRestoreDriverCDThread() { #ifndef DISABLE_CD // si le CD etait en pause du fait du release, on le relance // sinon, il etait en pause, on reste en pause if (stActiveCDTrack.bPaused == (BOOL)PAUSED_BY_RESTORE_RELEASE) SND_fn_vResumeCDThread(stActiveCDTrack.lVoice); #endif //DISABLE_CD } void SND_CALL SND_fn_vRestoreDriverCD() { #ifndef DISABLE_CD HANDLE hEventSynchro; if (stCDDriver.bCdDriverOk && stActiveCDTrack.bActive) { hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); if (!PostThreadMessage(dwCDThreadId,(UINT)SND_RESTORECD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDStop,"PostThreadMessage Restore"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); } #endif //DISABLE_CD } //--------------------------------------------------------- // GetPos: retourne la position "théorique" de la ressource // exprimé en seconde depuis le début // différent du temps absolu (car pitch, dérive..) // Entrée: voie concernée // Sortie: temps en S (SndReal) //---------------------------------------------------------- SndReal SND_CALL SND_fn_rGetPosCDThread(long voie) { double dfCDTrackPos = 0.0; #ifndef DISABLE_CD dfCDTrackPos=(double)SND_fn_lGetCurrentCdPosition(voie & MASK_OFFSET_CD_VOICE) / 1000; #endif return (M_DoubleToRealSnd(dfCDTrackPos)); } //--------------------------------------------------------- // GetPos: retourne la position "théorique" de la ressource // exprimé en seconde depuis le début // différent du temps absolu (car pitch, dérive..) // Entrée: voie concernée // Sortie: temps en S (SndReal) //---------------------------------------------------------- SndReal SND_CALL SND_fn_rGetPosCD(long voie) { #ifndef DISABLE_CD HANDLE hEventSynchro; if (stCDDriver.bCdDriverOk && stActiveCDTrack.bActive) { dw_a5_Params[0] = (DWORD)voie; hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL); if (!PostThreadMessage(dwCDThreadId,(UINT)SND_GETPOSCD_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro)) SND_fn_vDisplayError(E_uwSndCDStop,"Get Pos error"); WaitForSingleObject(hEventSynchro,INFINITE); CloseHandle(hEventSynchro); return (dw_a5_Params[0]); } else return SND_C_POS_UNKNOWN; #endif //DISABLE_CD return SND_C_POS_UNKNOWN; } //--------------------------------------------------------- // GetLength: retourne la durée "théorique" de la ressource // exprimé en seconde (constant pour une ressource donnée) // Entrée: voie concernée // Sortie: durée en S (SndReal) //---------------------------------------------------------- SndReal SND_CALL SND_fn_rGetLengthCD(long voie) { double dfCDTrackTime = 0.0; #ifndef DISABLE_CD dfCDTrackTime=(double)SND_fn_ulGetCDTrackLengthInMs(voie & MASK_OFFSET_CD_VOICE) / 1000; #endif return (M_DoubleToRealSnd(dfCDTrackTime)); //return SND_C_POS_UNKNOWN; } //------------------------------------------------- // Fonction de synchro moteur // ne sert à rien pour CD //------------------------------------------------- void SND_CALL SND_fn_vSynchroCD(void) { } SndBool SND_CALL SND_fn_bCheckVersionResourceCD(tdstBlockResourceDisk* disk) { return TRUE; } SndBool SND_CALL SND_fn_bSetResourceStaticVolumeCD(tdstBlockResourceMem* pstRes,unsigned char ucVolume) { pstRes->ucVolume=ucVolume; return TRUE; } // Partie de gestion de player de CD ouvert en partageable