2011 lines
58 KiB
C
2011 lines
58 KiB
C
/*
|
|
|
|
MODULE DE GESTION DU MIDI
|
|
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_uwSndMIDILoadTrack
|
|
E_uwSndMIDIStatus
|
|
E_uwSndMIDISet
|
|
E_uwSndMIDIPlay
|
|
E_uwSndMIDIStop
|
|
E_uwSndMIDINotifyFailure
|
|
E_uwSndMIDINotifyAborted
|
|
E_uwSndMIDINotifySuperseded
|
|
E_uwSndMIDICreateThread
|
|
E_uwSndMIDIOpen
|
|
E_uwSndMIDIClose
|
|
E_uwSndMIDIFade
|
|
E_uwSndMIDINbTracks
|
|
E_uwSndMIDIAllTracksUsed
|
|
|
|
******************************************************************************/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
|
|
#include "SNDinc.h"
|
|
|
|
#include "sndres.h"
|
|
#include "sndwin95.h"
|
|
#include "sndmidi.h"
|
|
|
|
#if defined(_DLL_COMPILATION_MODE)
|
|
#include "SNDDLL.h"
|
|
#endif
|
|
#include "sndthrd.h"
|
|
|
|
//#define MIDI_MCI
|
|
|
|
#ifndef DISABLE_MIDI
|
|
|
|
// Gestion du mixer midi, volume , muet....
|
|
|
|
static MIXERCAPS mixerCapsMidi;
|
|
static HMIXER hMixerMidi;
|
|
static UINT mixerIdentifierMidi;
|
|
static UINT uiNbrMixersMidi;
|
|
static DWORD dwNbrAudioLinesMidi;
|
|
|
|
static MIXERLINE mixerLineMidi;
|
|
static MIXERLINECONTROLS mixerLineControlsMidi;
|
|
static MIXERCONTROL mixerControlMidi;
|
|
static MIXERCONTROLDETAILS mixerControlDetailsMidi;
|
|
static MIXERCONTROLDETAILS_UNSIGNED valeurMidi;
|
|
static BOOL MidiControlAvailable = FALSE;
|
|
|
|
// Utilitaires de transformation d'unité de temps
|
|
|
|
#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)
|
|
|
|
//(DWORD) (((((((DWORD)tmsf>>8)&0xff) * 60)+(((DWORD)tmsf>>16)&0xff)) * 75)+(((DWORD)tmsf>>24)&0xff))
|
|
|
|
#define MSG_ERR_MIDI "Midi Device Error"
|
|
#define MSG_ERR_MIDI_FILE "Midi File Error"
|
|
|
|
#define NB_MAX_MIDI_TRACKS 50
|
|
//#define VOL_MAX_MIDI 60
|
|
|
|
#define OFFSET_MIDI_VOICE 0x2000
|
|
#define MASK_OFFSET_MIDI_VOICE 0x0FFF
|
|
#define NO_MIDI_VOICE 0x1000
|
|
#define MIDI_UNAVAILABLE 0x0008
|
|
|
|
#define FADE_AND_STOP_MIDI 12
|
|
|
|
//#ifdef MIDI_MCI
|
|
|
|
// VARIABLES GLOBALES EXTERNES
|
|
// TYPEDEF LOCAUX
|
|
|
|
//typedef struct _tdstMidiTrack
|
|
//{
|
|
// tduRefRes uMidiTrack;
|
|
// MCIDEVICEID uiMidiDeviceId;
|
|
// unsigned long ulLength;
|
|
// unsigned long ulNbLoops;
|
|
// unsigned long ulNb;
|
|
//}
|
|
//tdstMidiTrack;
|
|
|
|
typedef struct _tdstActiveMidiTrack
|
|
{
|
|
SndBool bActive;
|
|
SndBool bPaused;
|
|
SndBool bLoop;
|
|
MCIDEVICEID uiMidiDeviceId;
|
|
unsigned long ulLength;
|
|
unsigned long ulNbLoops;
|
|
unsigned long ulTrackLengthInMs;
|
|
long lVoice;
|
|
long lIndexVoice;
|
|
|
|
SoundParam * pstSoundParam;
|
|
long lPrio;
|
|
SND_td_pfn_vSoundCallback pfnSoundCallback;
|
|
long lParSoundCallback;
|
|
}tdstActiveMidiTrack;
|
|
|
|
typedef struct stMidiDriver
|
|
{
|
|
SndBool bMidiDriverOk;
|
|
int iLastMidiVolume;
|
|
}tdstMidiDriver;
|
|
|
|
|
|
// -------------------------------------------
|
|
// VARIABLES CONCERNANT LA GESTION DES THREADS
|
|
|
|
|
|
UINT SND_PLAYMIDI_MSG;
|
|
UINT SND_STOPMIDI_MSG;
|
|
UINT SND_LOADMIDI_MSG;
|
|
UINT SND_UNLOADMIDI_MSG;
|
|
UINT SND_PAUSEMIDI_MSG;
|
|
UINT SND_RESUMEMIDI_MSG;
|
|
UINT SND_NEXTTRACKMIDI_MSG;
|
|
UINT SND_DESINITMIDI_MSG;
|
|
UINT SND_RELEASEMIDI_MSG;
|
|
UINT SND_RESTOREMIDI_MSG;
|
|
static DWORD dw_a5_Params[5];
|
|
|
|
// VARIABLES GLOBALES LOCALES
|
|
|
|
static SndBool bMidiFadeIn = FALSE;
|
|
static UINT uiTimerMidiFadeIn; // Gestion du fade-in
|
|
static unsigned long ulCountDownFadeInMidi;
|
|
static unsigned long ulTimerPeriodFadeInMidi;
|
|
static unsigned long ulFadeInDurationMidi;
|
|
static long lNbIterFadeInMidi;
|
|
|
|
static SndBool bMidiFadeOut= FALSE;
|
|
static UINT uiTimerMidiFadeOut; // Gestion du fade-out
|
|
static unsigned long ulCountDownFadeOutMidi;
|
|
static unsigned long ulTimerPeriodFadeOutMidi;
|
|
static unsigned long ulFadeOutDurationMidi;
|
|
static long lNbIterFadeOutMidi;
|
|
|
|
static unsigned char ucFacteurVolumeMidi; // Volume global Midi
|
|
|
|
static MCIDEVICEID NO_MIDI_DEVICE = 127;
|
|
|
|
// Pistes Midi du jeu et piste active
|
|
static tduRefRes stMidiTracks[NB_MAX_MIDI_TRACKS];
|
|
|
|
//tdstMidiTrack stMidiTracks[NB_MAX_MIDI_TRACKS];
|
|
static tdstActiveMidiTrack stActiveMidiTrack;
|
|
|
|
static tdstMidiDriver stMidiDriver; // Midi driver
|
|
static int iNbTracks;
|
|
|
|
static char StrMidiDirectory[256];
|
|
static char texte_erreur_Midi[256];
|
|
|
|
|
|
// -------------------------------------------
|
|
// HANDLE ET ID DE THREADS ET FENETRES
|
|
|
|
|
|
static HWND hSndMidiWnd;// handle de la fenetre de gestion des messages
|
|
static DWORD dwMidiThreadId;
|
|
static HANDLE hMidiThread=NULL;
|
|
static DWORD dw_a2_threadParams[2];
|
|
static HANDLE hMidiThreadCallBack;
|
|
static DWORD dwMidiThreadIdCallBack;
|
|
|
|
|
|
int SND_fn_iInitMidiThread(void);
|
|
void SND_fn_vDesInitMidiThread(void);
|
|
SndBool SND_fn_bLoadMidiTrackThread(tdstBlockResourceMem * pstPtr,char *czFileName);
|
|
SndBool SND_fn_bUnloadMidiTrackThread(long lVoice);
|
|
long SND_fn_lPlayMidiThread(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback);
|
|
void SND_fn_vStopMidiThread(long voice);
|
|
void SND_fn_vPauseMidiThread(long voice);
|
|
void SND_fn_vResumeMidiThread(long voice);
|
|
|
|
void SND_CALL SND_fn_vReleaseDriverMidiThread();
|
|
void SND_CALL SND_fn_vRestoreDriverMidiThread();
|
|
|
|
|
|
// -------------------------------------------
|
|
// PROTOTYPES DES FONCTIONS LOCALES
|
|
|
|
SndBool SND_fn_bLoadMidiTrack(tdstBlockResourceMem * pstPtr,char *czFileName);
|
|
SndBool SND_fn_bUnloadMidiTrack(long voice);
|
|
long SND_fn_lGetActiveTrack(void);
|
|
long SND_fn_lGetCurrentMode(void);
|
|
long SND_fn_l_GetCurrentPosition(void);
|
|
LRESULT CALLBACK SND_fn_vMidiMSG(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
|
|
|
|
int SND_fn_iMixerInitMidi(void);
|
|
int SND_fn_iMixerDesInitMidi(void);
|
|
DWORD SND_fn_dwSND_fn_dwGetMidiMax(void);
|
|
DWORD SND_fn_dwSND_fn_dwGetMidiMin(void);
|
|
DWORD SND_fn_dwGetMidiValue(void);
|
|
void SND_fn_vSetMidiValue(DWORD val);
|
|
|
|
#endif //DISABLE_MIDI
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// ConvertRsvDiskToMem
|
|
//
|
|
// But : Convertir un BlockResourceDisk en Mem non opérationel
|
|
// Entrées : reference au structs ressources mem et disk
|
|
// Sorties : neant
|
|
//------------------------------------------------------------
|
|
void SND_CALL SND_fn_vConvertResDiskToMemMidi(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem,void * ptrBegin)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
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.stMidi.bStream = disk->uRes.stMidi.bStream;
|
|
mem->uRes.stMidi.bVolable = disk->uRes.stMidi.bVolable;
|
|
mem->uRes.stMidi.bLoop = disk->uRes.stMidi.bLoop;
|
|
mem->uRes.stMidi.ulNbLoops = disk->uRes.stMidi.ulNbLoops;
|
|
if (mem->uRes.stMidi.bLoop)
|
|
{
|
|
mem->uRes.stMidi.ulStartLoop = disk->uRes.stMidi.ulStartLoop;
|
|
mem->uRes.stMidi.ulEndLoop = disk->uRes.stMidi.ulEndLoop;
|
|
}
|
|
else
|
|
{
|
|
mem->uRes.stMidi.ulStartLoop = mem->uRes.stMidi.ulEndLoop = 0;
|
|
}
|
|
if (mem->uRes.stMidi.bStream)
|
|
{
|
|
strcpy(mem->uRes.stMidi.uData.stStream.fichier,"TOTO.MID");
|
|
mem->uRes.stMidi.uData.stStream.Offset = 0;
|
|
}
|
|
mem->uRes.stMidi.uData.stMem.uiMidiDeviceId=NO_MIDI_DEVICE;
|
|
// seul LoadResFromdisk doit rendre la ressource opérationelle
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// LoadResFromDiskMidi:rendre opérationel une ressource
|
|
// Entrées:blockdisk à exploiter
|
|
// blockmem à remplir (déjà alloué)
|
|
//--------------------------------------------------------
|
|
/*
|
|
void SND_CALL SND_fn_vLoadResFromDiskMidi(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
SND_fn_vConvertResDiskToMemMidi(disk,mem,NULL);
|
|
|
|
mem->bIsLoaded = TRUE;
|
|
if (!SND_fn_bLoadMidiTrack(mem,disk->uRes.stMidi.czFileName))
|
|
{
|
|
mem->bIsLoaded = FALSE;
|
|
SND_fn_vDisplayError(E_uwSndMIDILoadTrack,"From Disk");
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
*/
|
|
|
|
|
|
char SND_gszMidiMDXFakePartName[13]="fakepart.mid";
|
|
|
|
#if !defined(NO_ACP_SCRIPT) || defined(_DLL_COMPILATION_MODE)
|
|
/*this function must be defined in Script/Hybrid or DLL mode*/
|
|
SndBool SND_CALL SND_fn_bLoadResScriptMidi(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
char czFileName[13];
|
|
|
|
|
|
SND_fn_vConvertResDiskToMemMidi(disk,mem,NULL);
|
|
|
|
mem->bIsLoaded = TRUE;
|
|
|
|
// Case mdx fakepart: :
|
|
// change filename to lowercase and search the ".mdx" extension:
|
|
strncpy(czFileName,disk->uRes.stMidi.czFileName,13);
|
|
strlwr(czFileName);
|
|
// it's a mdx: replace it by the fakepart.mid file
|
|
if (strstr(czFileName,".mdx")!=NULL)
|
|
{
|
|
strcpy(disk->uRes.stMidi.czFileName,SND_gszMidiMDXFakePartName);
|
|
}
|
|
if (!SND_fn_bLoadMidiTrack(mem,disk->uRes.stMidi.czFileName))
|
|
{
|
|
mem->bIsLoaded = FALSE;
|
|
SND_fn_vDisplayError(E_uwSndMIDILoadTrack,"From Script");
|
|
return FALSE;
|
|
}
|
|
else return TRUE;
|
|
#else
|
|
return FALSE;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
#endif
|
|
|
|
SndBool SND_CALL SND_fn_bLoadResBinaryMidi(tdstBlockResourceDisk *disk,tdstBlockResourceMem *mem,char *pDataBloc)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
SND_fn_vConvertResDiskToMemMidi(disk,mem,NULL);
|
|
|
|
mem->bIsLoaded = TRUE;
|
|
if (!SND_fn_bLoadMidiTrack(mem,disk->uRes.stMidi.czFileName))
|
|
{
|
|
mem->bIsLoaded = FALSE;
|
|
SND_fn_vDisplayError(E_uwSndMIDILoadTrack,"From Binary");
|
|
|
|
return FALSE;
|
|
}
|
|
else
|
|
return TRUE;
|
|
#else
|
|
return FALSE;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
|
|
#ifndef DISABLE_MIDI
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_iMidiThreadCallBack
|
|
//
|
|
// 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_iMidiThreadCallBack(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_vMidiMSG
|
|
//
|
|
// But : Effectuer la gestion des messages du MIDI
|
|
// Entrées : Messages et leurs parametres
|
|
// Sorties : Ok ou Failed
|
|
//------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK SND_fn_vMidiMSG(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
char texte[256];
|
|
SECURITY_ATTRIBUTES sa;
|
|
|
|
switch(message)
|
|
{
|
|
case WM_CREATE : break;
|
|
case WM_COMMAND : 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_uwSndMIDINotifyFailure,texte);
|
|
break;
|
|
case MCI_NOTIFY_ABORTED:
|
|
// sprintf(texte,"MM_MCINOTIFY ABORTED wpar=%d lpar=%d",wParam,lParam);
|
|
// SND_fn_vDisplayError(E_uwSndMIDINotifyAborted,texte);
|
|
break;
|
|
case MCI_NOTIFY_SUPERSEDED:
|
|
sprintf(texte,"MM_MCINOTIFY SUPERSEDED wpar=%d lpar=%d",wParam,lParam);
|
|
SND_fn_vDisplayError(E_uwSndMIDINotifyFailure,texte);
|
|
break;
|
|
case MCI_NOTIFY_SUCCESSFUL:
|
|
switch (SND_fn_lGetCurrentMode())
|
|
{
|
|
case MCI_MODE_STOP :
|
|
// cas ou la piste est terminee de lire, on lance la callback
|
|
// si elle n'est pas nulle
|
|
if (!stActiveMidiTrack.bPaused)
|
|
{
|
|
|
|
if ((stActiveMidiTrack.bLoop) && (--stActiveMidiTrack.ulNbLoops))
|
|
{
|
|
SND_fn_lPlayMidiThread(stMidiTracks[stActiveMidiTrack.lVoice],stActiveMidiTrack.pstSoundParam,stActiveMidiTrack.lPrio,stActiveMidiTrack.pfnSoundCallback,stActiveMidiTrack.lParSoundCallback);
|
|
}
|
|
else
|
|
{
|
|
if (!stActiveMidiTrack.bPaused)
|
|
{
|
|
stActiveMidiTrack.lPrio = 0;
|
|
stActiveMidiTrack.lVoice = NO_MIDI_VOICE;
|
|
stActiveMidiTrack.pstSoundParam = NULL;
|
|
stActiveMidiTrack.bPaused = FALSE;
|
|
stActiveMidiTrack.bActive = FALSE;
|
|
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.bInheritHandle = TRUE;
|
|
sa.lpSecurityDescriptor = NULL;
|
|
dw_a2_threadParams[0] = (DWORD)stActiveMidiTrack.pfnSoundCallback;
|
|
dw_a2_threadParams[1] = (DWORD)stActiveMidiTrack.lParSoundCallback;
|
|
if (!(hMidiThreadCallBack = CreateThread(&sa,0,(LPTHREAD_START_ROUTINE)SND_fn_iMidiThreadCallBack,(LPVOID)dw_a2_threadParams,0,&dwMidiThreadIdCallBack)))
|
|
SND_fn_vDisplayError(E_uwSndMIDICreateThread,"");
|
|
|
|
/*
|
|
if (stActiveMidiTrack.pfnSoundCallback!= NULL)
|
|
(*stActiveMidiTrack.pfnSoundCallback)(stActiveMidiTrack.lParSoundCallback);
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MCI_MODE_PAUSE :
|
|
case MCI_MODE_OPEN :
|
|
case MCI_MODE_NOT_READY :
|
|
case MCI_MODE_PLAY :
|
|
case MCI_MODE_SEEK :
|
|
case MCI_MODE_RECORD :
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
if (uiTimerMidiFadeIn)
|
|
timeKillEvent(uiTimerMidiFadeIn);
|
|
if (uiTimerMidiFadeOut)
|
|
timeKillEvent(uiTimerMidiFadeOut);
|
|
PostQuitMessage(0);
|
|
break;
|
|
default:
|
|
return DefWindowProc(hwnd,message,wParam,lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_iMidiThreadProc
|
|
//
|
|
// 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_iMidiThreadProc(HANDLE arglist)
|
|
{
|
|
MSG msg;
|
|
WNDCLASS wcMidiWndClass;
|
|
DWORD * pdwParams;
|
|
|
|
PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);
|
|
|
|
|
|
if (SND_fn_iInitMidiThread() == C_INIT_FAILED)
|
|
{
|
|
stMidiDriver.bMidiDriverOk = FALSE;
|
|
ExitThread(C_INIT_FAILED);
|
|
}
|
|
|
|
//definit la window-classe
|
|
//definit la window-classe
|
|
wcMidiWndClass.hInstance = SND_hGlobalInst;
|
|
wcMidiWndClass.lpszClassName = "SoundAcpMidi";
|
|
wcMidiWndClass.lpfnWndProc = SND_fn_vMidiMSG;//fonction associée à la fonction
|
|
wcMidiWndClass.style = 0;
|
|
wcMidiWndClass.hIcon = 0;
|
|
wcMidiWndClass.hCursor = 0;
|
|
wcMidiWndClass.lpszMenuName = "\0";
|
|
wcMidiWndClass.cbClsExtra = 0;
|
|
wcMidiWndClass.cbWndExtra = 0;
|
|
wcMidiWndClass.hbrBackground = 0;
|
|
|
|
//enregistrement de la classe CdWnd
|
|
if (!RegisterClass(&wcMidiWndClass))
|
|
SND_fn_vDisplayError(E_uwSndCDRegisterWndClass,"");
|
|
|
|
//création de la fenetre midi
|
|
hSndMidiWnd = CreateWindow(wcMidiWndClass.lpszClassName,"MidiWindow",WS_OVERLAPPEDWINDOW,0,0,0,0,HWND_DESKTOP,NULL,SND_hGlobalInst,NULL);
|
|
|
|
// synchro d'initialisation du thread et de la pompe a messages
|
|
SetEvent(arglist);
|
|
|
|
while (GetMessage(&msg,NULL,0,0))
|
|
{
|
|
if (msg.message == SND_PLAYMIDI_MSG)
|
|
{
|
|
pdwParams = (DWORD *)msg.wParam;
|
|
pdwParams[0] = SND_fn_lPlayMidiThread(*(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_STOPMIDI_MSG)
|
|
{
|
|
pdwParams = (DWORD *)msg.wParam;
|
|
SND_fn_vStopMidiThread((long)pdwParams[0]);
|
|
SetEvent((HANDLE)msg.lParam);
|
|
}
|
|
else
|
|
if (msg.message == SND_LOADMIDI_MSG)
|
|
{
|
|
pdwParams = (DWORD *)msg.wParam;
|
|
pdwParams[0] = SND_fn_bLoadMidiTrackThread((tdstBlockResourceMem *)pdwParams[0],(char *)pdwParams[1]);
|
|
SetEvent((HANDLE)msg.lParam);
|
|
}
|
|
else
|
|
if (msg.message == SND_UNLOADMIDI_MSG)
|
|
{
|
|
pdwParams = (DWORD *)msg.wParam;
|
|
pdwParams[0] = SND_fn_bUnloadMidiTrackThread((long)pdwParams[0]);
|
|
SetEvent((HANDLE)msg.lParam);
|
|
}
|
|
else
|
|
if (msg.message == SND_PAUSEMIDI_MSG)
|
|
{
|
|
pdwParams = (DWORD *)msg.wParam;
|
|
SND_fn_vPauseMidiThread((long)pdwParams[0]);
|
|
SetEvent((HANDLE)msg.lParam);
|
|
}
|
|
else
|
|
if (msg.message == SND_RESUMEMIDI_MSG)
|
|
{
|
|
pdwParams = (DWORD *)msg.wParam;
|
|
SND_fn_vResumeMidiThread((long)pdwParams[0]);
|
|
SetEvent((HANDLE)msg.lParam);
|
|
}
|
|
else
|
|
if (msg.message == SND_DESINITMIDI_MSG)
|
|
{
|
|
SND_fn_vDesInitMidiThread();
|
|
SetEvent((HANDLE)msg.lParam);
|
|
ExitThread(0);
|
|
}
|
|
else
|
|
if (msg.message == SND_RELEASEMIDI_MSG)
|
|
{
|
|
SND_fn_vReleaseDriverMidiThread();
|
|
SetEvent((HANDLE)msg.lParam);
|
|
}
|
|
else
|
|
if (msg.message == SND_RESTOREMIDI_MSG)
|
|
{
|
|
SND_fn_vRestoreDriverMidiThread();
|
|
SetEvent((HANDLE)msg.lParam);
|
|
}
|
|
else
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
//WaitMessage();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lTimerIn()
|
|
//
|
|
// But : Callback de gestion du temps pour les fade-in.
|
|
// Entrées : neant
|
|
// Sorties : neant
|
|
//------------------------------------------------------------
|
|
void CALLBACK SND_fn_lMidiTimerIn(UINT IDEvent,UINT msg,DWORD par,DWORD dw1,DWORD dw2)
|
|
{
|
|
if (!stActiveMidiTrack.bPaused && stActiveMidiTrack.bActive)
|
|
if (bMidiFadeIn)
|
|
{
|
|
if (lNbIterFadeInMidi--)
|
|
SND_fn_vSetMidiValue(ucFacteurVolumeMidi++);
|
|
else
|
|
{
|
|
bMidiFadeIn = FALSE;
|
|
ulCountDownFadeInMidi = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lTimerOut()
|
|
//
|
|
// But : Callback de gestion du temps pour les fade-in.
|
|
// Entrées : neant
|
|
// Sorties : neant
|
|
//------------------------------------------------------------
|
|
void CALLBACK SND_fn_lMidiTimerOut(UINT IDEvent,UINT msg,DWORD par,DWORD dw1,DWORD dw2)
|
|
{
|
|
unsigned long ulRealTime = 0;
|
|
if (!stActiveMidiTrack.bPaused && stActiveMidiTrack.bActive)
|
|
if (bMidiFadeOut)
|
|
{
|
|
ulCountDownFadeOutMidi += ulTimerPeriodFadeOutMidi;
|
|
ulRealTime = stActiveMidiTrack.ulTrackLengthInMs - lNbIterFadeOutMidi * ulTimerPeriodFadeOutMidi;
|
|
if (ulCountDownFadeOutMidi > ulRealTime)
|
|
{
|
|
SND_fn_vSetMidiValue(ucFacteurVolumeMidi);
|
|
if (ucFacteurVolumeMidi-- == 0)
|
|
{
|
|
bMidiFadeOut = FALSE;
|
|
ulCountDownFadeOutMidi = 0;
|
|
if (par == FADE_AND_STOP_MIDI)
|
|
{
|
|
SND_fn_vStopMidiThread(0);
|
|
PostMessage(hSndMidiWnd,MM_MCINOTIFY,MCI_NOTIFY_SUCCESSFUL,0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif //DISABLE_MIDI
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_iInitMidi
|
|
//
|
|
// 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_iInitMidi(SND_tdstInitStruct *pInitStruct)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
DWORD dwExitCode = 0;
|
|
HANDLE hEventSynchro;
|
|
SECURITY_ATTRIBUTES sa;
|
|
HANDLE hHandlesForWait[2];
|
|
|
|
#if defined(_DLL_COMPILATION_MODE)
|
|
SND_DllInitEntryPoints_StaticFunctions((HMODULE)pInitStruct->hProcessInstance );
|
|
#endif
|
|
|
|
stMidiDriver.bMidiDriverOk = MIDI_UNAVAILABLE;
|
|
uiTimerMidiFadeIn = uiTimerMidiFadeOut = 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_PLAYMIDI_MSG = RegisterWindowMessage("PlayMIDI");
|
|
SND_STOPMIDI_MSG = RegisterWindowMessage("StopMIDI");
|
|
SND_LOADMIDI_MSG = RegisterWindowMessage("LoadMIDI");
|
|
SND_UNLOADMIDI_MSG = RegisterWindowMessage("UnloadMIDI");
|
|
SND_PAUSEMIDI_MSG = RegisterWindowMessage("PauseMIDI");
|
|
SND_RESUMEMIDI_MSG = RegisterWindowMessage("ResumeMIDI");
|
|
SND_NEXTTRACKMIDI_MSG = RegisterWindowMessage("NextTrackMIDI");
|
|
SND_DESINITMIDI_MSG = RegisterWindowMessage("DesinitMIDI");
|
|
|
|
SND_RELEASEMIDI_MSG = RegisterWindowMessage("ReleaseMIDI");
|
|
SND_RESTOREMIDI_MSG = RegisterWindowMessage("RestoreMIDI");
|
|
|
|
|
|
// on cree le thread de gestion CD l'ID du thread est dwCDThreadId
|
|
hMidiThread = NULL;
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.bInheritHandle = TRUE;
|
|
sa.lpSecurityDescriptor = NULL;
|
|
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
while (TRUE)
|
|
{
|
|
if (!(hMidiThread = CreateThread(&sa,0,(LPTHREAD_START_ROUTINE)SND_fn_iMidiThreadProc,hEventSynchro,0,&dwMidiThreadId)))
|
|
{
|
|
SND_fn_vDisplayError(E_uwSndMIDICreateThread,"");
|
|
return C_INIT_FAILED;
|
|
}
|
|
else
|
|
{
|
|
hHandlesForWait[0] = hEventSynchro;
|
|
hHandlesForWait[1] = hMidiThread;
|
|
|
|
// on attend la synchronisation d'init., l'attente se termine quand un des deux events arrive
|
|
WaitForMultipleObjects(2,hHandlesForWait,FALSE,INFINITE);
|
|
GetExitCodeThread(hMidiThread,&dwExitCode);
|
|
if (dwExitCode == STILL_ACTIVE)
|
|
{
|
|
stMidiDriver.bMidiDriverOk = TRUE;
|
|
CloseHandle(hEventSynchro);
|
|
return C_INIT_OK;
|
|
}
|
|
else
|
|
{
|
|
if (dwExitCode == C_INIT_FAILED)
|
|
{
|
|
// on joue sans Midi
|
|
CloseHandle(hEventSynchro);
|
|
return C_INIT_FAILED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return C_INIT_OK;
|
|
#else
|
|
return C_INIT_FAILED;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
#ifndef DISABLE_MIDI
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_iInitMidi
|
|
//
|
|
// But : Realiser l'init bas niveau du driver midi
|
|
// Entrées : neant
|
|
// Sorties : C_INIT_OK ou C_INIT_FAILED
|
|
//------------------------------------------------------------
|
|
int SND_fn_iInitMidiThread()
|
|
{
|
|
int i;
|
|
|
|
for (i=0;i < NB_MAX_MIDI_TRACKS;i++)
|
|
stMidiTracks[i].pstPtr = NULL;
|
|
|
|
stActiveMidiTrack.bLoop = FALSE;
|
|
stActiveMidiTrack.bActive = FALSE;
|
|
stActiveMidiTrack.bPaused = FALSE;
|
|
stActiveMidiTrack.ulNbLoops = 0;
|
|
stActiveMidiTrack.ulLength = 0;
|
|
stActiveMidiTrack.lVoice = NO_MIDI_VOICE;
|
|
stActiveMidiTrack.pstSoundParam = NULL;
|
|
stActiveMidiTrack.lPrio = 0;
|
|
stActiveMidiTrack.pfnSoundCallback= NULL;
|
|
stActiveMidiTrack.lParSoundCallback= 0;
|
|
|
|
stMidiDriver.bMidiDriverOk = TRUE;
|
|
iNbTracks = 0;
|
|
|
|
if (!SND_fn_iMixerInitMidi())
|
|
{
|
|
// On sauve l'ancienne valeur du volume CD
|
|
stMidiDriver.iLastMidiVolume = SND_fn_dwGetMidiValue();
|
|
ucFacteurVolumeMidi = stMidiDriver.iLastMidiVolume;
|
|
SND_fn_vSetMidiValue(ucFacteurVolumeMidi);
|
|
}
|
|
return C_INIT_OK;
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_iTestInitMidi
|
|
//
|
|
// But : Verifier l'etat d'init du driver midi
|
|
// Entrées : neant
|
|
// Sorties : True ou False suivant l'etat
|
|
//------------------------------------------------------------
|
|
SndBool SND_CALL SND_fn_bTestInitMidi(void)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
return (stMidiDriver.bMidiDriverOk);
|
|
#else
|
|
return FALSE;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_iDesInitMidi
|
|
//
|
|
// But : Realiser la desnit bas niveau du driver midi
|
|
// Entrées : neant
|
|
// Sorties : neant
|
|
//------------------------------------------------------------
|
|
void SND_CALL SND_fn_vDesInitMidi(void)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
HANDLE hEventSynchro;
|
|
|
|
if (hMidiThread)
|
|
{
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
|
|
if (!PostThreadMessage(dwMidiThreadId,(UINT)SND_DESINITMIDI_MSG,(WPARAM)0,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDIClose,"PostThreadMessage Desinit");
|
|
|
|
WaitForSingleObject(hEventSynchro,INFINITE);
|
|
CloseHandle(hEventSynchro);
|
|
|
|
WaitForSingleObject(hMidiThread,INFINITE);
|
|
CloseHandle(hMidiThread);
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
#ifndef DISABLE_MIDI
|
|
//-----------------------------------------------------------
|
|
// SND_fn_iDesInitMidiThread
|
|
//
|
|
// But : Realiser la desnit bas niveau du driver midi
|
|
// Entrées : neant
|
|
// Sorties : neant
|
|
//------------------------------------------------------------
|
|
void SND_fn_vDesInitMidiThread(void)
|
|
{
|
|
int i;
|
|
for (i=0;i<iNbTracks;i++)
|
|
SND_fn_bUnloadMidiTrackThread(i);
|
|
|
|
stActiveMidiTrack.bLoop = FALSE;
|
|
stActiveMidiTrack.bActive = FALSE;
|
|
stActiveMidiTrack.bPaused = FALSE;
|
|
stActiveMidiTrack.ulNbLoops = 0;
|
|
stActiveMidiTrack.ulLength = 0;
|
|
stActiveMidiTrack.lVoice = NO_MIDI_VOICE;
|
|
stActiveMidiTrack.pstSoundParam = NULL;
|
|
stActiveMidiTrack.lPrio = 0;
|
|
stActiveMidiTrack.pfnSoundCallback= NULL;
|
|
stActiveMidiTrack.lParSoundCallback= 0;
|
|
|
|
stMidiDriver.bMidiDriverOk = FALSE;
|
|
|
|
// On restaure l'ancienne valeur du volume CD
|
|
SND_fn_vSetMidiValue(stMidiDriver.iLastMidiVolume);
|
|
SND_fn_iMixerDesInitMidi();
|
|
DestroyWindow(hSndMidiWnd);
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_vRemoveCallbackMidi
|
|
//
|
|
// But : Remettre a zero la callback de la ressource
|
|
// joue sur la voie voice
|
|
// Entrées : voie jouee
|
|
// Sorties : neant
|
|
//------------------------------------------------------------
|
|
void SND_CALL SND_fn_vRemoveCallbackMidi(long voice)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
stActiveMidiTrack.pfnSoundCallback= NULL;
|
|
stActiveMidiTrack.lParSoundCallback= 0;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_bSetParamMidi
|
|
//
|
|
// But : Faire varier en temps reel les parametres
|
|
// de la ressource midi
|
|
// Entrées : voie jouee, parametres sonores
|
|
// Sorties : TRUE si maj possible FALSE sinon
|
|
//------------------------------------------------------------
|
|
SndBool SND_CALL SND_fn_bSetParamMidi(long voice,SoundParam *par)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
return (stActiveMidiTrack.bActive);
|
|
#else
|
|
return FALSE;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_bTestIsPlayingMidi
|
|
//
|
|
// But : Une ressource midi est-elle active
|
|
// Entrées : voie jouee
|
|
// Sorties : Activite midi si voie bonne, FALSE sinon
|
|
//------------------------------------------------------------
|
|
SndBool SND_CALL SND_fn_bTestIsPlayingMidi(long voice)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
return (stActiveMidiTrack.bActive);
|
|
#else
|
|
return FALSE;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
#ifndef DISABLE_MIDI
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lGetMidiTrack
|
|
//
|
|
// But : Renvoie la voie bas niveau sur laquelle
|
|
// est chargee une ressource
|
|
// Entrées : Id de la ressource
|
|
// Sorties : voie bas niveau si resource chargee, NO_MIDI_VOICE sinon
|
|
//------------------------------------------------------------
|
|
long SND_fn_lGetMidiTrack(MCIDEVICEID Id)
|
|
{
|
|
int i = 0;
|
|
do
|
|
{
|
|
if (stMidiTracks[i].pstPtr == NULL)
|
|
i++;
|
|
else
|
|
if (stMidiTracks[i].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId != Id)
|
|
i++;
|
|
else
|
|
break;
|
|
}
|
|
while (i < NB_MAX_MIDI_TRACKS);
|
|
|
|
if (i == NB_MAX_MIDI_TRACKS)
|
|
return (NO_MIDI_VOICE);
|
|
else
|
|
return (i);
|
|
}
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lGetActiveTrack
|
|
//
|
|
// But : Renvoie la voie active
|
|
// Entrées : neant
|
|
// Sorties : voie bas niveau active, NO_MIDI_VOICE sinon
|
|
//------------------------------------------------------------
|
|
long SND_fn_lGetActiveTrack()
|
|
{
|
|
if (stActiveMidiTrack.bActive)
|
|
return (stActiveMidiTrack.lVoice);
|
|
else
|
|
return (NO_MIDI_VOICE);
|
|
}
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lGetCurrentMode
|
|
//
|
|
// But : Renvoie la callback midi
|
|
// Entrées : voie bas niveau
|
|
// Sorties : Mode du device correspondant a la voie
|
|
//------------------------------------------------------------
|
|
long SND_fn_lGetCurrentMode(void)
|
|
{
|
|
MCI_STATUS_PARMS status;
|
|
MCIERROR mciReturn;
|
|
// Mode actuel de la piste
|
|
status.dwItem = MCI_STATUS_MODE;
|
|
if (stActiveMidiTrack.uiMidiDeviceId != NO_MIDI_DEVICE)
|
|
{
|
|
if (mciReturn=mciSendCommand(stActiveMidiTrack.uiMidiDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIStatus,texte_erreur_Midi);
|
|
return (0);
|
|
}
|
|
}
|
|
else return (0);
|
|
return(status.dwReturn);
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lGetCurrentPosition
|
|
//
|
|
// But : Renvoie la position courante de lecture
|
|
// de la voie active
|
|
// Entrées : neant
|
|
// Sorties : position en millisecondes
|
|
//------------------------------------------------------------
|
|
long SND_fn_lGetCurrentPosition(void)
|
|
{
|
|
MCI_STATUS_PARMS status;
|
|
MCIERROR mciReturn;
|
|
|
|
// Mode actuel de la piste
|
|
status.dwItem = MCI_STATUS_MODE;
|
|
if (mciReturn=mciSendCommand(stActiveMidiTrack.uiMidiDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIStatus,texte_erreur_Midi);
|
|
return (0);
|
|
}
|
|
if ((status.dwReturn == MCI_MODE_PLAY)||(status.dwReturn == MCI_MODE_PAUSE))
|
|
{
|
|
// Si la piste est en mode play ou en pause
|
|
status.dwItem = MCI_STATUS_POSITION;
|
|
if (mciReturn=mciSendCommand(stActiveMidiTrack.uiMidiDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIStatus,texte_erreur_Midi);
|
|
return (0);
|
|
}
|
|
|
|
return (status.dwReturn);
|
|
}
|
|
else return (0);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_ulGetMidiTrackLengthInMs
|
|
//
|
|
// But : Calcule la duree exacte de la piste en millisecondes
|
|
// Entrées : La voie active
|
|
// Sorties : La position en tmsf
|
|
//------------------------
|
|
unsigned long SND_fn_ulGetMidiTrackLengthInMs(unsigned long ulVoice)
|
|
{
|
|
unsigned long ulRealLength;
|
|
ulRealLength = stMidiTracks[stActiveMidiTrack.lVoice].pstPtr->uRes.stMidi.uData.stMem.ulLength;
|
|
return (ulRealLength);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_ulInitFadeMidi
|
|
//
|
|
// But : Initialise les variables de fading
|
|
// Entrées :
|
|
// Sorties :
|
|
//------------------------
|
|
void SND_fn_ulInitFadeMidi( unsigned long ulFadeInDurationMidi,unsigned long ulFadeOutDurationMidi)
|
|
{
|
|
lNbIterFadeInMidi = ucFacteurVolumeMidi;
|
|
lNbIterFadeOutMidi = ucFacteurVolumeMidi;
|
|
|
|
if (ulFadeInDurationMidi+ulFadeOutDurationMidi < stActiveMidiTrack.ulTrackLengthInMs)
|
|
{
|
|
bMidiFadeIn = (SndBool)ulFadeInDurationMidi;
|
|
bMidiFadeOut = (SndBool)ulFadeOutDurationMidi;
|
|
|
|
if (bMidiFadeIn)
|
|
{
|
|
ulTimerPeriodFadeInMidi = ulFadeInDurationMidi / lNbIterFadeInMidi;
|
|
ulCountDownFadeInMidi = 0;
|
|
ucFacteurVolumeMidi = 0;
|
|
// init du timer cross-fade
|
|
uiTimerMidiFadeIn = timeSetEvent(ulTimerPeriodFadeInMidi,10,(LPTIMECALLBACK)SND_fn_lMidiTimerIn,(DWORD)0,TIME_PERIODIC);
|
|
}
|
|
if (bMidiFadeOut)
|
|
{
|
|
ulTimerPeriodFadeOutMidi = ulFadeOutDurationMidi / lNbIterFadeInMidi;
|
|
ulCountDownFadeOutMidi = 0;
|
|
if (!bMidiFadeIn)
|
|
{
|
|
ucFacteurVolumeMidi = ucFacteurVolumeMidi;
|
|
}
|
|
// init du timer cross-fade
|
|
uiTimerMidiFadeOut = timeSetEvent(ulTimerPeriodFadeOutMidi,10,(LPTIMECALLBACK)SND_fn_lMidiTimerOut,(DWORD)0,TIME_PERIODIC);
|
|
}
|
|
SND_fn_vSetMidiValue(ucFacteurVolumeMidi);
|
|
}
|
|
else
|
|
{
|
|
SND_fn_vSetMidiValue(ucFacteurVolumeMidi);
|
|
SND_fn_vDisplayError(E_uwSndMIDIFade,"Bad Fading Parameters");
|
|
}
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lPlayMidi
|
|
//
|
|
// But : Joue la ressource midi res
|
|
// Entrées : La ressource, parametres son, la priorite et
|
|
// la callback
|
|
// Sorties : voie allouee pour jouee la ressource
|
|
//------------------------------------------------------------
|
|
long SND_CALL SND_fn_lPlayMidi(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
HANDLE hEventSynchro;
|
|
|
|
// Case mdx part: fail:
|
|
char czFileName[13];
|
|
// change filename to lowercase and search the ".mdx" extension:
|
|
strncpy(czFileName,res.pstPtr->uRes.stMidi.uData.stStream.fichier,13);
|
|
strlwr(czFileName);
|
|
if (strstr(czFileName,".mdx")!=NULL) return C_PLAY_FAILED;
|
|
|
|
|
|
|
|
if (stMidiDriver.bMidiDriverOk)
|
|
{
|
|
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(dwMidiThreadId,(UINT)SND_PLAYMIDI_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDIPlay,"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
|
|
#endif //DISABLE_MIDI
|
|
return (C_PLAY_FAILED);
|
|
}
|
|
|
|
#ifndef DISABLE_MIDI
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lPlayMidiThread
|
|
//
|
|
// But : Joue la ressource midi res
|
|
// Entrées : La ressource, parametres son, la priorite et
|
|
// la callback
|
|
// Sorties : voie allouee pour jouee la ressource
|
|
//------------------------------------------------------------
|
|
long SND_fn_lPlayMidiThread(tduRefRes res,SoundParam *par,long prio,SND_td_pfn_vSoundCallback fn_callback,long par_callback)
|
|
{
|
|
MCIERROR mciReturn;
|
|
MCI_PLAY_PARMS play;
|
|
long lVoice = 0,lIndexVoice;
|
|
|
|
play.dwCallback = (DWORD)hSndMidiWnd;
|
|
play.dwFrom = 0;
|
|
if ((lVoice = SND_fn_lGetMidiTrack(res.pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId)) != NO_MIDI_VOICE)
|
|
{
|
|
debut:
|
|
lIndexVoice = SND_fn_lGetMidiTrack(res.pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId);
|
|
if (stActiveMidiTrack.lVoice == NO_MIDI_VOICE)
|
|
{
|
|
stActiveMidiTrack.bLoop = res.pstPtr->uRes.stMidi.bLoop;
|
|
stActiveMidiTrack.lPrio = prio;
|
|
stActiveMidiTrack.lVoice = lVoice;
|
|
stActiveMidiTrack.lIndexVoice = lIndexVoice;
|
|
stActiveMidiTrack.ulNbLoops = stMidiTracks[lIndexVoice].pstPtr->uRes.stMidi.uData.stMem.ulNbLoops;
|
|
stActiveMidiTrack.ulTrackLengthInMs = SND_fn_ulGetMidiTrackLengthInMs(lIndexVoice);
|
|
}
|
|
else
|
|
{
|
|
// on a un ressource bouclante qui en est a son deuxieme tout minimum
|
|
if ((stActiveMidiTrack.bActive && stActiveMidiTrack.bLoop)&&
|
|
(stActiveMidiTrack.ulNbLoops != stMidiTracks[stActiveMidiTrack.lIndexVoice].pstPtr->uRes.stMidi.uData.stMem.ulNbLoops))
|
|
lVoice = stActiveMidiTrack.lVoice;
|
|
// on a une ressource pas bouclante mais il y a eu un play sans stop de la ressource precedente
|
|
else
|
|
{
|
|
// on arrete spontanement une voix, on doit reallouer la meme voie pour le haut niveau
|
|
lVoice = stActiveMidiTrack.lVoice;
|
|
SND_fn_vStopMidiThread(stActiveMidiTrack.lVoice);
|
|
goto debut;
|
|
}
|
|
|
|
}
|
|
if (stMidiTracks[lIndexVoice].pstPtr != NULL)
|
|
stActiveMidiTrack.uiMidiDeviceId = stMidiTracks[lIndexVoice].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId;
|
|
else
|
|
{
|
|
SND_fn_vDisplayError(E_uwSndMIDILoadTrack,"no unload before loading");
|
|
return (NO_MIDI_VOICE);
|
|
}
|
|
|
|
if (mciReturn=mciSendCommand(stActiveMidiTrack.uiMidiDeviceId,MCI_PLAY,MCI_NOTIFY|MCI_FROM,(DWORD)(LPVOID)&play))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIPlay,texte_erreur_Midi);
|
|
return (NO_MIDI_VOICE);
|
|
}
|
|
stActiveMidiTrack.bActive = TRUE;
|
|
stActiveMidiTrack.bPaused = FALSE;
|
|
stActiveMidiTrack.pstSoundParam = par;
|
|
stActiveMidiTrack.pfnSoundCallback=fn_callback;
|
|
stActiveMidiTrack.lParSoundCallback=par_callback;
|
|
return (lVoice | OFFSET_MIDI_VOICE);
|
|
}
|
|
return C_PLAY_FAILED;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_lPlayMidiWithFade
|
|
//
|
|
// But : Joue la ressource Midi 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_lPlayMidiWithFade(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_lPlayMidi(res,par,prio,fn_callback,par_callback);
|
|
SND_fn_ulInitFadeMidi(ulFadeIn,ulFadeOut);
|
|
return (result);
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_vStopMidi
|
|
//
|
|
// But : Stopper une voie
|
|
// Entrées : la voie a stopper
|
|
// Sorties : neant
|
|
//------------------------------------------------------------
|
|
void SND_CALL SND_fn_vStopMidi(long voice)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
HANDLE hEventSynchro;
|
|
dw_a5_Params[0] = (DWORD)voice;
|
|
|
|
if (stMidiDriver.bMidiDriverOk)
|
|
{
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
if (!PostThreadMessage(dwMidiThreadId,(UINT)SND_STOPMIDI_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDIStop,"PostThreadMessage");
|
|
|
|
WaitForSingleObject(hEventSynchro,INFINITE);
|
|
CloseHandle(hEventSynchro);
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
#ifndef DISABLE_MIDI
|
|
//-----------------------------------------------------------
|
|
// SND_fn_vStopMidiThread
|
|
//
|
|
// But : Stopper une voie
|
|
// Entrées : la voie a stopper
|
|
// Sorties : neant
|
|
//------------------------------------------------------------
|
|
void SND_fn_vStopMidiThread(long voice)
|
|
{
|
|
MCIERROR mciReturn;
|
|
MCI_GENERIC_PARMS stop;
|
|
SECURITY_ATTRIBUTES sa;
|
|
|
|
stop.dwCallback = (DWORD)hSndMidiWnd;
|
|
if (mciReturn=mciSendCommand(stActiveMidiTrack.uiMidiDeviceId,MCI_STOP,MCI_NOTIFY,(DWORD)&stop))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIStop,"Stopping Midi Error");
|
|
}
|
|
stActiveMidiTrack.lPrio = 0;
|
|
stActiveMidiTrack.lVoice = NO_MIDI_VOICE;
|
|
stActiveMidiTrack.uiMidiDeviceId = NO_MIDI_DEVICE;
|
|
stActiveMidiTrack.bPaused = FALSE;
|
|
stActiveMidiTrack.bActive = FALSE;
|
|
|
|
if (stActiveMidiTrack.pfnSoundCallback)
|
|
{
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.bInheritHandle = TRUE;
|
|
sa.lpSecurityDescriptor = NULL;
|
|
dw_a2_threadParams[0] = (DWORD)stActiveMidiTrack.pfnSoundCallback;
|
|
dw_a2_threadParams[1] = (DWORD)stActiveMidiTrack.lParSoundCallback;
|
|
if (!(hMidiThreadCallBack = CreateThread(&sa,0,(LPTHREAD_START_ROUTINE)SND_fn_iMidiThreadCallBack,(LPVOID)dw_a2_threadParams,0,&dwMidiThreadIdCallBack)))
|
|
SND_fn_vDisplayError(E_uwSndCDCreateThread,"");
|
|
}
|
|
stActiveMidiTrack.pfnSoundCallback = NULL;
|
|
stActiveMidiTrack.lParSoundCallback= 0;
|
|
stActiveMidiTrack.pstSoundParam = NULL;
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_vPauseMidi
|
|
//
|
|
// But : Pauser une voie
|
|
// Entrées : la voie a pauser
|
|
// Sorties : true,false
|
|
//------------------------------------------------------------
|
|
void SND_CALL SND_fn_vPauseMidi(long voice)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
HANDLE hEventSynchro;
|
|
dw_a5_Params[0] = (DWORD)voice;
|
|
|
|
if (stMidiDriver.bMidiDriverOk)
|
|
{
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
if (!PostThreadMessage(dwMidiThreadId,(UINT)SND_PAUSEMIDI_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDIStop,"PostThreadMessage Pause");
|
|
|
|
WaitForSingleObject(hEventSynchro,INFINITE);
|
|
CloseHandle(hEventSynchro);
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
#ifndef DISABLE_MIDI
|
|
//-----------------------------------------------------------
|
|
// SND_fn_vPauseMidiThread
|
|
//
|
|
// But : Pauser une voie
|
|
// Entrées : la voie a pauser
|
|
// Sorties : true,false
|
|
//------------------------------------------------------------
|
|
void SND_fn_vPauseMidiThread(long voice)
|
|
{
|
|
MCIERROR mciReturn;
|
|
MCI_GENERIC_PARMS pause;
|
|
|
|
pause.dwCallback = (DWORD)hSndMidiWnd;
|
|
|
|
if (mciReturn=mciSendCommand(stActiveMidiTrack.uiMidiDeviceId,MCI_STOP,MCI_NOTIFY,(DWORD)&pause))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIStop,texte_erreur_Midi);
|
|
return;
|
|
}
|
|
|
|
stActiveMidiTrack.bPaused = TRUE;
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_vResumeMidi
|
|
//
|
|
// But : Resumer une voie
|
|
// Entrées : la voie a resumer
|
|
// Sorties : True,false
|
|
//------------------------------------------------------------
|
|
void SND_CALL SND_fn_vResumeMidi(long voice)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
HANDLE hEventSynchro;
|
|
|
|
dw_a5_Params[0] = (DWORD)voice;
|
|
|
|
if (stMidiDriver.bMidiDriverOk)
|
|
{
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
if (!PostThreadMessage(dwMidiThreadId,(UINT)SND_RESUMEMIDI_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDIPlay,"PostThreadMessage Resume");
|
|
WaitForSingleObject(hEventSynchro,INFINITE);
|
|
CloseHandle(hEventSynchro);
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
|
|
#ifndef DISABLE_MIDI
|
|
//-----------------------------------------------------------
|
|
// SND_fn_vResumeMidi
|
|
//
|
|
// But : Resumer une voie
|
|
// Entrées : la voie a resumer
|
|
// Sorties : True,false
|
|
//------------------------------------------------------------
|
|
void SND_fn_vResumeMidiThread(long voice)
|
|
{
|
|
MCIERROR mciReturn;
|
|
MCI_GENERIC_PARMS resume;
|
|
MCI_PLAY_PARMS play;
|
|
|
|
resume.dwCallback = (DWORD)hSndMidiWnd;
|
|
play.dwCallback = (DWORD)hSndMidiWnd;
|
|
|
|
|
|
if (stActiveMidiTrack.bPaused)
|
|
if (mciReturn=mciSendCommand(stActiveMidiTrack.uiMidiDeviceId,MCI_PLAY,MCI_NOTIFY,(DWORD)&play))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIPlay,texte_erreur_Midi);
|
|
return;
|
|
}
|
|
stActiveMidiTrack.bPaused = FALSE;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_bLoadMidiTrack
|
|
//
|
|
// But : Charge une piste midi, a partir du block ressource
|
|
// Entrées : Le block ressource et le nom du fichier midi
|
|
// Sorties : true,false
|
|
//------------------------------------------------------------
|
|
SndBool SND_fn_bLoadMidiTrack(tdstBlockResourceMem * pstPtr,char *czFileName)
|
|
{
|
|
HANDLE hEventSynchro;
|
|
|
|
if (stMidiDriver.bMidiDriverOk)
|
|
{
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
dw_a5_Params[0] = (DWORD)pstPtr;
|
|
dw_a5_Params[1] = (DWORD)czFileName;
|
|
|
|
if (!PostThreadMessage(dwMidiThreadId,(UINT)SND_LOADMIDI_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDILoadTrack,"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_bLoadMidiTrackThread
|
|
//
|
|
// But : Charge une piste midi, a partir du block ressource
|
|
// Entrées : Le block ressource et le nom du fichier midi
|
|
// Sorties : true,false
|
|
//------------------------------------------------------------
|
|
SndBool SND_fn_bLoadMidiTrackThread(tdstBlockResourceMem * pstPtr,char *czFileName)
|
|
{
|
|
MCI_OPEN_PARMS open;
|
|
MCI_STATUS_PARMS status;
|
|
MCI_SET_PARMS set;
|
|
MCIERROR mciReturn;
|
|
int iNumTrack = 0;
|
|
|
|
// on cherche une track libre dans le tableau de stMidiTracks
|
|
while (stMidiTracks[iNumTrack].pstPtr != NULL)
|
|
{
|
|
if (iNumTrack > NB_MAX_MIDI_TRACKS)
|
|
{
|
|
// on en trouve pas
|
|
SND_fn_vDisplayError(E_uwSndMIDIAllTracksUsed,"");
|
|
return FALSE;
|
|
}
|
|
iNumTrack++;
|
|
}
|
|
// on en a trouve une
|
|
// on reference le bloc midi a la liste des pistes midi
|
|
|
|
stMidiTracks[iNumTrack].pstPtr = pstPtr;
|
|
open.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_SEQUENCER;
|
|
open.dwCallback = (DWORD)hSndMidiWnd;
|
|
SND_fn_vResolveFileName(czFileName,StrMidiDirectory);
|
|
//SND_fn_vGetDataDirectory(StrMidiDirectory,sizeof(StrMidiDirectory));
|
|
//strncat((LPSTR)StrMidiDirectory,(LPCSTR)czFileName,sizeof(StrMidiDirectory)-strlen(StrMidiDirectory));
|
|
open.lpstrElementName = (LPSTR)StrMidiDirectory;
|
|
|
|
if (mciReturn=mciSendCommand( stMidiTracks[iNumTrack].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId,
|
|
MCI_OPEN,
|
|
MCI_WAIT|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT,
|
|
(DWORD)(LPVOID)&open))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIOpen,texte_erreur_Midi);
|
|
return FALSE;
|
|
}
|
|
|
|
stMidiTracks[iNumTrack].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId = open.wDeviceID;
|
|
status.dwItem = MCI_SEQ_STATUS_PORT;
|
|
|
|
if (mciReturn=mciSendCommand(stMidiTracks[iNumTrack].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)(LPVOID)&status))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
stMidiDriver.bMidiDriverOk = FALSE;
|
|
SND_fn_vDisplayError(E_uwSndMIDIStatus,texte_erreur_Midi);
|
|
mciSendCommand(stMidiTracks[iNumTrack].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId,MCI_CLOSE,0,0);
|
|
return FALSE;
|
|
}
|
|
|
|
// Par défaut, l'unité de temps MIDI est la milliseconde
|
|
set.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
|
|
|
|
if (mciReturn=mciSendCommand( stMidiTracks[iNumTrack].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId,
|
|
MCI_SET,
|
|
MCI_SET_TIME_FORMAT,
|
|
(DWORD)(LPVOID)&set))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDISet,texte_erreur_Midi);
|
|
return FALSE;
|
|
}
|
|
|
|
// Par défaut, l'unité de temps MIDI est la milliseconde
|
|
status.dwItem = MCI_STATUS_LENGTH;
|
|
|
|
// On calcule la longueur de la piste en millisecondes
|
|
if (mciReturn=mciSendCommand( stMidiTracks[iNumTrack].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId,
|
|
MCI_STATUS,
|
|
MCI_STATUS_ITEM,
|
|
(DWORD)(LPVOID)&status))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIStatus,texte_erreur_Midi);
|
|
return FALSE;
|
|
}
|
|
stMidiTracks[iNumTrack].pstPtr->uRes.stMidi.uData.stMem.ulLength = status.dwReturn;
|
|
stMidiTracks[iNumTrack].pstPtr->uRes.stMidi.uData.stMem.ulNbLoops = pstPtr->uRes.stMidi.ulNbLoops;
|
|
iNbTracks = iNumTrack+1;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
SndBool SND_fn_bUnloadMidiRes(tduRefRes RR)
|
|
{
|
|
long voice = SND_fn_lGetMidiTrack(RR.pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId);
|
|
if (SND_fn_bUnloadMidiTrack(voice))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
*/
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_bUnloadMidiTrack
|
|
//
|
|
// But : Decharge une piste midi, a partir de la voie
|
|
// Entrées : La voie a decharger
|
|
// Sorties : true,false
|
|
//------------------------------------------------------------
|
|
SndBool SND_fn_bUnloadMidiTrack(long lVoice)
|
|
{
|
|
HANDLE hEventSynchro;
|
|
|
|
if (stMidiDriver.bMidiDriverOk)
|
|
{
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
dw_a5_Params[0] = (DWORD)lVoice;
|
|
|
|
if (!PostThreadMessage(dwMidiThreadId,(UINT)SND_UNLOADMIDI_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDIUnloadTrack,"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_bUnloadMidiTrack
|
|
//
|
|
// But : Decharge une piste midi, a partir de la voie
|
|
// Entrées : La voie a decharger
|
|
// Sorties : true,false
|
|
//------------------------------------------------------------
|
|
SndBool SND_fn_bUnloadMidiTrackThread(long lVoice)
|
|
{
|
|
MCIERROR mciReturn;
|
|
|
|
if ((lVoice < NB_MAX_MIDI_TRACKS)&&
|
|
(stMidiTracks[lVoice].pstPtr != NULL))
|
|
{
|
|
if ((stMidiTracks[lVoice].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId != NO_MIDI_DEVICE)&&
|
|
(stMidiTracks[lVoice].pstPtr->bIsLoaded))
|
|
{
|
|
if (mciReturn=mciSendCommand(stMidiTracks[lVoice].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId,MCI_CLOSE,0,0))
|
|
{
|
|
mciGetErrorString(mciReturn,texte_erreur_Midi,sizeof(texte_erreur_Midi));
|
|
SND_fn_vDisplayError(E_uwSndMIDIClose,texte_erreur_Midi);
|
|
return FALSE;
|
|
}
|
|
stMidiTracks[lVoice].pstPtr->uRes.stMidi.uData.stMem.uiMidiDeviceId= NO_MIDI_DEVICE;
|
|
stMidiTracks[lVoice].pstPtr = NULL;
|
|
iNbTracks--;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
#endif //DISABLE_MIDI
|
|
|
|
|
|
void SND_CALL SND_fn_vUnLoadResMidi(tdstBlockResourceMem *mem)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
long voice = SND_fn_lGetMidiTrack(mem->uRes.stMidi.uData.stMem.uiMidiDeviceId);
|
|
SND_fn_bUnloadMidiTrack(voice);
|
|
mem->eType = TYPE_INVALID;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// SND_fn_bIsResLoadedMidi
|
|
//
|
|
// Goal : Tell if the binary data associated with a midi resource are loaded.
|
|
// Input : The block Resource to test
|
|
// Output : true,false
|
|
//------------------------------------------------------------
|
|
|
|
SndBool SND_CALL SND_fn_bIsResLoadedMidi(tdstBlockResourceMem* _pBRMem)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
if (_pBRMem->uRes.stMidi.bStream)
|
|
return TRUE;// Streaming sample is always "loaded"
|
|
else
|
|
return (_pBRMem->uRes.stMidi.uData.stMem.uiMidiDeviceId!=NO_MIDI_DEVICE);
|
|
#else
|
|
return FALSE;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
/*
|
|
void SND_CALL SND_fn_vSetResUnloadedMidi(tdstBlockResourceMem *pResMem)
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
pResMem->uRes.stMidi.bStream=FALSE;
|
|
pResMem->uRes.stMidi.uData.stMem.uiMidiDeviceId=NO_MIDI_DEVICE;
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
#ifndef DISABLE_MIDI
|
|
|
|
//#endif //MIDI_MCI
|
|
|
|
int SND_fn_iMixerInitMidi(void)
|
|
{
|
|
uiNbrMixersMidi = mixerGetNumDevs(); //OK
|
|
if (uiNbrMixersMidi == 0)
|
|
{
|
|
SND_fn_vDisplayError(E_uwSndMixerNoMixer,"");
|
|
return 1;
|
|
}
|
|
|
|
if(mixerGetID((HMIXEROBJ)0,&mixerIdentifierMidi,MIXER_OBJECTF_MIXER) !=MMSYSERR_NOERROR)
|
|
{
|
|
SND_fn_vDisplayError(E_uwSndMixerNoId,"");
|
|
return 1;
|
|
}
|
|
|
|
|
|
if(mixerOpen(&hMixerMidi,mixerIdentifierMidi,0,0,MIXER_OBJECTF_MIXER/* MIXER_OBJECTF_HWAVEOUT*/) != MMSYSERR_NOERROR)
|
|
{
|
|
SND_fn_vDisplayError(E_uwSndMixerOpen,"");
|
|
return 1;
|
|
}
|
|
|
|
if(mixerGetDevCaps((UINT)hMixerMidi,&mixerCapsMidi,sizeof(MIXERCAPS)) != MMSYSERR_NOERROR)
|
|
{
|
|
SND_fn_vDisplayError(E_uwSndMixerCapacities,"");
|
|
return 1;
|
|
}
|
|
|
|
dwNbrAudioLinesMidi = mixerCapsMidi.cDestinations;
|
|
|
|
//==================
|
|
// MIXERLINE MIDI
|
|
//==================
|
|
|
|
mixerLineMidi.cbStruct = sizeof(MIXERLINE);
|
|
mixerLineMidi.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
|
|
if (mixerGetLineInfo((HMIXEROBJ)hMixerMidi,&mixerLineMidi,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR)
|
|
{
|
|
//return MIXER_ERR_GETLINEINFOSAMPLE;
|
|
MidiControlAvailable = FALSE;
|
|
}
|
|
else
|
|
{
|
|
MidiControlAvailable = TRUE;
|
|
}
|
|
|
|
//======================
|
|
// MIXERLINECONTROL MIDI
|
|
//======================
|
|
mixerLineControlsMidi.cbStruct = sizeof(MIXERLINECONTROLS);
|
|
mixerLineControlsMidi.dwLineID = mixerLineMidi.dwLineID;
|
|
mixerLineControlsMidi.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
|
|
mixerLineControlsMidi.cControls = 1;
|
|
mixerLineControlsMidi.cbmxctrl = sizeof(MIXERCONTROL);
|
|
mixerLineControlsMidi.pamxctrl =(MIXERCONTROL *) &mixerControlMidi;
|
|
if(mixerGetLineControls((HMIXEROBJ)hMixerMidi,&mixerLineControlsMidi,MIXER_GETLINECONTROLSF_ONEBYTYPE|MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR)
|
|
MidiControlAvailable = FALSE;
|
|
else
|
|
MidiControlAvailable = TRUE;
|
|
|
|
|
|
//=============================
|
|
// MIXERLINECONTROLDETAILS MIDI
|
|
//=============================
|
|
mixerControlDetailsMidi.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
|
mixerControlDetailsMidi.dwControlID = mixerControlMidi.dwControlID;
|
|
mixerControlDetailsMidi.cChannels = 1/*mixerLineMidi.cChannels 1*/;
|
|
mixerControlDetailsMidi.cMultipleItems = mixerControlMidi.cMultipleItems;
|
|
mixerControlDetailsMidi.cbDetails =sizeof(MIXERCONTROLDETAILS_UNSIGNED);
|
|
mixerControlDetailsMidi.paDetails= &valeurMidi;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
DWORD SND_fn_dwGetMidiMax(void)
|
|
{
|
|
return mixerControlMidi.Bounds.dwMaximum;
|
|
}
|
|
DWORD SND_fn_dwGetMidiMin(void)
|
|
{
|
|
return mixerControlMidi.Bounds.dwMinimum;
|
|
}
|
|
|
|
//=======================================
|
|
// void SND_fn_vSetMidiValue(DWORD val)
|
|
//=======================================
|
|
// Positionne le volume du Midi en %
|
|
// val entre 0 et 100
|
|
//=======================================
|
|
void SND_fn_vSetMidiValue(DWORD val)
|
|
{
|
|
DWORD inc;
|
|
|
|
if (MidiControlAvailable)
|
|
{
|
|
//snd_assert(val>=0);
|
|
snd_assert(val<=100);
|
|
|
|
inc = (SND_fn_dwGetMidiMax()-SND_fn_dwGetMidiMin())/100;
|
|
val = (val* inc) + SND_fn_dwGetMidiMin();
|
|
|
|
snd_assert(val>=SND_fn_dwGetMidiMin());
|
|
snd_assert(val<=SND_fn_dwGetMidiMax());
|
|
|
|
valeurMidi.dwValue = val;
|
|
|
|
if(mixerSetControlDetails((HMIXEROBJ)hMixerMidi,&mixerControlDetailsMidi,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR)
|
|
{
|
|
//return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=================================
|
|
// SND_fn_dwGetMidiValue
|
|
//=================================
|
|
// Retourne la valeur du mixer Midi
|
|
// en %
|
|
//=================================
|
|
DWORD SND_fn_dwGetMidiValue(void)
|
|
{
|
|
DWORD inc;
|
|
DWORD result;
|
|
|
|
if (MidiControlAvailable)
|
|
{
|
|
inc = (SND_fn_dwGetMidiMax()-SND_fn_dwGetMidiMin())/100;
|
|
|
|
if(mixerGetControlDetails((HMIXEROBJ)hMixerMidi,&mixerControlDetailsMidi,MIXER_GETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
result = (valeurMidi.dwValue - SND_fn_dwGetMidiMin())/inc;
|
|
|
|
//snd_assert(result>=0);
|
|
snd_assert(result<=100);
|
|
return result;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
BOOL SND_fn_bIsMidiControlAvailable(void)
|
|
{
|
|
return MidiControlAvailable;
|
|
}
|
|
|
|
|
|
int SND_fn_iMixerDesInitMidi(void)
|
|
{
|
|
if(mixerClose(hMixerMidi) != MMSYSERR_NOERROR)
|
|
{
|
|
SND_fn_vDisplayError(E_uwSndMixerDesinit,"");
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif //DISABLE_MIDI
|
|
|
|
#ifndef NO_ACP_LDBIN
|
|
SndBool SND_CALL SND_fn_bCanFreeDataMidi(void)
|
|
{
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*--------------------------------------------------
|
|
relache-reprise a chaud des drives
|
|
---------------------------------------------------------*/
|
|
#define PAUSED_BY_RESTORE_RELEASE 2
|
|
|
|
void SND_CALL SND_fn_vReleaseDriverMidiThread()
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
if (! stActiveMidiTrack.bPaused)
|
|
{
|
|
SND_fn_vPauseMidiThread(stActiveMidiTrack.lVoice);
|
|
stActiveMidiTrack.bPaused = (BOOL)PAUSED_BY_RESTORE_RELEASE;
|
|
}
|
|
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
void SND_CALL SND_fn_vReleaseDriverMidi()
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
HANDLE hEventSynchro;
|
|
|
|
if (stMidiDriver.bMidiDriverOk && stActiveMidiTrack.bActive)
|
|
{
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
if (!PostThreadMessage(dwMidiThreadId,(UINT)SND_RELEASEMIDI_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDIStop,"PostThreadMessage Release");
|
|
|
|
WaitForSingleObject(hEventSynchro,INFINITE);
|
|
CloseHandle(hEventSynchro);
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
void SND_CALL SND_fn_vRestoreDriverMidiThread()
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
if (stActiveMidiTrack.bPaused == (BOOL)PAUSED_BY_RESTORE_RELEASE)
|
|
SND_fn_vResumeMidiThread(stActiveMidiTrack.lVoice);
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
void SND_CALL SND_fn_vRestoreDriverMidi()
|
|
{
|
|
#ifndef DISABLE_MIDI
|
|
HANDLE hEventSynchro;
|
|
|
|
if (stMidiDriver.bMidiDriverOk && stActiveMidiTrack.bActive)
|
|
{
|
|
hEventSynchro = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
if (!PostThreadMessage(dwMidiThreadId,(UINT)SND_RESTOREMIDI_MSG,(WPARAM)dw_a5_Params,(LPARAM)hEventSynchro))
|
|
SND_fn_vDisplayError(E_uwSndMIDIStop,"PostThreadMessage Restore");
|
|
|
|
WaitForSingleObject(hEventSynchro,INFINITE);
|
|
CloseHandle(hEventSynchro);
|
|
}
|
|
#endif //DISABLE_MIDI
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// 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_rGetPosMidi(long voie)
|
|
{
|
|
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_rGetLengthMidi(long voie)
|
|
{
|
|
return SND_C_POS_UNKNOWN;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// Fonction de synchro moteur
|
|
// ne sert à rien pour Midi
|
|
//-------------------------------------------------
|
|
void SND_CALL SND_fn_vSynchroMidi()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// Fonctions pour thems NON IMPLEMENTéES
|
|
//------------------------------------------------------
|
|
|
|
static tduRefRes s_CurrentMidiThemeRes={0};
|
|
static long s_lCurrentMidiThemeVoice;
|
|
static tduRefRes s_NextMidiThemeRes={0};
|
|
static SND_td_pfn_vSoundCallback s_pfnThemeTransitionCB;
|
|
static long s_lThemeTransitionCBParam;
|
|
static SndBool s_bChangingTheme=FALSE;
|
|
void SND_CALL fn_MidiThemeTransition(long par)
|
|
{
|
|
// A midi theme part just ended (either normally, or it was ended).
|
|
// s_bChangingTheme is true when a transition is forced.
|
|
if (s_bChangingTheme==TRUE)
|
|
{
|
|
s_bChangingTheme=FALSE;
|
|
s_lCurrentMidiThemeVoice=
|
|
SND_fn_lPlayMidi(s_CurrentMidiThemeRes,(SoundParam *)par,0,fn_MidiThemeTransition,par);
|
|
if (s_NextMidiThemeRes.pstPtr==NULL)
|
|
s_pfnThemeTransitionCB(s_lThemeTransitionCBParam);
|
|
return;
|
|
}
|
|
s_CurrentMidiThemeRes=s_NextMidiThemeRes;
|
|
if (s_CurrentMidiThemeRes.pstPtr!=NULL)
|
|
{
|
|
s_lCurrentMidiThemeVoice=
|
|
SND_fn_lPlayMidi(s_CurrentMidiThemeRes,(SoundParam *)par,0,fn_MidiThemeTransition,par);
|
|
s_pfnThemeTransitionCB(s_lThemeTransitionCBParam);
|
|
}
|
|
}
|
|
|
|
long SND_CALL SND_fn_lPlayTransitionMidi(tduRefRes FirstRes,tduRefRes NextRes,SND_td_pfn_vSoundCallback transition_callback,long param_callback,SoundParam* par)
|
|
{
|
|
if (s_CurrentMidiThemeRes.pstPtr!=NULL) s_bChangingTheme=TRUE;
|
|
else s_bChangingTheme=FALSE;
|
|
|
|
s_CurrentMidiThemeRes=FirstRes;
|
|
s_NextMidiThemeRes=NextRes;
|
|
s_pfnThemeTransitionCB=transition_callback;
|
|
s_lThemeTransitionCBParam=param_callback;
|
|
|
|
// If a theme is already playing, stopping the current part will trigger the midi CB,
|
|
// and start the next part.
|
|
// Otherwise, we must launch the first part...
|
|
if (s_bChangingTheme==TRUE)
|
|
SND_fn_vStopMidi(s_lCurrentMidiThemeVoice); // stop current midi part
|
|
else
|
|
{
|
|
s_lCurrentMidiThemeVoice=
|
|
SND_fn_lPlayMidi(s_CurrentMidiThemeRes,par,0,fn_MidiThemeTransition,(long)par);
|
|
}
|
|
|
|
return s_lCurrentMidiThemeVoice;
|
|
}
|
|
|
|
|
|
SndBool SND_CALL SND_fn_bSetParamTransitionMidi(long voice,SoundParam* par)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
SndBool SND_CALL SND_fn_bSetNextTransitionMidi(long voice,tduRefRes new_res)
|
|
{
|
|
s_NextMidiThemeRes=new_res;
|
|
return TRUE;
|
|
}
|
|
|
|
void SND_CALL SND_fn_vStopTransitionMidi(long voice)
|
|
{
|
|
s_NextMidiThemeRes.pstPtr=NULL;
|
|
if (s_CurrentMidiThemeRes.pstPtr!=NULL)
|
|
SND_fn_vStopMidi(s_lCurrentMidiThemeVoice); // stop current midi part
|
|
}
|
|
|
|
void SND_CALL SND_fn_vResumeTransitionMidi(long voice)
|
|
{
|
|
if (s_CurrentMidiThemeRes.pstPtr!=NULL) SND_fn_vResumeMidi(s_lCurrentMidiThemeVoice);
|
|
}
|
|
|
|
void SND_CALL SND_fn_vPauseTransitionMidi(long voice)
|
|
{
|
|
if (s_CurrentMidiThemeRes.pstPtr!=NULL) SND_fn_vPauseMidi(s_lCurrentMidiThemeVoice);
|
|
}
|
|
|
|
SndBool SND_CALL SND_fn_bDoTransitionWithFadeMidi(long voice,tduRefRes new_res)
|
|
{
|
|
s_bChangingTheme=TRUE;
|
|
s_CurrentMidiThemeRes=new_res;
|
|
s_NextMidiThemeRes.pstPtr=NULL;
|
|
SND_fn_vStopMidi(s_lCurrentMidiThemeVoice); // stop current midi part
|
|
return TRUE;
|
|
}
|
|
|
|
SndBool SND_CALL SND_fn_bDoTransitionWithFadeMidi2( long voice, tduRefRes new_res, SndReal rDuration )
|
|
{
|
|
s_bChangingTheme=TRUE;
|
|
s_CurrentMidiThemeRes=new_res;
|
|
s_NextMidiThemeRes.pstPtr=NULL;
|
|
SND_fn_vStopMidi(s_lCurrentMidiThemeVoice); // stop current midi part
|
|
return TRUE;
|
|
}
|
|
|
|
SndBool SND_CALL SND_fn_bCheckVersionResourceMidi(tdstBlockResourceDisk* disk)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
SndBool SND_CALL SND_fn_bSetResourceStaticVolumeMidi(tdstBlockResourceMem* pstRes,unsigned char ucVolume)
|
|
{
|
|
pstRes->ucVolume=ucVolume;
|
|
|
|
return TRUE;
|
|
}
|
|
|