Alibek Omarov
7 years ago
4 changed files with 277 additions and 486 deletions
@ -1,483 +0,0 @@
@@ -1,483 +0,0 @@
|
||||
/*
|
||||
s_backend.c - sound hardware output |
||||
Copyright (C) 2009 Uncle Mike |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 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 General Public License for more details. |
||||
*/ |
||||
|
||||
#include "common.h" |
||||
#include "sound.h" |
||||
#include <dsound.h> |
||||
|
||||
#define iDirectSoundCreate( a, b, c ) pDirectSoundCreate( a, b, c ) |
||||
|
||||
static HRESULT ( _stdcall *pDirectSoundCreate)(GUID* lpGUID, LPDIRECTSOUND* lpDS, IUnknown* pUnkOuter ); |
||||
|
||||
static dllfunc_t dsound_funcs[] = |
||||
{ |
||||
{ "DirectSoundCreate", (void **) &pDirectSoundCreate }, |
||||
{ NULL, NULL } |
||||
}; |
||||
|
||||
dll_info_t dsound_dll = { "dsound.dll", dsound_funcs, false }; |
||||
|
||||
#define SAMPLE_16BIT_SHIFT 1 |
||||
#define SECONDARY_BUFFER_SIZE 0x10000 |
||||
|
||||
typedef enum |
||||
{ |
||||
SIS_SUCCESS, |
||||
SIS_FAILURE, |
||||
SIS_NOTAVAIL |
||||
} si_state_t; |
||||
|
||||
static qboolean snd_firsttime = true; |
||||
static qboolean primary_format_set; |
||||
static HWND snd_hwnd; |
||||
|
||||
/*
|
||||
======================================================================= |
||||
Global variables. Must be visible to window-procedure function |
||||
so it can unlock and free the data block after it has been played. |
||||
======================================================================= |
||||
*/ |
||||
static DWORD locksize; |
||||
static HPSTR lpData, lpData2; |
||||
static DWORD gSndBufSize; |
||||
static MMTIME mmstarttime; |
||||
static LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf; |
||||
static LPDIRECTSOUND pDS; |
||||
|
||||
qboolean SNDDMA_InitDirect( void *hInst ); |
||||
void SNDDMA_FreeSound( void ); |
||||
|
||||
static const char *DSoundError( int error ) |
||||
{ |
||||
switch( error ) |
||||
{ |
||||
case DSERR_BUFFERLOST: |
||||
return "buffer is lost"; |
||||
case DSERR_INVALIDCALL: |
||||
return "invalid call"; |
||||
case DSERR_INVALIDPARAM: |
||||
return "invalid param"; |
||||
case DSERR_PRIOLEVELNEEDED: |
||||
return "invalid priority level"; |
||||
} |
||||
|
||||
return "unknown error"; |
||||
} |
||||
|
||||
/*
|
||||
================== |
||||
DS_CreateBuffers |
||||
================== |
||||
*/ |
||||
static qboolean DS_CreateBuffers( void *hInst ) |
||||
{ |
||||
WAVEFORMATEX pformat, format; |
||||
DSBCAPS dsbcaps; |
||||
DSBUFFERDESC dsbuf; |
||||
|
||||
memset( &format, 0, sizeof( format )); |
||||
format.wFormatTag = WAVE_FORMAT_PCM; |
||||
format.nChannels = 2; |
||||
format.wBitsPerSample = 16; |
||||
format.nSamplesPerSec = SOUND_DMA_SPEED; |
||||
format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; |
||||
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; |
||||
format.cbSize = 0; |
||||
|
||||
if( pDS->lpVtbl->SetCooperativeLevel( pDS, hInst, DSSCL_EXCLUSIVE ) != DS_OK ) |
||||
{ |
||||
Con_DPrintf( S_ERROR "DirectSound: failed to set EXCLUSIVE coop level\n" ); |
||||
SNDDMA_FreeSound(); |
||||
return false; |
||||
} |
||||
|
||||
// get access to the primary buffer, if possible, so we can set the sound hardware format
|
||||
memset( &dsbuf, 0, sizeof( dsbuf )); |
||||
dsbuf.dwSize = sizeof( DSBUFFERDESC ); |
||||
dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER; |
||||
dsbuf.dwBufferBytes = 0; |
||||
dsbuf.lpwfxFormat = NULL; |
||||
|
||||
memset( &dsbcaps, 0, sizeof( dsbcaps )); |
||||
dsbcaps.dwSize = sizeof( dsbcaps ); |
||||
primary_format_set = false; |
||||
|
||||
if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSPBuf, NULL ) == DS_OK ) |
||||
{ |
||||
pformat = format; |
||||
|
||||
if( pDSPBuf->lpVtbl->SetFormat( pDSPBuf, &pformat ) != DS_OK ) |
||||
{ |
||||
if( snd_firsttime ) |
||||
Con_DPrintf( S_ERROR "DirectSound: failed to set primary sound format\n" ); |
||||
} |
||||
else |
||||
{ |
||||
primary_format_set = true; |
||||
} |
||||
} |
||||
|
||||
// create the secondary buffer we'll actually work with
|
||||
memset( &dsbuf, 0, sizeof( dsbuf )); |
||||
dsbuf.dwSize = sizeof( DSBUFFERDESC ); |
||||
dsbuf.dwFlags = (DSBCAPS_CTRLFREQUENCY|DSBCAPS_LOCSOFTWARE); |
||||
dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE; |
||||
dsbuf.lpwfxFormat = &format; |
||||
|
||||
memset( &dsbcaps, 0, sizeof( dsbcaps )); |
||||
dsbcaps.dwSize = sizeof( dsbcaps ); |
||||
|
||||
if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSBuf, NULL ) != DS_OK ) |
||||
{ |
||||
// couldn't get hardware, fallback to software.
|
||||
dsbuf.dwFlags = (DSBCAPS_LOCSOFTWARE|DSBCAPS_GETCURRENTPOSITION2); |
||||
|
||||
if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSBuf, NULL ) != DS_OK ) |
||||
{ |
||||
Con_DPrintf( S_ERROR "DirectSound: failed to create secondary buffer\n" ); |
||||
SNDDMA_FreeSound (); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
if( pDSBuf->lpVtbl->GetCaps( pDSBuf, &dsbcaps ) != DS_OK ) |
||||
{ |
||||
Con_DPrintf( S_ERROR "DirectSound: failed to get capabilities\n" ); |
||||
SNDDMA_FreeSound (); |
||||
return false; |
||||
} |
||||
|
||||
// make sure mixer is active
|
||||
if( pDSBuf->lpVtbl->Play( pDSBuf, 0, 0, DSBPLAY_LOOPING ) != DS_OK ) |
||||
{ |
||||
Con_DPrintf( S_ERROR "DirectSound: failed to create circular buffer\n" ); |
||||
SNDDMA_FreeSound (); |
||||
return false; |
||||
} |
||||
|
||||
// we don't want anyone to access the buffer directly w/o locking it first
|
||||
lpData = NULL; |
||||
dma.samplepos = 0; |
||||
snd_hwnd = (HWND)hInst; |
||||
gSndBufSize = dsbcaps.dwBufferBytes; |
||||
dma.samples = gSndBufSize / 2; |
||||
dma.buffer = (byte *)lpData; |
||||
|
||||
SNDDMA_BeginPainting(); |
||||
if( dma.buffer ) memset( dma.buffer, 0, dma.samples * 2 ); |
||||
SNDDMA_Submit(); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/*
|
||||
================== |
||||
DS_DestroyBuffers |
||||
================== |
||||
*/ |
||||
static void DS_DestroyBuffers( void ) |
||||
{ |
||||
if( pDS ) pDS->lpVtbl->SetCooperativeLevel( pDS, snd_hwnd, DSSCL_NORMAL ); |
||||
|
||||
if( pDSBuf ) |
||||
{ |
||||
pDSBuf->lpVtbl->Stop( pDSBuf ); |
||||
pDSBuf->lpVtbl->Release( pDSBuf ); |
||||
} |
||||
|
||||
// only release primary buffer if it's not also the mixing buffer we just released
|
||||
if( pDSPBuf && ( pDSBuf != pDSPBuf )) |
||||
pDSPBuf->lpVtbl->Release( pDSPBuf ); |
||||
|
||||
dma.buffer = NULL; |
||||
pDSPBuf = NULL; |
||||
pDSBuf = NULL; |
||||
} |
||||
|
||||
/*
|
||||
================== |
||||
SNDDMA_LockSound |
||||
================== |
||||
*/ |
||||
void SNDDMA_LockSound( void ) |
||||
{ |
||||
if( pDSBuf != NULL ) |
||||
pDSBuf->lpVtbl->Stop( pDSBuf ); |
||||
} |
||||
|
||||
/*
|
||||
================== |
||||
SNDDMA_LockSound |
||||
================== |
||||
*/ |
||||
void SNDDMA_UnlockSound( void ) |
||||
{ |
||||
if( pDSBuf != NULL ) |
||||
pDSBuf->lpVtbl->Play( pDSBuf, 0, 0, DSBPLAY_LOOPING ); |
||||
} |
||||
|
||||
/*
|
||||
================== |
||||
SNDDMA_FreeSound |
||||
================== |
||||
*/ |
||||
void SNDDMA_FreeSound( void ) |
||||
{ |
||||
if( pDS ) |
||||
{ |
||||
DS_DestroyBuffers(); |
||||
pDS->lpVtbl->Release( pDS ); |
||||
Sys_FreeLibrary( &dsound_dll ); |
||||
} |
||||
|
||||
lpData = NULL; |
||||
pDSPBuf = NULL; |
||||
pDSBuf = NULL; |
||||
pDS = NULL; |
||||
} |
||||
|
||||
/*
|
||||
================== |
||||
SNDDMA_InitDirect |
||||
|
||||
Direct-Sound support |
||||
================== |
||||
*/ |
||||
si_state_t SNDDMA_InitDirect( void *hInst ) |
||||
{ |
||||
DSCAPS dscaps; |
||||
HRESULT hresult; |
||||
|
||||
if( !dsound_dll.link ) |
||||
{ |
||||
if( !Sys_LoadLibrary( &dsound_dll )) |
||||
return SIS_FAILURE; |
||||
} |
||||
|
||||
if(( hresult = iDirectSoundCreate( NULL, &pDS, NULL )) != DS_OK ) |
||||
{ |
||||
if( hresult != DSERR_ALLOCATED ) |
||||
return SIS_FAILURE; |
||||
|
||||
Con_DPrintf( S_ERROR "DirectSound: hardware already in use\n" ); |
||||
return SIS_NOTAVAIL; |
||||
} |
||||
|
||||
dscaps.dwSize = sizeof( dscaps ); |
||||
|
||||
if( pDS->lpVtbl->GetCaps( pDS, &dscaps ) != DS_OK ) |
||||
Con_DPrintf( S_ERROR "DirectSound: failed to get capabilities\n" ); |
||||
|
||||
if( FBitSet( dscaps.dwFlags, DSCAPS_EMULDRIVER )) |
||||
{ |
||||
Con_DPrintf( S_ERROR "DirectSound: driver not installed\n" ); |
||||
SNDDMA_FreeSound(); |
||||
return SIS_FAILURE; |
||||
} |
||||
|
||||
if( !DS_CreateBuffers( hInst )) |
||||
return SIS_FAILURE; |
||||
|
||||
return SIS_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
================== |
||||
SNDDMA_Init |
||||
|
||||
Try to find a sound device to mix for. |
||||
Returns false if nothing is found. |
||||
================== |
||||
*/ |
||||
int SNDDMA_Init( void *hInst ) |
||||
{ |
||||
// already initialized
|
||||
if( dma.initialized ) return true; |
||||
|
||||
memset( &dma, 0, sizeof( dma )); |
||||
|
||||
// init DirectSound
|
||||
if( SNDDMA_InitDirect( hInst ) != SIS_SUCCESS ) |
||||
return false; |
||||
|
||||
if( snd_firsttime ) |
||||
Con_Printf( "Audio: DirectSound\n" ); |
||||
dma.initialized = true; |
||||
snd_firsttime = false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_GetDMAPos |
||||
|
||||
return the current sample position (in mono samples read) |
||||
inside the recirculating dma buffer, so the mixing code will know |
||||
how many sample are required to fill it up. |
||||
=============== |
||||
*/ |
||||
int SNDDMA_GetDMAPos( void ) |
||||
{ |
||||
int s; |
||||
MMTIME mmtime; |
||||
DWORD dwWrite; |
||||
|
||||
if( !dma.initialized ) |
||||
return 0; |
||||
|
||||
mmtime.wType = TIME_SAMPLES; |
||||
pDSBuf->lpVtbl->GetCurrentPosition( pDSBuf, &mmtime.u.sample, &dwWrite ); |
||||
s = mmtime.u.sample - mmstarttime.u.sample; |
||||
|
||||
s >>= SAMPLE_16BIT_SHIFT; |
||||
s &= (dma.samples - 1); |
||||
|
||||
return s; |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_GetSoundtime |
||||
|
||||
update global soundtime |
||||
=============== |
||||
*/ |
||||
int SNDDMA_GetSoundtime( void ) |
||||
{ |
||||
static int buffers, oldsamplepos; |
||||
int samplepos, fullsamples; |
||||
|
||||
fullsamples = dma.samples / 2; |
||||
|
||||
// it is possible to miscount buffers
|
||||
// if it has wrapped twice between
|
||||
// calls to S_Update. Oh well.
|
||||
samplepos = SNDDMA_GetDMAPos(); |
||||
|
||||
if( samplepos < oldsamplepos ) |
||||
{ |
||||
buffers++; // buffer wrapped
|
||||
|
||||
if( paintedtime > 0x40000000 ) |
||||
{ |
||||
// time to chop things off to avoid 32 bit limits
|
||||
buffers = 0; |
||||
paintedtime = fullsamples; |
||||
S_StopAllSounds( true ); |
||||
} |
||||
} |
||||
|
||||
oldsamplepos = samplepos; |
||||
|
||||
return (buffers * fullsamples + samplepos / 2); |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_BeginPainting |
||||
|
||||
Makes sure dma.buffer is valid |
||||
=============== |
||||
*/ |
||||
void SNDDMA_BeginPainting( void ) |
||||
{ |
||||
int reps; |
||||
DWORD dwSize2; |
||||
DWORD *pbuf, *pbuf2; |
||||
HRESULT hr; |
||||
DWORD dwStatus; |
||||
|
||||
if( !pDSBuf ) return; |
||||
|
||||
// if the buffer was lost or stopped, restore it and/or restart it
|
||||
if( pDSBuf->lpVtbl->GetStatus( pDSBuf, &dwStatus ) != DS_OK ) |
||||
Con_DPrintf( S_ERROR "BeginPainting: couldn't get sound buffer status\n" ); |
||||
|
||||
if( dwStatus & DSBSTATUS_BUFFERLOST ) |
||||
pDSBuf->lpVtbl->Restore( pDSBuf ); |
||||
|
||||
if( !FBitSet( dwStatus, DSBSTATUS_PLAYING )) |
||||
pDSBuf->lpVtbl->Play( pDSBuf, 0, 0, DSBPLAY_LOOPING ); |
||||
|
||||
// lock the dsound buffer
|
||||
dma.buffer = NULL; |
||||
reps = 0; |
||||
|
||||
while(( hr = pDSBuf->lpVtbl->Lock( pDSBuf, 0, gSndBufSize, &pbuf, &locksize, &pbuf2, &dwSize2, 0 )) != DS_OK ) |
||||
{ |
||||
if( hr != DSERR_BUFFERLOST ) |
||||
{ |
||||
Con_DPrintf( S_ERROR "BeginPainting: %s\n", DSoundError( hr )); |
||||
S_Shutdown (); |
||||
return; |
||||
} |
||||
else pDSBuf->lpVtbl->Restore( pDSBuf ); |
||||
if( ++reps > 2 ) return; |
||||
} |
||||
|
||||
dma.buffer = (byte *)pbuf; |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_Submit |
||||
|
||||
Send sound to device if buffer isn't really the dma buffer |
||||
Also unlocks the dsound buffer |
||||
=============== |
||||
*/ |
||||
void SNDDMA_Submit( void ) |
||||
{ |
||||
if( !dma.buffer ) return; |
||||
// unlock the dsound buffer
|
||||
if( pDSBuf ) pDSBuf->lpVtbl->Unlock( pDSBuf, dma.buffer, locksize, NULL, 0 ); |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_Shutdown |
||||
|
||||
Reset the sound device for exiting |
||||
=============== |
||||
*/ |
||||
void SNDDMA_Shutdown( void ) |
||||
{ |
||||
if( !dma.initialized ) return; |
||||
dma.initialized = false; |
||||
SNDDMA_FreeSound(); |
||||
} |
||||
|
||||
/*
|
||||
=========== |
||||
S_Activate |
||||
|
||||
Called when the main window gains or loses focus. |
||||
The window have been destroyed and recreated |
||||
between a deactivate and an activate. |
||||
=========== |
||||
*/ |
||||
void S_Activate( qboolean active, void *hInst ) |
||||
{ |
||||
if( !dma.initialized ) return; |
||||
snd_hwnd = (HWND)hInst; |
||||
|
||||
if( !pDS || !snd_hwnd ) |
||||
return; |
||||
|
||||
if( active ) |
||||
DS_CreateBuffers( snd_hwnd ); |
||||
else DS_DestroyBuffers(); |
||||
} |
@ -0,0 +1,261 @@
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
s_backend.c - sound hardware output |
||||
Copyright (C) 2009 Uncle Mike |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 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 General Public License for more details. |
||||
*/ |
||||
|
||||
#include "common.h" |
||||
#if XASH_SOUND == SOUND_SDL |
||||
|
||||
#include "sound.h" |
||||
|
||||
#include <SDL.h> |
||||
|
||||
#define SAMPLE_16BIT_SHIFT 1 |
||||
#define SECONDARY_BUFFER_SIZE 0x10000 |
||||
|
||||
/*
|
||||
======================================================================= |
||||
Global variables. Must be visible to window-procedure function |
||||
so it can unlock and free the data block after it has been played. |
||||
======================================================================= |
||||
*/ |
||||
static int sdl_dev; |
||||
|
||||
//static qboolean snd_firsttime = true;
|
||||
//static qboolean primary_format_set;
|
||||
|
||||
void SDL_SoundCallback( void *userdata, Uint8 *stream, int len ) |
||||
{ |
||||
int size = dma.samples << 1; |
||||
int pos = dma.samplepos << 1; |
||||
int wrapped = pos + len - size; |
||||
|
||||
if( wrapped < 0 ) |
||||
{ |
||||
memcpy( stream, dma.buffer + pos, len ); |
||||
dma.samplepos += len >> 1; |
||||
} |
||||
else |
||||
{ |
||||
int remaining = size - pos; |
||||
memcpy( stream, dma.buffer + pos, remaining ); |
||||
memcpy( stream + remaining, dma.buffer, wrapped ); |
||||
dma.samplepos = wrapped >> 1; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
================== |
||||
SNDDMA_Init |
||||
|
||||
Try to find a sound device to mix for. |
||||
Returns false if nothing is found. |
||||
================== |
||||
*/ |
||||
qboolean SNDDMA_Init( void *hInst ) |
||||
{ |
||||
SDL_AudioSpec desired, obtained; |
||||
int samplecount; |
||||
|
||||
if( SDL_Init( SDL_INIT_AUDIO ) ) |
||||
{ |
||||
MsgDev( D_ERROR, "Audio: SDL: %s \n", SDL_GetError( ) ); |
||||
return false; |
||||
} |
||||
|
||||
#ifdef __linux__ |
||||
setenv( "PULSE_PROP_application.name", GI->title, 1 ); |
||||
setenv( "PULSE_PROP_media.role", "game", 1 ); |
||||
#endif |
||||
|
||||
memset( &desired, 0, sizeof( desired ) ); |
||||
desired.freq = SOUND_DMA_SPEED; |
||||
desired.format = AUDIO_S16LSB; |
||||
desired.samples = 1024; |
||||
desired.channels = 2; |
||||
desired.callback = SDL_SoundCallback; |
||||
|
||||
sdl_dev = SDL_OpenAudioDevice( NULL, 0, &desired, &obtained, 0 ); |
||||
|
||||
if( !sdl_dev ) |
||||
{ |
||||
Con_Printf( "Couldn't open SDL audio: %s\n", SDL_GetError( ) ); |
||||
return false; |
||||
} |
||||
|
||||
if( obtained.format != AUDIO_S16LSB ) |
||||
{ |
||||
Con_Printf( "SDL audio format %d unsupported.\n", obtained.format ); |
||||
goto fail; |
||||
} |
||||
|
||||
if( obtained.channels != 1 && obtained.channels != 2 ) |
||||
{ |
||||
Con_Printf( "SDL audio channels %d unsupported.\n", obtained.channels ); |
||||
goto fail; |
||||
} |
||||
|
||||
dma.format.speed = obtained.freq; |
||||
dma.format.channels = obtained.channels; |
||||
dma.format.width = 2; |
||||
samplecount = s_samplecount->value; |
||||
if( !samplecount ) |
||||
samplecount = 0x8000; |
||||
dma.samples = samplecount * obtained.channels; |
||||
dma.buffer = Z_Malloc( dma.samples * 2 ); |
||||
dma.samplepos = 0; |
||||
|
||||
Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq ); |
||||
|
||||
SDL_PauseAudioDevice( sdl_dev, 0 ); |
||||
|
||||
dma.initialized = true; |
||||
return true; |
||||
|
||||
fail: |
||||
SNDDMA_Shutdown( ); |
||||
return false; |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_GetDMAPos |
||||
|
||||
return the current sample position (in mono samples read) |
||||
inside the recirculating dma buffer, so the mixing code will know |
||||
how many sample are required to fill it up. |
||||
=============== |
||||
*/ |
||||
int SNDDMA_GetDMAPos( void ) |
||||
{ |
||||
return dma.samplepos; |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_GetSoundtime |
||||
|
||||
update global soundtime |
||||
=============== |
||||
*/ |
||||
int SNDDMA_GetSoundtime( void ) |
||||
{ |
||||
static int buffers, oldsamplepos; |
||||
int samplepos, fullsamples; |
||||
|
||||
fullsamples = dma.samples / 2; |
||||
|
||||
// it is possible to miscount buffers
|
||||
// if it has wrapped twice between
|
||||
// calls to S_Update. Oh well.
|
||||
samplepos = SNDDMA_GetDMAPos( ); |
||||
|
||||
if( samplepos < oldsamplepos ) |
||||
{ |
||||
buffers++; // buffer wrapped
|
||||
|
||||
if( paintedtime > 0x40000000 ) |
||||
{ |
||||
// time to chop things off to avoid 32 bit limits
|
||||
buffers = 0; |
||||
paintedtime = fullsamples; |
||||
S_StopAllSounds( true ); |
||||
} |
||||
} |
||||
|
||||
oldsamplepos = samplepos; |
||||
|
||||
return ( buffers * fullsamples + samplepos / 2 ); |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_BeginPainting |
||||
|
||||
Makes sure dma.buffer is valid |
||||
=============== |
||||
*/ |
||||
void SNDDMA_BeginPainting( void ) |
||||
{ |
||||
SDL_LockAudio( ); |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_Submit |
||||
|
||||
Send sound to device if buffer isn't really the dma buffer |
||||
Also unlocks the dsound buffer |
||||
=============== |
||||
*/ |
||||
void SNDDMA_Submit( void ) |
||||
{ |
||||
SDL_UnlockAudio( ); |
||||
} |
||||
|
||||
/*
|
||||
============== |
||||
SNDDMA_Shutdown |
||||
|
||||
Reset the sound device for exiting |
||||
=============== |
||||
*/ |
||||
void SNDDMA_Shutdown( void ) |
||||
{ |
||||
Con_Printf( "Shutting down audio.\n" ); |
||||
dma.initialized = false; |
||||
|
||||
if( sdl_dev ) |
||||
{ |
||||
SDL_PauseAudioDevice( sdl_dev, 1 ); |
||||
#ifndef __EMSCRIPTEN__ |
||||
SDL_CloseAudioDevice( sdl_dev ); |
||||
SDL_CloseAudio( ); |
||||
#endif |
||||
} |
||||
|
||||
#ifndef __EMSCRIPTEN__ |
||||
if( SDL_WasInit( SDL_INIT_AUDIO ) ) |
||||
SDL_QuitSubSystem( SDL_INIT_AUDIO ); |
||||
#endif |
||||
|
||||
if( dma.buffer ) |
||||
{ |
||||
Mem_Free( dma.buffer ); |
||||
dma.buffer = NULL; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
=========== |
||||
S_PrintDeviceName |
||||
=========== |
||||
*/ |
||||
void S_PrintDeviceName( void ) |
||||
{ |
||||
Msg( "Audio: SDL (driver: %s)\n", SDL_GetCurrentAudioDriver( ) ); |
||||
} |
||||
|
||||
/*
|
||||
=========== |
||||
S_Activate |
||||
Called when the main window gains or loses focus. |
||||
The window have been destroyed and recreated |
||||
between a deactivate and an activate. |
||||
=========== |
||||
*/ |
||||
void S_Activate( qboolean active ) |
||||
{ |
||||
SDL_PauseAudioDevice( sdl_dev, !active ); |
||||
} |
||||
#endif // XASH_SOUND == SOUND_SDL
|
Loading…
Reference in new issue