reman3/Rayman_X/cpa/tempgrp/SND_OLD/src/Win95/sndmidi.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;
}