| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** 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.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- //----------------------------------------------------------------------------
- //
- // Westwood Studios Pacific.
- //
- // Confidential Information
- // Copyright (C) 2001 - All Rights Reserved
- //
- //----------------------------------------------------------------------------
- //
- // Project: WPAudio
- //
- // Module: AUD
- //
- // File name: AUD_Windows.cpp
- //
- // Created: 5/09/01
- //
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Includes
- //----------------------------------------------------------------------------
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <mmreg.h>
- #include <wpaudio/thread.h>
- #include <wpaudio/memory.h>
- #include <wpaudio/Source.h>
- #include <wsys/File.h>
- #include <wpaudio/device.h>
- #include <wpaudio/profiler.h>
- #include <wpaudio/win32.h>
- // 'assignment within condition expression'.
- #pragma warning(disable : 4706)
- //----------------------------------------------------------------------------
- // Externals
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Defines
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Private Types
- //----------------------------------------------------------------------------
- struct _aud_thread
- {
- char name[200];
- volatile int quit; /* thread must quit */
- volatile int count;
- volatile int leaving; /* thread is quiting */
- volatile TimeStamp interval; /* itask interval */
- volatile int running; /* thread is running */
- HANDLE handle; /* threads handle (windows) */
- void *data;
- AUD_ThreadCB *code;
- DWORD id; /* thread id (windows) */
- CRITICAL_SECTION access;
- AudioServiceInfo update;
- ProfileCPU cpu;
- DBG_TYPE()
- };
- DBG_DECLARE_TYPE ( AUD_Thread )
- //----------------------------------------------------------------------------
- // Private Data
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Public Data
- //----------------------------------------------------------------------------
- static HWND audioMainWindowHandle = NULL;
- //----------------------------------------------------------------------------
- // Private Prototypes
- //----------------------------------------------------------------------------
- static DWORD WINAPI AUD_service_thread ( VOID *data );
- //----------------------------------------------------------------------------
- // Private Functions
- //----------------------------------------------------------------------------
- static DWORD WINAPI AUD_service_thread ( VOID *data )
- {
- AUD_Thread *thread = (AUD_Thread *) data;
- if ( !thread )
- {
- return 0;
- }
- AUD_ThreadBeginCriticalSection ( thread );
- thread->running = TRUE;
- thread->leaving = FALSE;
- while ( !thread->quit )
- {
- if ( thread->code ( thread, thread->data ))
- {
- AUD_ThreadEndCriticalSection ( thread );
- Sleep ( (unsigned long ) thread->interval );
- AUD_ThreadBeginCriticalSection ( thread );
- }
- else
- {
- AUD_ThreadEndCriticalSection ( thread );
- Sleep ( MSECONDS(5));
- AUD_ThreadBeginCriticalSection ( thread );
- }
- thread->count++;
- }
- AUD_ThreadEndCriticalSection ( thread );
- thread->leaving = TRUE;
- return 0;
- }
- //----------------------------------------------------------------------------
- // Public Functions
- //----------------------------------------------------------------------------
- AUD_Thread* AUD_ThreadCreate ( const char *name, AUD_ThreadPriority pri, AUD_ThreadCB *code )
- {
- AUD_Thread *thread;
- ALLOC_STRUCT ( thread, AUD_Thread );
- DBG_SET_TYPE ( thread, AUD_Thread );
- if ( !name )
- {
- name = "no name given";
- }
- strncpy ( thread->name, name, ArrayLen(thread->name));
- ArrayEnd(thread->name);
- thread->quit = FALSE;
- thread->leaving = FALSE;
- thread->running = FALSE;
- thread->count = 0;
- thread->code = code;
- AudioServiceInfoInit ( &thread->update );
- ProfileCPUInit ( thread->cpu );
- InitializeCriticalSection ( &thread->access );
- AUD_ThreadSetInterval ( thread, SECONDS(1)/30 );
- if ( !(thread->handle = CreateThread ( NULL, 4*1024, AUD_service_thread, thread, 0, &thread->id )))
- {
- DBGPRINTF (( "ERROR: Failed to create audio thread: '%s'\n", thread->name ));
- return NULL;
- }
- int set;
- switch (pri)
- {
- case AUD_THREAD_PRI_NORMAL:
- set = TRUE;
- break;
- case AUD_THREAD_PRI_HIGH:
- set = SetThreadPriority ( thread->handle, THREAD_PRIORITY_HIGHEST );
- break;
- case AUD_THREAD_PRI_REALTIME:
- set = SetThreadPriority ( thread->handle, THREAD_PRIORITY_TIME_CRITICAL );
- break;
- default:
- DBG_MSGASSERT ( FALSE, ("Illegal thread priority"));
- set = TRUE;
- }
- if ( !set )
- {
- char buffer[1024];
- FormatMessage ( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buffer, sizeof(buffer), NULL);
- DBGPRINTF (( "Unable to change the priority of the thread - %s\n", buffer ));
- msg_assert ( FALSE, ( "Unable to change the priority of the thread - %s\n", buffer ));
- }
- DBGPRINTF (( "Created audio thread: '%s'\n", thread->name ));
- return thread;
- }
- //============================================================================
- // AUD_ThreadDestroy
- //============================================================================
- void AUD_ThreadDestroy ( AUD_Thread *thread )
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- thread->quit = TRUE;
- while ( !thread->leaving );
- WaitForSingleObject ( thread->handle, SECONDS(5));
- CloseHandle ( thread->handle );
- DeleteCriticalSection ( &thread->access );
- DBGPRINTF (( "Removed audio thread: '%s'\n", thread->name ));
- DBG_INVALIDATE_TYPE ( thread );
- AudioMemFree ( thread );
- }
- //============================================================================
- // AUD_ThreadBeginCriticalSection
- //============================================================================
- void AUD_ThreadBeginCriticalSection ( AUD_Thread *thread)
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- EnterCriticalSection ( &thread->access );
- }
- //============================================================================
- // AUD_ThreadEndCriticalSection
- //============================================================================
- void AUD_ThreadEndCriticalSection ( AUD_Thread *thread )
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- LeaveCriticalSection ( &thread->access );
- }
- //============================================================================
- // AUD_ThreadSetData
- //============================================================================
- void AUD_ThreadSetData ( AUD_Thread *thread, void *data )
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- AUD_ThreadBeginCriticalSection ( thread );
- thread->data = data;
- AUD_ThreadEndCriticalSection ( thread );
- }
- //============================================================================
- // AUD_ThreadSetInterval
- //============================================================================
- void AUD_ThreadSetInterval ( AUD_Thread *thread, TimeStamp interval )
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- AUD_ThreadBeginCriticalSection ( thread );
- thread->interval = interval;
- AudioServiceSetInterval ( &thread->update, thread->interval );
- AudioServiceSetMustServiceInterval ( &thread->update, thread->interval*4 );
- AudioServiceSetResetInterval ( &thread->update, thread->interval*4 );
- AUD_ThreadEndCriticalSection ( thread );
- }
- //============================================================================
- // AUD_ThreadGetInterval
- //============================================================================
- TimeStamp AUD_ThreadGetInterval ( AUD_Thread *thread )
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- return thread->interval;
- }
- //============================================================================
- // AUD_ThreadName
- //============================================================================
- char* AUD_ThreadName( AUD_Thread *thread )
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- return thread->name;
- }
- //============================================================================
- // AUD_ThreadCPUProfile
- //============================================================================
- ProfileCPU* AUD_ThreadCPUProfile( AUD_Thread *thread )
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- return &thread->cpu;
- }
- //============================================================================
- // AUD_ThreadAudioServiceInfo
- //============================================================================
- AudioServiceInfo* AUD_ThreadServiceInfo( AUD_Thread *thread )
- {
- DBG_ASSERT_TYPE ( thread, AUD_Thread );
- return &thread->update;
- }
- //============================================================================
- // AudioFormatReadWaveFile
- //============================================================================
- int AudioFormatReadWaveFile ( File *file, AudioFormat *format, int *bytes )
- {
- RIFF_HEADER rh;
- RIFF_CHUNK chunk;
- WAVEFORMATEX *wformat = NULL;
- int got_format = FALSE;
- int result = FALSE;
- //int mp3 = FALSE;
- DBG_ASSERT_TYPE ( format, AudioFormat );
- if ( bytes )
- {
- *bytes = 0;
- }
- if ( !file )
- {
- goto done;
- }
- file->seek ( 0, File::START );
- /* read wav info */
- if ( file->read ( &rh, sizeof (rh)) != sizeof(rh) )
- {
- DBGPRINTF (( "error: cannot read file\n" ));
- goto done;
- }
- if ( rh.form != vRIFF || rh.type != vWAVE )
- {
- file->seek ( 0, File::START );
- result = AudioFormatReadMP3File ( file, format, bytes );
- goto done;
- }
- while ( file->read ( &chunk, sizeof (chunk) ) == sizeof(chunk) )
- {
- switch ( chunk.type )
- {
- case vFMT :
- if ( chunk.length < sizeof ( WAVEFORMATEX ) )
- {
- wformat = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX));
- memset ( wformat, 0, sizeof ( WAVEFORMATEX) );
- }
- else
- {
- wformat = (WAVEFORMATEX *) malloc ( chunk.length );
- memset ( wformat, 0, chunk.length );
- }
- file->read ( wformat, chunk.length );
- wformat->cbSize = (ushort) chunk.length;
- got_format = TRUE;
- break;
- case vDATA:
- *bytes = chunk.length;
- goto got_data;
- default:
- file->seek ( chunk.length, File::CURRENT );
- break;
- }
- }
- DBGPRINTF (( "no data chunk found\n" ));
- goto done;
- got_data:
- if ( !wformat )
- {
- DBGPRINTF (( "no format chunk found\n" ));
- goto done;
- }
- format->SampleWidth = wformat->wBitsPerSample / 8;
- if ( wformat->wFormatTag == WAVE_FORMAT_IMA_ADPCM )
- {
- format->cdata.adpcm.BlockSize = wformat->nBlockAlign;
- format->Compression = AUDIO_COMPRESS_IMA_ADPCM;
- format->SampleWidth = 2;
- }
- else if ( wformat->wFormatTag == WAVE_FORMAT_ADPCM )
- {
- ADPCMWAVEFORMAT *aformat = (ADPCMWAVEFORMAT *)wformat;
- if ( aformat->wNumCoef != 7 && memcmp ( aformat->aCoef, MSADPCM_StdCoef, sizeof ( MSADPCM_StdCoef )) )
- {
- //currently we only support MS ADPCM using the standard coef table
- goto done;
- }
- format->cdata.adpcm.BlockSize = wformat->nBlockAlign;
- format->Compression = AUDIO_COMPRESS_MS_ADPCM;
- format->SampleWidth = 2;
- }
- else if ( wformat->wFormatTag == WAVE_FORMAT_PCM )
- {
- format->Compression = AUDIO_COMPRESS_NONE;
- }
- else if ( wformat->wFormatTag == WAVE_FORMAT_MPEGLAYER3 )
- {
- result = AudioFormatReadMP3File ( file, format, NULL );
- goto done;
- }
- else
- {
- goto done;
- }
- format->Channels = wformat->nChannels;
- format->BytesPerSecond = wformat->nAvgBytesPerSec;
- format->Rate = wformat->nSamplesPerSec;
- format->Flags = mAUDIO_FORMAT_PCM;
- AudioFormatUpdate ( format );
- result = TRUE;
- done:
- if ( wformat )
- {
- free ( wformat );
- }
-
- return result;
- }
- //============================================================================
- // WindowsDebugPrint
- //============================================================================
- void WindowsDebugPrint( const char * lpOutputString )
- {
- OutputDebugStringA ( lpOutputString );
- }
- //============================================================================
- // AudioSetWindowsHandle
- //============================================================================
- void AudioSetWindowsHandle ( HWND hwnd )
- {
- audioMainWindowHandle = hwnd;
- }
- //============================================================================
- // AudioGetWindowsHandle
- //============================================================================
- HWND AudioGetWindowsHandle ( void )
- {
- return audioMainWindowHandle;
- }
|