gps/GPSResources/tcpmpVerOld/mikmod/libmikmod/drivers/drv_ds.c

385 lines
9.5 KiB
C
Executable File

/* MikMod sound library
(c) 1998-2001 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: drv_ds.c,v 1.3 2004/01/31 22:39:40 raph Exp $
Driver for output on win32 platforms using DirectSound
==============================================================================*/
/*
Written by Brian McKinney <Brian.McKinney@colorado.edu>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
#ifdef DRV_DS
#include <memory.h>
#include <string.h>
#define INITGUID
#include <dsound.h>
/* DSBCAPS_CTRLALL is not defined anymore with DirectX 7. Of course DirectSound
is a coherent, backwards compatible API... */
#ifndef DSBCAPS_CTRLALL
#define DSBCAPS_CTRLALL ( DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLVOLUME | \
DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | \
DSBCAPS_CTRL3D )
#endif
/* size of each buffer */
#define FRAGSIZE 16
/* buffer count */
#define UPDATES 2
static LPDIRECTSOUND pSoundCard = NULL;
static LPDIRECTSOUNDBUFFER pPrimarySoundBuffer = NULL, pSoundBuffer = NULL;
static LPDIRECTSOUNDNOTIFY pSoundBufferNotify = NULL;
static HANDLE notifyUpdateHandle = 0, updateBufferHandle = 0;
static BOOL threadInUse = FALSE;
static int fragsize=1<<FRAGSIZE;
static DWORD controlflags = DSBCAPS_CTRLALL & ~DSBCAPS_GLOBALFOCUS;
#define SAFE_RELEASE(p) \
do { \
if (p) { \
if ((p)->lpVtbl) { \
(p)->lpVtbl->Release(p); \
(p) = NULL; \
} \
} \
} while (0)
static DWORD WINAPI updateBufferProc(LPVOID lpParameter)
{
LPVOID pBlock1 = NULL, pBlock2 = NULL;
DWORD soundBufferCurrentPosition, blockBytes1, blockBytes2;
DWORD start;
while (threadInUse) {
if (WaitForSingleObject(notifyUpdateHandle,INFINITE)==WAIT_OBJECT_0) {
if (!threadInUse) break;
pSoundBuffer->lpVtbl->GetCurrentPosition
(pSoundBuffer,&soundBufferCurrentPosition,NULL);
if (soundBufferCurrentPosition < fragsize)
start = fragsize;
else
start = 0;
if (pSoundBuffer->lpVtbl->Lock
(pSoundBuffer,start,fragsize,&pBlock1,&blockBytes1,
&pBlock2,&blockBytes2,0)==DSERR_BUFFERLOST) {
pSoundBuffer->lpVtbl->Restore(pSoundBuffer);
pSoundBuffer->lpVtbl->Lock
(pSoundBuffer,start,fragsize,&pBlock1,&blockBytes1,
&pBlock2,&blockBytes2,0);
}
MUTEX_LOCK(vars);
if (Player_Paused_internal()) {
VC_SilenceBytes((SBYTE*)pBlock1,(ULONG)blockBytes1);
if (pBlock2)
VC_SilenceBytes((SBYTE*)pBlock2,(ULONG)blockBytes2);
} else {
VC_WriteBytes((SBYTE*)pBlock1,(ULONG)blockBytes1);
if (pBlock2)
VC_WriteBytes((SBYTE*)pBlock2,(ULONG)blockBytes2);
}
MUTEX_UNLOCK(vars);
pSoundBuffer->lpVtbl->Unlock
(pSoundBuffer,pBlock1,blockBytes1,pBlock2,blockBytes2);
}
}
return 0;
}
static void DS_CommandLine(CHAR *cmdline)
{
CHAR *ptr=MD_GetAtom("buffer",cmdline,0);
if (ptr) {
int buf=atoi(ptr);
if ((buf<12)||(buf>19)) buf=FRAGSIZE;
fragsize=1<<buf;
free(ptr);
}
if ((ptr=MD_GetAtom("globalfocus",cmdline,1))) {
controlflags |= DSBCAPS_GLOBALFOCUS;
free(ptr);
} else
controlflags &= ~DSBCAPS_GLOBALFOCUS;
}
static BOOL DS_IsPresent(void)
{
if(DirectSoundCreate(NULL,&pSoundCard,NULL)!=DS_OK)
return 0;
SAFE_RELEASE(pSoundCard);
return 1;
}
static BOOL DS_Init(void)
{
DSBUFFERDESC soundBufferFormat;
WAVEFORMATEX pcmwf;
DSBPOSITIONNOTIFY positionNotifications[2];
DWORD updateBufferThreadID;
if (DirectSoundCreate(NULL,&pSoundCard,NULL)!=DS_OK) {
_mm_errno=MMERR_OPENING_AUDIO;
return 1;
}
if (pSoundCard->lpVtbl->SetCooperativeLevel
(pSoundCard,GetForegroundWindow(),DSSCL_PRIORITY)!=DS_OK) {
_mm_errno=MMERR_DS_PRIORITY;
return 1;
}
memset(&soundBufferFormat,0,sizeof(DSBUFFERDESC));
soundBufferFormat.dwSize =sizeof(DSBUFFERDESC);
soundBufferFormat.dwFlags =DSBCAPS_PRIMARYBUFFER;
soundBufferFormat.dwBufferBytes=0;
soundBufferFormat.lpwfxFormat =NULL;
if (pSoundCard->lpVtbl->CreateSoundBuffer
(pSoundCard,&soundBufferFormat,&pPrimarySoundBuffer,NULL)!=DS_OK) {
_mm_errno=MMERR_DS_BUFFER;
return 1;
}
memset(&pcmwf,0,sizeof(WAVEFORMATEX));
pcmwf.wFormatTag =WAVE_FORMAT_PCM;
pcmwf.nChannels =(md_mode&DMODE_STEREO)?2:1;
pcmwf.nSamplesPerSec =md_mixfreq;
pcmwf.wBitsPerSample =(md_mode&DMODE_16BITS)?16:8;
pcmwf.nBlockAlign =(pcmwf.wBitsPerSample * pcmwf.nChannels) / 8;
pcmwf.nAvgBytesPerSec=pcmwf.nSamplesPerSec*pcmwf.nBlockAlign;
if (pPrimarySoundBuffer->lpVtbl->SetFormat
(pPrimarySoundBuffer,&pcmwf)!=DS_OK) {
_mm_errno=MMERR_DS_FORMAT;
return 1;
}
pPrimarySoundBuffer->lpVtbl->Play(pPrimarySoundBuffer,0,0,DSBPLAY_LOOPING);
memset(&soundBufferFormat,0,sizeof(DSBUFFERDESC));
soundBufferFormat.dwSize =sizeof(DSBUFFERDESC);
soundBufferFormat.dwFlags =controlflags|DSBCAPS_GETCURRENTPOSITION2 ;
soundBufferFormat.dwBufferBytes=fragsize*UPDATES;
soundBufferFormat.lpwfxFormat =&pcmwf;
if (pSoundCard->lpVtbl->CreateSoundBuffer
(pSoundCard,&soundBufferFormat,&pSoundBuffer,NULL)!=DS_OK) {
_mm_errno=MMERR_DS_BUFFER;
return 1;
}
pSoundBuffer->lpVtbl->QueryInterface
(pSoundBuffer,&IID_IDirectSoundNotify,(LPVOID*)&pSoundBufferNotify);
if (!pSoundBufferNotify) {
_mm_errno=MMERR_DS_NOTIFY;
return 1;
}
notifyUpdateHandle=CreateEvent
(NULL,FALSE,FALSE,"libmikmod DirectSound Driver positionNotify Event");
if (!notifyUpdateHandle) {
_mm_errno=MMERR_DS_EVENT;
return 1;
}
updateBufferHandle=CreateThread
(NULL,0,updateBufferProc,NULL,CREATE_SUSPENDED,&updateBufferThreadID);
if (!updateBufferHandle) {
_mm_errno=MMERR_DS_THREAD;
return 1;
}
memset(positionNotifications,0,2*sizeof(DSBPOSITIONNOTIFY));
positionNotifications[0].dwOffset =0;
positionNotifications[0].hEventNotify=notifyUpdateHandle;
positionNotifications[1].dwOffset =fragsize;
positionNotifications[1].hEventNotify=notifyUpdateHandle;
if (pSoundBufferNotify->lpVtbl->SetNotificationPositions
(pSoundBufferNotify,2,positionNotifications) != DS_OK) {
_mm_errno=MMERR_DS_UPDATE;
return 1;
}
return VC_Init();
}
static void DS_Exit(void)
{
DWORD statusInfo;
if(updateBufferHandle) {
/* Signal thread to exit and wait for the exit */
if (threadInUse) {
threadInUse = 0;
MUTEX_UNLOCK(vars);
SetEvent (notifyUpdateHandle);
WaitForSingleObject (updateBufferHandle, INFINITE);
MUTEX_LOCK(vars);
}
CloseHandle(updateBufferHandle),
updateBufferHandle = 0;
}
if (notifyUpdateHandle) {
CloseHandle(notifyUpdateHandle),
notifyUpdateHandle = 0;
}
SAFE_RELEASE(pSoundBufferNotify);
if(pSoundBuffer) {
if(pSoundBuffer->lpVtbl->GetStatus(pSoundBuffer,&statusInfo)==DS_OK)
if(statusInfo&DSBSTATUS_PLAYING)
pSoundBuffer->lpVtbl->Stop(pSoundBuffer);
SAFE_RELEASE(pSoundBuffer);
}
if(pPrimarySoundBuffer) {
if(pPrimarySoundBuffer->lpVtbl->GetStatus
(pPrimarySoundBuffer,&statusInfo)==DS_OK)
if(statusInfo&DSBSTATUS_PLAYING)
pPrimarySoundBuffer->lpVtbl->Stop(pPrimarySoundBuffer);
SAFE_RELEASE(pPrimarySoundBuffer);
}
SAFE_RELEASE(pSoundCard);
VC_Exit();
}
static BOOL do_update = 0;
static void DS_Update(void)
{
LPVOID block;
DWORD bBytes;
/* Do first update in DS_Update() to be consistent with other
non threaded drivers. */
if (do_update && pSoundBuffer) {
do_update = 0;
if (pSoundBuffer->lpVtbl->Lock (pSoundBuffer, 0, fragsize,
&block, &bBytes, NULL, NULL, 0)
== DSERR_BUFFERLOST) {
pSoundBuffer->lpVtbl->Restore (pSoundBuffer);
pSoundBuffer->lpVtbl->Lock (pSoundBuffer, 0, fragsize,
&block, &bBytes, NULL, NULL, 0);
}
if (Player_Paused_internal()) {
VC_SilenceBytes ((SBYTE *)block, (ULONG)bBytes);
} else {
VC_WriteBytes ((SBYTE *)block, (ULONG)bBytes);
}
pSoundBuffer->lpVtbl->Unlock (pSoundBuffer, block, bBytes, NULL, 0);
pSoundBuffer->lpVtbl->SetCurrentPosition(pSoundBuffer, 0);
pSoundBuffer->lpVtbl->Play(pSoundBuffer, 0, 0, DSBPLAY_LOOPING);
threadInUse=1;
ResumeThread (updateBufferHandle);
}
}
static void DS_PlayStop(void)
{
do_update = 0;
if (pSoundBuffer)
pSoundBuffer->lpVtbl->Stop(pSoundBuffer);
VC_PlayStop();
}
static BOOL DS_PlayStart(void)
{
do_update = 1;
return VC_PlayStart();
}
MIKMODAPI MDRIVER drv_ds=
{
NULL,
"DirectSound",
"DirectSound Driver (DX6+) v0.4",
0,255,
"ds",
"buffer:r:12,19,16:Audio buffer log2 size\n"
"globalfocus:b:0:Play if window does not have the focus\n",
DS_CommandLine,
DS_IsPresent,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
DS_Init,
DS_Exit,
NULL,
VC_SetNumVoices,
DS_PlayStart,
DS_PlayStop,
DS_Update,
NULL,
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
#else
MISSING(drv_ds);
#endif
/* ex:set ts=4: */