Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA
2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
6072 changed files with 2283311 additions and 0 deletions
@@ -0,0 +1,150 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audassrt.cpp **
** **
** Created by: 12/??/00 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <string.h>
#include <stdarg.h>
#include <assert.h>
//#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
#include <wpaudio/altypes.h>
/*****************************************************************************
** Externals **
*****************************************************************************/
extern void WindowsDebugPrint( const char * lpOutputString );
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
char *DBG_type_struct_is_dead = "Invalid structure";
char assert_msg_buf[10*1024];
static FILE *err_file = NULL;
static int total_errors;
static char _msg_buf[sizeof(assert_msg_buf)*2];
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
#ifdef _DEBUG
/******************************************************************/
/* */
/* */
/******************************************************************/
void __cdecl _assert_printf ( const char *format, ...)
{
va_list args;
va_start( args, format ); /* Initialize variable arguments. */
vsprintf ( assert_msg_buf, format, args );
va_end( args );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void __cdecl _aud_debug_printf ( const char *format, ...)
{
va_list args;
va_start( args, format ); /* Initialize variable arguments. */
vsprintf ( _msg_buf, format, args );
va_end( args );
WindowsDebugPrint ( _msg_buf );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void _aud_assert ( const char *, const char *file, int line, const char *reason )
{
sprintf ( _msg_buf, "%s(%d) : Error : ASSERT - %s\n", file, line, reason );
WindowsDebugPrint ( _msg_buf );
_assert ( _msg_buf, (void *) file, line );
}
#endif
/*****************************************************************************
** Public Functions **
*****************************************************************************/
@@ -0,0 +1,230 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audattr.cpp **
** **
** Created by: 11/16/95 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <wpaudio/altypes.h>
#include <wpaudio/level.h>
#include <wpaudio/attributes.h>
DBG_DECLARE_TYPE ( AudioAttribs )
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioAttribsInit ( AudioAttribs *attr )
{
DBG_ASSERT ( attr != NULL);
DBG_SET_TYPE ( attr, AudioAttribs );
AudioLevelInit ( &attr->VolumeLevel, AUDIO_VOLUME_MAX );
AudioLevelInit ( &attr->PitchLevel, 100);
AudioLevelInit ( &attr->PanPosition, AUDIO_PAN_CENTER);
AudioAttribsSetPitchDuration (attr, SECONDS(1), 10 );
AudioAttribsSetVolumeDuration (attr, SECONDS(1), AUDIO_LEVEL_MAX );
AudioAttribsSetPanDuration (attr, SECONDS(1), AUDIO_LEVEL_MAX );
AudioLevelSet ( &attr->VolumeLevel, AUDIO_VOLUME_MAX );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioAttribsUpdate ( AudioAttribs *attr )
{
DBG_ASSERT_TYPE ( attr, AudioAttribs );
AudioLevelUpdate ( &attr->VolumeLevel );
AudioLevelUpdate ( &attr->PitchLevel );
AudioLevelUpdate ( &attr->PanPosition );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioAttribsChanged ( AudioAttribs *attr )
{
DBG_ASSERT_TYPE ( attr, AudioAttribs );
return AudioLevelChanged ( &attr->VolumeLevel ) || AudioLevelChanged ( &attr->PitchLevel ) || AudioLevelChanged ( &attr->PanPosition );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioAttribsApply ( AudioAttribs *attr, AudioAttribs *mod )
{
DBG_ASSERT_TYPE ( attr, AudioAttribs );
DBG_ASSERT_TYPE ( mod, AudioAttribs );
AudioLevelSet ( &attr->VolumeLevel, AudioLevelApply ( &mod->VolumeLevel, AudioAttribsGetVolume ( attr ) ));
AudioLevelUpdate ( &attr->VolumeLevel );
{
// apply pitch
int level;
int change;
level = AudioAttribsGetPitch ( attr );
change = AudioAttribsGetPitch ( mod );
level = (level * change) / 100;
AudioAttribsSetPitch ( attr, level );
AudioLevelUpdate ( &attr->PitchLevel );
}
{
// apply pan
int pos;
if ( (pos = AudioAttribsGetPan ( mod ) - AUDIO_PAN_CENTER) != 0 )
{
if ( ( pos = pos + AudioAttribsGetPan ( attr )) < AUDIO_PAN_LEFT )
{
pos = AUDIO_PAN_LEFT ;
}
else if ( pos > AUDIO_PAN_RIGHT )
{
pos = AUDIO_PAN_RIGHT ;
}
AudioAttribsSetPan ( attr, pos );
}
AudioLevelUpdate ( &attr->PanPosition );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioAttribsUsed ( AudioAttribs *attr )
{
AudioLevelUsed ( &attr->VolumeLevel );
AudioLevelUsed ( &attr->PanPosition );
AudioLevelUsed ( &attr->PitchLevel );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioAttribsCalcPitch ( AudioAttribs *attr, int pitch )
{
int level;
DBG_ASSERT_TYPE ( attr, AudioAttribs );
level = AudioAttribsGetPitch ( attr );
return ( pitch * level ) / 100;
}
@@ -0,0 +1,586 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audcache.cpp **
** **
** Created by: 04/30/99 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <string.h>
#include <memory.h>
#include <wpaudio/altypes.h> // always include this header first
#include <wpaudio/memory.h>
#include <wpaudio/list.h>
#include <wpaudio/source.h>
#include <wpaudio/cache.h>
#include <wpaudio/profiler.h>
#include <wsys/File.h>
// 'assignment within condition expression'.
#pragma warning(disable : 4706)
DBG_DECLARE_TYPE ( AudioCache );
DBG_DECLARE_TYPE ( AudioCacheItem );
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
#define DEBUG_CACHE 0
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
static void audioCacheAssetClose ( AudioCache *cache )
{
if ( cache->assetFile )
{
cache->assetFile->close();
cache->assetFile = NULL;
}
cache->assetBytesLeft = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static int audioCacheAssetOpen ( AudioCache *cache, const char *name )
{
audioCacheAssetClose ( cache );
if ( name == NULL || cache->openAssetCB == NULL )
{
return FALSE;
}
cache->assetFile = cache->openAssetCB( name );
if ( !cache->assetFile )
{
return FALSE;
}
if ( !AudioFormatReadWaveFile ( cache->assetFile, &cache->assetFormat, &cache->assetBytesLeft ))
{
audioCacheAssetClose ( cache );
return FALSE;
}
return TRUE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int audioCacheAssetRead ( AudioCache *cache, void *data, int bytes )
{
if ( bytes > cache->assetBytesLeft )
{
bytes = cache->assetBytesLeft;
}
return cache->assetFile ? cache->assetFile->read ( data, bytes ) : 0 ;
}
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioCache* AudioCacheCreate ( int cacheSize, int maxItems, int frameSize )
{
AudioCache *cache;
int frameBytes;
int pages;
ALLOC_STRUCT ( cache, AudioCache );
DBG_SET_TYPE ( cache, AudioCache );
cache->frameSize = frameSize;
frameBytes = sizeof ( AudioFrame ) + frameSize;
pages = cacheSize/frameBytes;
cache->framePool = MemoryPoolCreate ( pages, frameBytes );
cache->itemPool = MemoryPoolCreate ( maxItems, sizeof ( AudioCacheItem ) );
ListInit ( &cache->items );
cache->assetFile = NULL;
AudioFormatInit ( &cache->assetFormat );
ProfCacheInit ( &cache->profile, pages, frameSize );
ProfCacheUpdateInterval ( &cache->profile, 10 ); // every ten milliseconds
if ( !cache->framePool || !cache->itemPool )
{
AudioCacheDestroy ( cache );
cache = NULL;
}
return cache;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioCacheDestroy ( AudioCache *cache )
{
AudioCacheItem *item;
DBG_ASSERT_TYPE ( cache, AudioCache );
while ( ( item = (AudioCacheItem *) ListNodeNext ( &cache->items )) )
{
AudioCacheItemFree ( item );
}
if ( cache->framePool )
{
MemoryPoolDestroy ( cache->framePool );
}
if ( cache->itemPool )
{
MemoryPoolDestroy ( cache->itemPool );
}
DBG_INVALIDATE_TYPE ( cache );
AudioMemFree ( cache );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioCacheItem* AudioCacheGetItem ( AudioCache *cache, const char *name )
{
AudioCacheItem *item, *head;
DBG_ASSERT_TYPE ( cache, AudioCache );
item = head = (AudioCacheItem *) &cache->items ;
while ( (item = (AudioCacheItem *) item->nd.next ) != head )
{
if ( item->valid && item->name == name )
{
return item;
}
}
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioCacheInvalidate ( AudioCache *cache )
{
AudioCacheItem *item, *head;
DBG_ASSERT_TYPE ( cache, AudioCache );
item = head = (AudioCacheItem *) &cache->items ;
while ( (item = (AudioCacheItem *) item->nd.next ) != head )
{
item->valid = FALSE;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioCacheOpenCB* AudioCacheSetOpenCB ( AudioCache *cache, AudioCacheOpenCB *cb )
{
DBG_ASSERT_TYPE ( cache, AudioCache );
AudioCacheOpenCB *old = cache->openAssetCB;
cache->openAssetCB = cb;
return old;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioCacheItem* AudioCacheLoadItem ( AudioCache *cache, const char *name )
{
AudioCacheItem *item;
int error;
DBG_ASSERT_TYPE ( cache, AudioCache );
if ( (item = AudioCacheGetItem ( cache, name )))
{
#if DEBUG_CACHE
DBGPRINTF (("ACACHE: %10s - Cached\n", item->name ));
#endif
ListNodeRemove ( &item->nd );
ListNodeAppend ( &cache->items, &item->nd );
ProfCacheHit ( &cache->profile );
return item;
}
ProfCacheMiss ( &cache->profile );
// item is not in the cache so load it
// see first if the sample exists
#if DEBUG_CACHE
DBGPRINTF (("ACACHE: %10s - Loading\n", name ));
#endif
ProfCacheLoadStart ( &cache->profile, 0 );
if ( !audioCacheAssetOpen( cache, name ))
{
#if DEBUG_CACHE
DBGPRINTF (("does not exist\n"));
#endif
goto none;
}
item = (AudioCacheItem *) MemoryPoolGetItem ( cache->itemPool );
if ( !item )
{
// free the oldest item so that we can use it's item struct
AudioCacheFreeOldestItem ( cache );
item = (AudioCacheItem *) MemoryPoolGetItem ( cache->itemPool );
if ( !item )
{
// the oldest item could not be freed because it was still playing
DBGPRINTF (("Audio cache overflow\n"));
audioCacheAssetClose ( cache );
goto none;
}
}
// prepare item for use
item->name = name;
item->cache = cache;
ListNodeInit ( &item->nd );
LockInit ( &item->lock );
AudioSampleInit ( &item->sample );
AudioSampleSetName ( &item->sample, name );
AudioFormatInit ( &item->format );
item->sample.Format = &item->format;
DBG_SET_TYPE ( item, AudioCacheItem );
error = FALSE;
// ok load sample data in to cache
{
int bytesToTransfer;
int bytes;
int bytesTransfered;
bytesToTransfer = cache->assetBytesLeft;
while ( bytesToTransfer )
{
AudioFrame *frame;
void *data;
if ( (bytes = cache->frameSize ) > bytesToTransfer )
{
bytes = bytesToTransfer;
}
while ( ! (frame = (AudioFrame *) MemoryPoolGetItem ( cache->framePool )))
{
if ( !AudioCacheFreeOldestItem ( cache ) )
{
break;
}
}
if ( !frame )
{
error = TRUE;
break;
}
data = (void *) ( (uint) frame + sizeof ( AudioFrame ));
AudioFrameInit ( frame, data, bytes );
AudioSampleAddFrame ( &item->sample, frame );
bytesTransfered = audioCacheAssetRead ( cache, data, bytes );
ProfCacheAddLoadBytes ( &cache->profile, bytesTransfered );
ProfCacheAddPage ( &cache->profile );
ProfCacheFill ( &cache->profile, bytesTransfered );
if ( bytesTransfered != bytes )
{
error = TRUE;
break;
}
bytesToTransfer -= bytesTransfered;
}
}
if ( error )
{
#if DEBUG_CACHE
DBGPRINTF (("FAILED\n"));
#endif
AudioCacheItemFree ( item );
goto none;
}
#if DEBUG_CACHE
DBGPRINTF (("done\n"));
#endif
// update the format structure
memcpy ( &item->format, &cache->assetFormat, sizeof ( AudioFormat) );
ListNodeAppend ( &cache->items, &item->nd );
item->valid = TRUE;
audioCacheAssetClose ( cache );
ProfCacheLoadEnd ( &cache->profile );
return item;
none:
ProfCacheLoadEnd ( &cache->profile );
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
// AudioCacheFreeOldestItem()
// Free the oldest UNUSED item in the list. These should tend to be
// towards the end of the list, as old events should expire and unlock.
// But not always (e.g. loops), so don't count on it.
int AudioCacheFreeOldestItem( AudioCache *cache )
{
AudioCacheItem *item;
DBG_ASSERT_TYPE( cache, AudioCache );
item = (AudioCacheItem*) ListNodePrev( &cache->items );
while ( item )
{
if ( !AudioCacheItemInUse( item ) )
{
AudioCacheItemFree( item );
return TRUE;
}
item = (AudioCacheItem*) ListNodePrev( (ListNode*) item );
}
return FALSE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioCacheItemLock ( AudioCacheItem *item )
{
DBG_ASSERT_TYPE ( item, AudioCacheItem );
LockAcquire ( &item->lock );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioCacheItemUnlock ( AudioCacheItem *item )
{
DBG_ASSERT_TYPE ( item, AudioCacheItem );
LockRelease ( &item->lock );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioCacheItemInUse ( AudioCacheItem *item )
{
DBG_ASSERT_TYPE ( item, AudioCacheItem );
return Locked ( &item->lock );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioCacheItemFree ( AudioCacheItem *item )
{
DBG_ASSERT_TYPE ( item, AudioCacheItem );
if ( ListNodeInList ( &item->nd ))
{
ListNodeRemove ( &item->nd );
}
DBG_MSGASSERT ( !AudioCacheItemInUse ( item ), ("cache item is still in use"));
#if DEBUG_CACHE
DBGPRINTF (("ACACHE: %10s - Freeing\n", AudioBagGetItemName ( item->cache->bag, item->id )));
#endif
// return frames to frame pool
{
AudioFrame *frame;
while ( (frame = (AudioFrame *) ListNodeNext ( &item->sample.Frames )) )
{
ListNodeRemove ( &frame->nd );
ProfCacheRemove ( &item->cache->profile, frame->Bytes );
AudioFrameDeinit ( frame );
ProfCacheRemovePage ( &item->cache->profile );
MemoryPoolReturnItem ( item->cache->framePool, frame );
}
}
AudioSampleDeinit ( &item->sample );
DBG_INVALIDATE_TYPE ( item );
MemoryPoolReturnItem ( item->cache->itemPool, item );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioSample* AudioCacheItemSample ( AudioCacheItem *item )
{
DBG_ASSERT_TYPE ( item, AudioCacheItem );
return &item->sample;
}
@@ -0,0 +1,710 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audchanl.cpp **
** **
** Created by: 11/16/96 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <string.h>
#include <wpaudio/altypes.h>
#include <wpaudio/memory.h>
#include <wpaudio/list.h>
#include <wpaudio/channel.h>
#include <wpaudio/device.h>
// 'assignment within condition expression'.
#pragma warning(disable : 4706)
DBG_DECLARE_TYPE ( AudioChannel)
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
static int audioChannelSampleDone ( AudioChannel *chan );
static int audioChannelNextSample ( AudioChannel *chan );
static int audioChannelNextFrame ( AudioChannel *chan );
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioChannel* audioChannelCreate ( AudioDevice *dev )
{
AudioChannel *chan = NULL;
DBG_ASSERT_TYPE ( dev , AudioDevice );
ALLOC_STRUCT ( chan, AudioChannel );
DBG_SET_TYPE ( chan, AudioChannel );
ListNodeInit ( &chan->nd );
AudioControlInit ( &chan->Control );
AudioAttribsInit ( &chan->attribs );
audioChannelMakeStandard ( chan ); // set up for standard processing
chan->Device = dev;
chan->driver = dev->driver;
chan->current_format = dev->DefaultFormat;
chan->format_changed = FALSE;
chan->drv_format_changed = FALSE;
#ifndef IG_FINAL_RELEASE
chan->sample_name[0] = 0;
#endif
if ( dev->driver->openChannel ( chan ) != vNO_ERROR )
{
DBGPRINTF (("Audio driver failed to open a new channel\n"));
goto error;
}
return chan;
error:
if ( chan )
{
audioChannelDestroy ( chan );
}
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void audioChannelDestroy ( AudioChannel *chan )
{
DBG_ASSERT_TYPE ( chan, AudioChannel );
chan->driver->closeChannel ( chan );
AudioMemFree ( chan );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void audioChannelMakeStandard ( AudioChannel *chan )
{
DBG_ASSERT_TYPE ( chan, AudioChannel );
// reset callbacks
chan->drvCBNextFrame = (AudioChannelCB *) audioChannelNextFrame;
chan->drvCBNextSample = (AudioChannelCB *) audioChannelNextSample;
chan->drvCBSampleDone = (AudioChannelCB *) audioChannelSampleDone;
chan->CB_NextFrame = NULL;
chan->CB_NextSample = NULL;
chan->CB_SampleDone = NULL;
chan->CB_Stop = NULL;
chan->Data = NULL;
chan->Type = AUDIO_CHANNEL_TYPE_STD;
// reset control
AudioControlInit ( &chan->Control );
chan->Control.Priority = AUD_NORMAL_PRIORITY;
// reset attribs
chan->GroupAttribs = audioStdChannelAttribs;
chan->SfxAttribs = NULL;
chan->CompAttribs = NULL;
chan->FadeAttribs = NULL;
AudioAttribsInit ( &chan->ChannelAttribs );
// reset sequencer
// clear audio
chan->sample = NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void audioChannelRecalcAttribs ( AudioChannel *chan )
{
AudioDevice *dev;
DBG_ASSERT_TYPE ( chan, AudioChannel );
dev = (AudioDevice *) chan->Device;
DBG_ASSERT_TYPE ( dev, AudioDevice );
AudioAttribsInit ( &chan->attribs );
AudioAttribsApply ( &chan->attribs, &chan->ChannelAttribs );
AudioAttribsUsed ( &chan->ChannelAttribs );
if ( chan->SfxAttribs )
{
AudioAttribsApply ( &chan->attribs, chan->SfxAttribs );
AudioAttribsUsed ( chan->SfxAttribs );
}
if ( chan->GroupAttribs )
{
AudioAttribsApply ( &chan->attribs, chan->GroupAttribs );
}
if ( chan->CompAttribs )
{
AudioAttribsApply ( &chan->attribs, chan->CompAttribs );
}
if ( chan->FadeAttribs )
{
AudioAttribsApply ( &chan->attribs, chan->FadeAttribs );
}
AudioAttribsApply ( &chan->attribs, &dev->Attribs );
if ( dev->GroupAttribs )
{
AudioAttribsApply ( &chan->attribs, dev->GroupAttribs );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static int audioChannelNextFrame ( AudioChannel *chan )
{
int err;
DBG_ASSERT ( chan != NULL );
if ( chan->CB_NextFrame )
{
// user is controlling frame access
if ( (err = chan->CB_NextFrame ( chan )) != vNO_ERROR )
{
// there was an error
DBGPRINTF(("Frame error:\n"));
chan->bytesInFrame = 0;
chan->bytesRemaining = 0;
chan->frameData = NULL;
return err;
};
DBG_ASSERT ( chan->bytesInFrame >= 0 );
DBG_ASSERT ( chan->bytesRemaining >= 0 );
return vNO_ERROR;
}
// user is not controlling frame access so we handle the default behaviour
DBG_ASSERT ( chan->bytesRemaining >= 0 ); // something corrupted this field
if ( chan->frame )
{
if ( ( chan->frame = (AudioFrame*) ListNodeNext ( &chan->frame->nd )) )
{
// there is more data to be got
chan->frameData = (char *) chan->frame->Data;
chan->bytesInFrame = chan->frame->Bytes;
chan->bytesRemaining = chan->bytesInFrame;
DBG_MSGASSERT ( chan->frame->sample == chan->sample, ("frame does not belong to sample") );
return vNO_ERROR;
}
}
// data has been exhausted
chan->bytesInFrame = 0; // no more frames, drvCBNextSample() will be called
return vNO_ERROR;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static int audioChannelNextSample ( AudioChannel *chan )
{
DBG_ASSERT ( chan != NULL );
if (chan->Control.LoopCount)
{
if ( chan->Control.LoopCount != AUDIO_CTRL_LOOP_FOREVER )
{
chan->Control.LoopCount--;
}
AudioChannelSetSample ( chan, chan->sample );
}
else
{
AudioChannelSetSample ( chan, NULL );
}
if ( chan->CB_NextSample)
{
chan->CB_NextSample ( chan );
}
if ( chan->sample )
{
chan->driver->queueIt ( chan );
}
return vNO_ERROR;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static int audioChannelSampleDone ( AudioChannel *chan )
{
// reset channel back to default
chan->sample = NULL;
FLAGS_CLEAR ( chan->Control.Status, mAUDIO_CTRL_PLAYING|mAUDIO_CTRL_PAUSED );
chan->Control.LoopCount = 0;
AudioAttribsInit ( &chan->ChannelAttribs );
#ifndef IG_FINAL_RELEASE
chan->sample_name[0] = 0;
#endif
if ( chan->CB_SampleDone )
{
return chan->CB_SampleDone ( chan );
}
return vNO_ERROR;
}
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioChannelTaken ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
return chan->Control.Status & mAUDIO_CTRL_ALLOCATED;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelReserve ( AudioChannel *chan, AudioChannelType type )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
DBG_ASSERT ( chan->Type == AUDIO_CHANNEL_TYPE_STD ); // you can only reserve standard channels
chan->Type = type;
AudioChannelStop ( chan );
FLAGS_SET ( chan->Control.Status, mAUDIO_CTRL_ALLOCATED );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelRelease ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
if ( chan->Control.Status & mAUDIO_CTRL_ALLOCATED)
{
FLAGS_CLEAR ( chan->Control.Status, mAUDIO_CTRL_ALLOCATED );
chan->Type = AUDIO_CHANNEL_TYPE_STD;
audioChannelMakeStandard ( chan );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelDestroy ( AudioChannel *chan)
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
AudioChannelStop ( chan ); // stop anything that is playing
audioRemoveChannel ( chan );
audioChannelDestroy ( chan );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelStop ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
chan->driver->lock ( chan);
if ( chan->Control.Status & (mAUDIO_CTRL_PLAYING|mAUDIO_CTRL_PAUSED) )
{
chan->driver->stop ( chan );
DBG_ASSERT ( !(chan->Control.Status & (mAUDIO_CTRL_PLAYING|mAUDIO_CTRL_PAUSED)) );
}
chan->driver->unlock ( chan );
if ( chan->CB_Stop )
{
chan->CB_Stop ( chan );
}
chan->sample = NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelPause ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
chan->driver->lock ( chan );
if ( chan->Control.Status & mAUDIO_CTRL_PLAYING )
{
FLAGS_CLEAR (chan->Control.Status, mAUDIO_CTRL_PLAYING);
chan->driver->pause ( chan );
FLAGS_SET (chan->Control.Status, mAUDIO_CTRL_PAUSED);
}
chan->driver->unlock ( chan );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelResume ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
chan->driver->lock ( chan );
if ( chan->Control.Status & mAUDIO_CTRL_PAUSED )
{
chan->driver->resume ( chan );
FLAGS_CLEAR (chan->Control.Status, mAUDIO_CTRL_PAUSED);
FLAGS_SET (chan->Control.Status, mAUDIO_CTRL_PLAYING);
}
chan->driver->unlock ( chan );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelLock ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
chan->driver->lock ( chan );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelUnlock ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
chan->driver->unlock ( chan );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelUse ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
chan->driver->lock ( chan );
FLAGS_SET ( chan->Control.Status, mAUDIO_CTRL_INUSE);
chan->driver->unlock ( chan );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelNoUse ( AudioChannel *chan )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
chan->driver->lock ( chan );
FLAGS_CLEAR ( chan->Control.Status, mAUDIO_CTRL_INUSE);
chan->driver->unlock ( chan );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioChannelStart ( AudioChannel *chan )
{
int err = ERROR_CODE_FAIL;
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
if ( (chan->Control.Status & (mAUDIO_CTRL_PAUSED | mAUDIO_CTRL_PLAYING)))
{
DBGPRINTF (("Failed to start channel as channel is currently active\n"));
return ERROR_CODE_NO_CHANNEL;
}
if ( chan->sample == NULL )
{
DBGPRINTF (("Failed to start channel as no sample data was given\n"));
return ERROR_CODE_MISSING_DATA;
}
AudioAttribsUpdate ( &chan->ChannelAttribs );
audioChannelRecalcAttribs ( chan );
chan->driver->lock ( chan );
if ( (err = chan->driver->start ( chan )) == vNO_ERROR )
{
FLAGS_SET ( chan->Control.Status, mAUDIO_CTRL_PLAYING);
}
chan->driver->unlock ( chan );
return err;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioChannelSetSample ( AudioChannel *chan, AudioSample *sample )
{
DBG_ASSERT ( audioInitialized ); // AudioSetUp() was not called
DBG_ASSERT_TYPE ( chan, AudioChannel );
if ( (chan->sample = sample) )
{
DBG_ASSERT_TYPE ( sample, AudioSample);
#ifndef IG_FINAL_RELEASE
strncpy ( chan->sample_name, sample->name, sizeof(chan->sample_name));
chan->sample_name[ sizeof(chan->sample_name) -1 ] = 0;
#endif
if ( chan->frame = AudioSampleFirstFrame ( sample ) )
{
chan->frameData = (char *) chan->frame->Data;
chan->bytesInFrame = chan->frame->Bytes;
chan->bytesRemaining = chan->bytesInFrame;
sample->Data = NULL;
DBG_MSGASSERT ( chan->frame->sample == sample, ("frame does not belong to sample") );
}
else
{
chan->frameData = chan->sample->Data;
chan->bytesInFrame = chan->sample->Bytes;
chan->bytesRemaining = chan->bytesInFrame;
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioChannelSetFormat ( AudioChannel *chan, AudioFormat *new_format )
{
if ( !memcmp ( new_format, &chan->current_format, sizeof ( AudioFormat )))
{
chan->format_changed = FALSE;
}
else
{
chan->format_changed = TRUE;
chan->current_format = *new_format;
}
return chan->format_changed;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioChannelIsAudible ( AudioChannel *chan )
{
return (chan->Control.Status & mAUDIO_CTRL_PLAYING);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioControlInit ( AudioControl *ctrl )
{
ctrl->LoopCount = 0;
ctrl->Status = 0;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,288 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audlevel.cpp **
** **
** Created by: 11/16/95 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <wpaudio/altypes.h>
#include <wpaudio/level.h>
#include <wpaudio/time.h>
// 'assignment within condition expression'.
#pragma warning(disable : 4706)
DBG_DECLARE_TYPE ( AudioLevel )
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioLevelInit ( AudioLevel *level, int startLevel )
{
DBG_ASSERT ( level != NULL );
DBG_SET_TYPE ( level, AudioLevel );
level->flags = 0;
level->lastTime = AudioGetTime ();
AudioLevelSetDuration ( level, SECONDS(1), AUDIO_LEVEL_MAX);
AudioLevelSet ( level, startLevel );
AudioLevelUpdate ( level );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioLevelSet ( AudioLevel *level, int newLevel )
{
DBG_ASSERT_TYPE ( level, AudioLevel );
DBG_ASSERT (newLevel>=AUDIO_LEVEL_MIN);
DBG_ASSERT (newLevel<=AUDIO_LEVEL_MAX);
level->flags |= AUDIO_LEVEL_SET;
level->newLevel = (newLevel<<AUDIO_LEVEL_SCALE);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioLevelForce( AudioLevel *level)
{
DBG_ASSERT_TYPE ( level, AudioLevel );
level->flags |= AUDIO_LEVEL_SET;
}
#ifdef _DEBUG
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioLevelApply ( AudioLevel *level, int val )
{
DBG_ASSERT_TYPE ( level, AudioLevel );
DBG_ASSERT (val >= AUDIO_LEVEL_MIN_VAL);
DBG_ASSERT (val <= AUDIO_LEVEL_MAX_VAL);
return AUDIO_LEVEL_APPLY(level,val);
}
#endif
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioLevelAdjust ( AudioLevel *level, int newLevel )
{
DBG_ASSERT_TYPE ( level, AudioLevel );
DBG_ASSERT (newLevel>=AUDIO_LEVEL_MIN);
DBG_ASSERT (newLevel<=AUDIO_LEVEL_MAX);
level->flags &= ~AUDIO_LEVEL_SET;
if ( level->newLevel == level->level)
{
level->lastTime = AudioGetTime ();
}
level->newLevel = newLevel<<AUDIO_LEVEL_SCALE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioLevelSetDuration ( AudioLevel *level, TimeStamp time, int range )
{
DBG_ASSERT_TYPE ( level, AudioLevel );
DBG_ASSERT ( time != 0 );
DBG_ASSERT (range > 0);
DBG_ASSERT (range <= AUDIO_LEVEL_MAX);
level->change = (range<< AUDIO_LEVEL_SCALE) / (uint) time;
level->duration = time;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioLevelUpdate ( AudioLevel *level )
{
int dif;
int delta; // amount to move by this update
TimeStamp time, thisTime;
DBG_ASSERT_TYPE ( level, AudioLevel );
if ( (dif = (level->newLevel - level->level)) )
{
if (level->flags & AUDIO_LEVEL_SET )
{
level->level = level->newLevel;
}
else
{
// calculate what the delta change is for this update
thisTime = AudioGetTime ( ) ;
time = thisTime - level->lastTime;
level->lastTime = thisTime; // remember time of this update
// the next check avoid overflowing the delta
if (time > level->duration)
{
time = level->duration;
}
delta = level->change * (uint) time;
if (dif<0)
{
if ( delta > (-dif))
{
level->level += dif;
}
else
{
level->level -= delta;
}
}
else
{
if ( delta > dif )
{
level->level += dif;
}
else
{
level->level += delta;
}
}
}
// there was a change in the level
level->flags |= AUDIO_LEVEL_CHANGED;
return TRUE;
}
// there has been no change this update
return FALSE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioLevelGetVal( AudioLevel *level )
{
return (level->newLevel>>AUDIO_LEVEL_SCALE);
}
@@ -0,0 +1,418 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audlists.cpp **
** **
** Created by: 04/01/95 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <wpaudio/altypes.h>
#include <wpaudio/list.h>
// 'assignment within condition expression'.
#pragma warning(disable : 4706)
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
void ListInit ( ListHead *head )
{
head->prev = head->next = head;
head->pri = (Priority) head; // this identifies the node as a head node
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ListNodeInit ( ListNode *node )
{
node->prev = node->next= node;
node->pri = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int ListAddNodeSortAscending( ListHead *head, ListNode *new_node )
{
ListNode *node;
Priority pri;
int index;
index = 0;
pri = new_node->pri;
node = (ListNode*) head;
while( (node = ListNodeNext ( node )))
{
if ( pri <= node->pri )
{
ListNodeInsert ( node, new_node );
return index;
}
index++;
}
ListNodeInsert ( head, new_node );
return index;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ListAddNode( ListHead *head, ListNode *new_node )
{
ListNode *node;
Priority pri;
pri = new_node->pri;
node = (ListNode*) head;
while( (node = ListNodeNext ( node )))
{
if (node->pri <= pri )
{
ListNodeInsert ( node, new_node );
return;
}
}
ListNodeInsert ( head, new_node );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ListAddNodeAfter( ListHead *head, ListNode *new_node )
{
ListNode *node;
Priority pri;
pri = new_node->pri;
node = (ListNode*) head;
while( (node = ListNodeNext ( node )))
{
if (node->pri < pri )
{
ListNodeInsert ( node, new_node );
return;
}
}
ListNodeInsert ( head, new_node );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ListMerge( ListHead *from, ListHead *to )
{
ListNode *first,
*last,
*node;
first = from->next;
last = from->prev;
if ( first == (ListNode*) from )
{
/* the from list is empty so there is nothing to do */
return;
}
node = to->prev;
node->next = first;
first->prev = node;
last->next = (ListNode*) to;
to->prev = last;
ListInit ( from ); /* make the from list empty now */
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int ListCountItems ( ListHead *head )
{
ListNode *node;
int count = 0;
node = head->next;
while(node!=(ListNode*)head)
{
count++;
node = node->next;
}
return count;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
ListNode* ListFirstItem ( ListHead *head )
{
return ListNextItem ((ListNode*) head );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
ListNode* ListNextItem ( ListNode *node )
{
if ( !node )
{
return NULL;
}
return ( ListNodeNext ( node ));
}
/******************************************************************/
/* */
/* */
/******************************************************************/
ListNode* ListGetItem( ListHead *head, int number )
{
ListNode *node;
node = head->next;
while( node != (ListNode*) head )
{
if ( number-- == 0 )
{
return node;
}
node = node->next;
}
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ListNodeInsert( ListNode *node, ListNode *new_node )
{
new_node->prev = node->prev;
new_node->next = node;
node->prev = new_node;
new_node->prev->next = new_node;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ListNodeAppend( ListNode *node, ListNode *new_node )
{
new_node->prev = node;
new_node->next = node->next;
node->next = new_node;
new_node->next->prev = new_node;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ListNodeRemove( ListNode *node )
{
node->prev->next = node->next;
node->next->prev = node->prev;
node->prev = node->next = node; // so we know that the node is not in a list
}
/******************************************************************/
/* */
/* */
/******************************************************************/
ListNode* ListNodeNext( ListNode *node )
{
ListNode *next;
next = node->next;
if ( next && ListNodeIsHead ( next ))
{
return NULL;
}
return next;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
ListNode* ListNodePrev (ListNode *node)
{
ListNode *next;
next = node->prev;
if ( ListNodeIsHead ( next ))
{
return NULL;
}
return next;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
ListNode* ListNodeLoopNext (ListNode *node)
{
ListNode *next;
next = node->next;
if ( ListNodeIsHead ( next ))
{
// skip head node
next = next->next;
if ( ListNodeIsHead ( next ))
{
return NULL; // it is an empty list
}
}
return next;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
ListNode* ListNodeLoopPrev (ListNode *node)
{
ListNode *next;
next = node->prev;
if ( ListNodeIsHead ( next ))
{
// skip head node
next = next->prev;
if ( ListNodeIsHead ( next ))
{
return NULL; // it is an empty list
}
}
return next;
}
@@ -0,0 +1,158 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audlock.cpp **
** **
** Created by: 04/01/95 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <wpaudio/altypes.h>
#include <wpaudio/lock.h>
DBG_DECLARE_TYPE ( Lock )
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
#ifdef _DEBUG
/******************************************************************/
/* */
/* */
/******************************************************************/
void LockInit ( volatile Lock *lock )
{
DBG_ASSERT ( lock != NULL);
LOCK_INIT(lock);
DBG_SET_TYPE ( lock, Lock );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void LockAcquire ( volatile Lock *lock)
{
DBG_ASSERT_TYPE ( lock, Lock);
DBG_ASSERT ( lock->count >= 0 );
LOCK_ACQUIRE (lock);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void LockRelease ( volatile Lock *lock)
{
DBG_ASSERT_TYPE ( lock, Lock);
DBG_ASSERT ( lock->count > 0 );
LOCK_RELEASE(lock);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int Locked ( volatile Lock *lock)
{
DBG_ASSERT_TYPE ( lock, Lock);
DBG_ASSERT ( lock->count >= 0 );
return LOCKED(lock);
}
#endif
@@ -0,0 +1,277 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audmpool.cpp **
** **
** Created by: 10/23/95 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <string.h>
#include <wpaudio/altypes.h>
#include <wpaudio/memory.h>
// 'assignment within condition expression'.
#pragma warning(disable : 4706)
DBG_DECLARE_TYPE ( AudioMemoryPool )
DBG_DECLARE_TYPE ( MemoryItem )
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioMemoryPool* MemoryPoolCreate( uint items, uint size )
{
uint poolsize;
AudioMemoryPool *pool;
MemoryItem *item;
uint i;
DBG_ASSERT ( items > 0 );
DBG_ASSERT ( size > 0 );
poolsize = items*(size + sizeof(MemoryItem)) + sizeof (AudioMemoryPool);
if ((pool = (AudioMemoryPool *) AudioMemAlloc ( poolsize )))
{
item = (MemoryItem *)( (uint)pool + (uint) sizeof(AudioMemoryPool));
pool->next = item;
DBG_CODE ( pool->itemsOut = 0;)
DBG_CODE ( pool->numItems = items;)
DBG_SET_TYPE ( pool, AudioMemoryPool );
for ( i=0; i < items-1; i++)
{
DBG_SET_TYPE ( item, MemoryItem );
item->next = (MemoryItem *) ( (uint) item + (uint) (sizeof(MemoryItem) + size) );
item = item->next;
}
item->next = NULL;
DBG_SET_TYPE ( item, MemoryItem );
}
return pool;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void MemoryPoolDestroy ( AudioMemoryPool *pool )
{
DBG_ASSERT_TYPE ( pool, AudioMemoryPool );
DBG_CODE
(
if ( pool->itemsOut > 0 )
{
DBGPRINTF ( ( "Destroying memory pool with %d items still out\n", pool->itemsOut) );
}
)
AudioMemFree ( pool );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void *MemoryPoolGetItem ( AudioMemoryPool *pool )
{
MemoryItem *item = NULL;
DBG_ASSERT_TYPE ( pool, AudioMemoryPool );
if (! (item = pool->next) )
{
return NULL;
}
DBG_CODE ( pool->itemsOut++;)
DBG_MSGASSERT ( pool->itemsOut <= pool->numItems,( "pool overflow" ));
DBG_ASSERT_TYPE ( item, MemoryItem ); // !!! Memory corruption !!!
pool->next = item->next;
return (void *) ( (uint) item + (uint) sizeof(MemoryItem));
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void MemoryPoolReturnItem ( AudioMemoryPool *pool, void *data )
{
MemoryItem *item;
DBG_ASSERT_TYPE ( pool, AudioMemoryPool );
DBG_ASSERT_PTR ( data );
item = (MemoryItem *) ( (uint) data - (uint) sizeof(MemoryItem));
DBG_ASSERT_TYPE ( item, MemoryItem ); // returning invalid item to pool
item->next = pool->next;
pool->next = item;
DBG_MSGASSERT ( pool->itemsOut > 0,( "Pool underflow" )); // returning more items than were taken
DBG_CODE ( pool->itemsOut--; )
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int MemoryPoolCount ( AudioMemoryPool *pool )
{
MemoryItem *item = NULL;
int count = 0;
DBG_ASSERT_TYPE ( pool, AudioMemoryPool );
if ( (item = pool->next) )
{
while ( item )
{
count++;
item = item->next;
}
}
return count;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioAddSlash ( char *string )
{
int len = strlen ( string );
if ( len )
{
if ( string[len-1] != '\\' )
{
string[len] = '\\';
string[len+1] = 0;
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioHasPath ( const char *string )
{
return ( strchr ( string, ':' ) || strchr ( string, '\\' ) || strchr ( string, '/' ) || strchr ( string, '.'));
}
@@ -0,0 +1,636 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audprof.cpp **
** **
** Created by: mm/dd/yy <author> **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <wpaudio/profiler.h>
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
#ifndef IG_FINAL_RELEASE
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheInit ( ProfileData *prof, int pages, int pageSize )
{
memset ( prof, 0, sizeof ( ProfileData ));
if ( !QueryPerformanceFrequency( (LARGE_INTEGER*) &prof->freq ))
{
prof->freq = 0;
}
prof->update = prof->freq;
prof->cacheSize = pages*pageSize;
prof->numPages = pages;
prof->pageSize = pageSize;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheDeinit ( ProfileData * )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheNewFrame ( ProfileData *prof )
{
int total;
prof->frames++;
if ( prof->totalTime > prof->longestFrame )
{
prof->nextLongestFrame = prof->longestFrame;
prof->nextLongestFramePages = prof->longestFramePages;
prof->nextLongestFrameBytes = prof->longestFrameBytes;
prof->longestFrame = prof->totalTime ;
prof->longestFrameBytes = prof->totalDataBytes;
prof->longestFramePages = prof->pageCount;
}
else if ( prof->totalTime > prof->nextLongestFrame )
{
prof->nextLongestFrame = prof->totalTime ;
prof->nextLongestFrameBytes = prof->totalDataBytes;
prof->nextLongestFramePages = prof->pageCount;
}
prof->pageCount = 0;
if ( (total = prof->hits + prof->misses ))
{
prof->HitPercent = (prof->hits *100) / total;
}
prof->BytesPerFrame = prof->totalFrameBytes / prof->frames;
if ( prof->frames > 3*30 )
{
prof->totalFrameBytes = 0;
prof->frames = 0;
}
if ( ! (prof->frames % 30) )
{
prof->hits = 0;
prof->misses = 0;
}
if ( prof->totalTime > prof->update )
{
int ms;
ms = (int) ( (prof->totalTime *1000 )/prof->freq);
prof->TotalBytesPerSecond = (int) (((unsigned __int64) prof->totalDataBytes *1000)/ ms);
prof->totalDataBytes = 0;
prof->totalTime = 0;
ms = (int) ((prof->totalDecompTime *1000 )/prof->freq) ;
if ( ms )
{
prof->DecompBytesPerSecond = (int) (((unsigned __int64) prof->totalDecompBytes *1000)/ ms);
}
else
{
prof->DecompBytesPerSecond = 0;
}
prof->totalDecompBytes = 0;
prof->totalDecompTime = 0;
ms = (int) ((prof->totalLoadTime *1000 )/prof->freq );
if ( ms )
{
prof->LoadBytesPerSecond = (int) (((unsigned __int64)prof->totalLoadBytes *1000)/ ms);
}
else
{
prof->LoadBytesPerSecond = 0;
}
prof->totalLoadBytes = 0;
prof->totalLoadTime = 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheLoadStart ( ProfileData *prof, int bytes )
{
QueryPerformanceCounter( (LARGE_INTEGER*)&prof->start );
prof->dbytes = bytes;
prof->start_decomp = 0;
prof->pageCount++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheAddLoadBytes ( ProfileData *prof, int bytes )
{
prof->dbytes += bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheDecompress ( ProfileData *prof, int bytes )
{
QueryPerformanceCounter( (LARGE_INTEGER*)&prof->start_decomp );
prof->lbytes = bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheLoadEnd ( ProfileData *prof )
{
QueryPerformanceCounter( (LARGE_INTEGER*)&prof->end );
prof->totalTime += prof->end - prof->start;
prof->totalDataBytes += prof->dbytes;
prof->totalFrameBytes += prof->dbytes;
if ( prof->start_decomp )
{
prof->totalLoadTime += prof->start_decomp - prof->start;
prof->totalDecompTime += prof->end - prof->start_decomp;
prof->totalLoadBytes += prof->lbytes;
prof->totalDecompBytes += prof->dbytes;
}
else
{
prof->totalLoadTime += prof->end - prof->start;
prof->totalLoadBytes += prof->dbytes;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheMiss ( ProfileData *prof )
{
prof->misses++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheHit ( ProfileData *prof )
{
prof->hits++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheAddPage ( ProfileData *prof )
{
prof->pagesUsed++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheRemovePage ( ProfileData *prof )
{
prof->pagesUsed--;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheFill ( ProfileData *prof, int bytes )
{
prof->cacheUsed += bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheRemove ( ProfileData *prof, int bytes )
{
prof->cacheUsed -= bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheText ( ProfileData *prof, void ( *print) ( char *text ) )
{
char buf[1024];
int used;
int filled;
print ("Audio Cache Stats\n");
sprintf( buf, "Hits: %d%%\n", prof->HitPercent );
print ( buf );
if ( prof->numPages )
{
used = (prof->pagesUsed *100)/prof->numPages;
}
else
{
used = 0;
}
if ( prof->pagesUsed * prof->pageSize )
{
filled = (prof->cacheUsed *100)/ (prof->pagesUsed * prof->pageSize );
}
else
{
filled = 0;
}
sprintf( buf, "Used: %d%% (%d%%)\n", used, filled );
print ( buf );
sprintf( buf, "KbPS: %d.%02d (%d.%02d,%d.%02d)\n",
prof->TotalBytesPerSecond/1024, ((prof->TotalBytesPerSecond%1024)*100)/1024,
prof->LoadBytesPerSecond/1024, ((prof->LoadBytesPerSecond%1024)*100)/1024,
prof->DecompBytesPerSecond/1024, ((prof->DecompBytesPerSecond%1024)*100)/1024);
print ( buf );
sprintf( buf, "KPF: %d.%02d\n",
prof->BytesPerFrame/1024, ((prof->BytesPerFrame%1024)*100)/1024 );
print ( buf );
sprintf( buf, " LF: %d.%02ds; %d pages; %d Kb\n",
(int) (prof->longestFrame/prof->freq), (int)(((prof->longestFrame % prof->freq)*100)/prof->freq),
prof->longestFramePages, prof->longestFrameBytes/1024 );
print ( buf );
sprintf( buf, "NLF: %d.%02ds; %d pages; %d Kb\n",
(int) (prof->nextLongestFrame/prof->freq), (int) (((prof->nextLongestFrame % prof->freq)*100)/prof->freq),
prof->nextLongestFramePages, prof->nextLongestFrameBytes/1024 );
print ( buf );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheUpdateInterval ( ProfileData *prof, int mseconds )
{
prof->update = (prof->freq * mseconds )/ 1000;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static ProfStamp calc_ticks ( ProfStamp start, ProfStamp end )
{
if ( start < end )
{
return end - start;
}
return ((ProfStamp)0xffffffffffffffff) - start + end ;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void calc_stats ( ProfileCPU &prof )
{
if ( prof.lastCPU )
{
prof.cpuUsage = (int) ((prof.lastTicks*((ProfStamp)1000))/prof.lastCPU);
}
else
{
prof.cpuUsage = 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUInit ( ProfileCPU &prof )
{
memset ( &prof, 0, sizeof ( ProfileCPU ));
if ( !QueryPerformanceFrequency( (LARGE_INTEGER*) &prof.freq ))
{
prof.freq = 0;
}
prof.updateInterval = SECONDS(1);
if ( prof.freq )
{
prof.overflowInterval = SECONDS ( (((ProfStamp) 0xffffffffffffffff) / prof.freq) );
if ( prof.overflowInterval < prof.updateInterval )
{
prof.updateInterval = prof.overflowInterval;
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUDeinit ( ProfileCPU &prof )
{
prof;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUStart ( ProfileCPU &prof )
{
if ( prof.state == PROF_STATE_IDLE )
{
QueryPerformanceCounter( (LARGE_INTEGER*)&prof.start );
if ( prof.lastStart )
{
prof.totalCPUTicks += calc_ticks ( prof.lastStart, prof.start );
}
prof.lastStart = prof.start;
prof.state = PROF_STATE_PROFILING;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUPause ( ProfileCPU &prof )
{
if ( prof.state == PROF_STATE_PROFILING )
{
ProfStamp end;
QueryPerformanceCounter( (LARGE_INTEGER*) &end );
prof.totalTicks += calc_ticks ( prof.start, end );
prof.state = PROF_STATE_PAUSED;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUResume ( ProfileCPU &prof )
{
if ( prof.state == PROF_STATE_PAUSED )
{
QueryPerformanceCounter( (LARGE_INTEGER*) &prof.start );
prof.state = PROF_STATE_PROFILING;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUEnd ( ProfileCPU &prof )
{
ProfStamp end;
QueryPerformanceCounter( (LARGE_INTEGER*) &end );
if ( prof.state != PROF_STATE_IDLE )
{
if ( prof.start && prof.totalCPUTicks )
{
prof.totalTicks += calc_ticks ( prof.start, end );
}
prof.state = PROF_STATE_IDLE;
}
TimeStamp now = AudioGetTime();
TimeStamp lastUpdate = now - prof.lastUpdate;
if ( lastUpdate > prof.updateInterval )
{
prof.lastUpdate = now;
if ( lastUpdate < prof.overflowInterval )
{
// we can use the data
prof.lastTicks = prof.totalTicks;
prof.lastCPU = prof.totalCPUTicks;
calc_stats ( prof );
}
prof.totalTicks = 0;
prof.totalCPUTicks = 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int ProfileCPUUsage ( ProfileCPU &prof )
{
return prof.cpuUsage;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int ProfileCPUTicks ( ProfileCPU &prof )
{
prof;
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUSetName ( ProfileCPU &prof, const char *name )
{
strncpy ( prof.name, name, MAX_PROF_NAME );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUPrint ( ProfileCPU &prof, void ( *print) ( char *text ) )
{
char buffer[200];
if ( prof.freq )
{
sprintf ( buffer, "%s : CPU %3d.%1d / %I64d", prof.name, prof.cpuUsage/10, prof.cpuUsage%10, prof.lastTicks );
}
else
{
sprintf ( buffer, "%s : CPU (no timer)" );
}
print ( buffer );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
#endif
@@ -0,0 +1,632 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: <filename> **
** **
** Created by: 04/05/96 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <memory.h>
#include <stdio.h>
#include <string.h>
#include <wpaudio/altypes.h>
#include <wpaudio/memory.h>
#include <wpaudio/time.h>
#include <wpaudio/source.h>
#include <wsys/file.h>
//#include "asimp3\mss.h"
//#include "asimp3\mp3dec.h"
// 'assignment within condition expression'.
#pragma warning(disable : 4706)
DBG_DECLARE_TYPE ( AudioSample )
DBG_DECLARE_TYPE ( AudioFormat )
DBG_DECLARE_TYPE ( AudioFrame )
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
//
// Sample rate in samples/second for [MPEG25][MPEG version][value]
//
static const int sample_rate[2][2][4] =
{{
{ 22050L,24000L,16000L,22050L },
{ 44100L,48000L,32000L,44100L }
},
{
{ 11025L,12000L, 8000L,11025L },
{ 44100L,48000L,32000L,44100L }
}};
//
// Bit rate in bits/second for [MPEG version][value]
//
static const int bit_rate[2][15] =
{
{ 0L,8000L,16000L,24000L,32000L,40000L,48000L,56000L,64000L,80000L,96000L,112000L,128000L,144000L,160000L }
,
{ 0L,32000L,40000L,48000L,56000L,64000L,80000L,96000L,112000L,128000L,160000L,192000L,224000L,256000L,320000L }
};
/*****************************************************************************
** Public Data **
*****************************************************************************/
const short MSADPCM_StdCoef[7][2] = {
{ 256, 0},
{ 512,-256},
{ 0, 0},
{ 192, 64},
{ 240, 0},
{ 460,-208},
{ 392,-232}
};
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioSample* AudioCreateSample( uint bytes )
{
AudioSample *sample;
DBG_ASSERT ( bytes > 0 );
ALLOC_STRUCT ( sample, AudioSample );
AudioSampleInit ( sample );
sample->Bytes = bytes;
if ( ! ( sample->Data = ( char *) AudioMemAlloc ( sample->Bytes ) ))
{
goto error;
}
return sample;
error:
if ( sample )
{
AudioSampleDestroy ( sample );
}
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioSampleDestroy ( AudioSample *sample )
{
DBG_ASSERT_TYPE ( sample, AudioSample );
if ( sample->Data )
{
AudioMemFree ( sample->Data );
}
AudioMemFree ( sample );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioSampleInit ( AudioSample *sample )
{
DBG_ASSERT ( sample != NULL );
DBG_SET_TYPE ( sample, AudioSample );
sample->Data = NULL;
sample->Bytes = 0;
sample->Format = NULL;
sample->Attribs = NULL;
ListInit ( &sample->Frames );
#ifdef _DEBUG
sample->name[0] = 0;
#endif
}
#ifndef IG_FINAL_RELEASE
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioSampleSetName ( AudioSample *sample, const char *orig_name )
{
int diff;
char *buffer = NULL;
char *name;
DBG_ASSERT_TYPE ( sample, AudioSample );
buffer = (char *) AudioMemAlloc ( strlen ( orig_name ) + 1);
name = buffer;
sample->name[0] = 0;
if ( name )
{
char *ptr;
strcpy ( name, orig_name );
ptr = strrchr ( name, '.' );
if ( ptr )
{
*ptr = 0;
}
ptr = strrchr ( name, '\\' );
if ( ptr )
{
name = ptr + 1;
}
if ( ( diff = (strlen ( name ) - (sizeof(sample->name) - 1))) > 0 )
{
strcpy ( sample->name, "...");
name = name + diff + 3;
strcat ( sample->name, name );
}
else
{
strcpy ( sample->name, name );
}
}
if ( buffer )
{
AudioMemFree ( buffer );
}
}
#endif
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioSampleAddFrame ( AudioSample *sample, AudioFrame *frame )
{
DBG_ASSERT_TYPE ( sample, AudioSample );
DBG_ASSERT_TYPE ( frame, AudioFrame );
ListAddToTail ( &sample->Frames, &frame->nd );
sample->Bytes += frame->Bytes;
frame->sample = sample;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
AudioFrame* AudioSampleFirstFrame ( AudioSample *sample )
{
DBG_ASSERT_TYPE ( sample, AudioSample );
return (AudioFrame *) ListNodeNext ( &sample->Frames );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioSampleDeinit ( AudioSample *sample )
{
DBG_ASSERT_TYPE ( sample, AudioSample );
DBG_INVALIDATE_TYPE ( sample );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioFormatBytes ( AudioFormat *format, TimeStamp time )
{
DBG_ASSERT_TYPE ( format, AudioFormat );
return (int) ( ((TimeStamp)format->BytesPerSecond*time)/(TimeStamp)SECONDS(1));
}
/******************************************************************/
/* */
/* */
/******************************************************************/
TimeStamp AudioFormatTime ( AudioFormat *format, int bytes )
{
DBG_ASSERT_TYPE ( format, AudioFormat );
if ( format->BytesPerSecond )
{
return (((TimeStamp)bytes)*(TimeStamp)SECONDS(1))/(TimeStamp)format->BytesPerSecond;
}
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioFormatInit ( AudioFormat *format )
{
DBG_ASSERT ( format != NULL );
memset ( format, 0, sizeof ( AudioFormat));
DBG_SET_TYPE ( format, AudioFormat );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioFormatUpdate ( AudioFormat *format )
{
DBG_ASSERT_TYPE ( format, AudioFormat );
DBG_ASSERT ( format->Channels != 0 );
DBG_ASSERT ( format->SampleWidth >0 );
DBG_ASSERT ( format->Rate >0 );
DBG_ASSERT ( format->Compression < AUDIO_COMPRESS_MAX_ID );
if ( format->Compression != AUDIO_COMPRESS_MP3 )
{
format->BytesPerSecond = format->Channels*format->SampleWidth*format->Rate;
if ( format->Compression == AUDIO_COMPRESS_IMA_ADPCM
|| format->Compression == AUDIO_COMPRESS_MS_ADPCM )
{
format->BytesPerSecond >>= 2; // 4:1 compression
}
}
else
{
int mpeg1 = (W_BitsGet ( format->cdata.mp3.Header, 1, 19 ));
int bitrateindex = W_BitsGet ( format->cdata.mp3.Header, 4, 12 );
format->BytesPerSecond = bit_rate[mpeg1][bitrateindex] / 8;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioFrameInit ( AudioFrame *frame, void *data, int bytes )
{
DBG_ASSERT_PTR ( frame );
DBG_SET_TYPE ( frame, AudioFrame );
frame->Bytes = bytes;
frame->Data = data;
ListNodeInit ( &frame->nd );
frame->sample = NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void AudioFrameDeinit ( AudioFrame *frame )
{
DBG_ASSERT_TYPE ( frame, AudioFrame );
frame->sample = NULL;
DBG_INVALIDATE_TYPE ( frame );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
#define MAX_SYNC_SEARCH (10*1024) // max bytes that will be searched for the sync
int AudioFormatReadMP3File ( File *file, AudioFormat *format, int *datasize )
{
unsigned char buffer[MAX_SYNC_SEARCH+3];
int bytes;
int pos;
unsigned int header = 0;
int bitrateindex = 0; // initialize to prevent compiler warning
int sampling_frequency = 0; // initialize to prevent compiler warning
int layer;
int data_start = file->position ();
bytes = file->read ( buffer, sizeof (buffer ));
pos = 0;
while ( !header && bytes >= 4 )
{
unsigned char mask = 0xFF;
// find next sync
while ( bytes >= 3 )
{
if ( (buffer[pos]&mask) == mask )
{
if ( mask == 0xE0 )
{
pos--;
bytes++;
//header = (buffer[pos] << 24) || (buffer[pos+1] << 16) || (buffer[pos+2] << 8) || buffer[pos+3];
header = MAKEID ( buffer[pos], buffer[pos+1], buffer[pos+2], buffer[pos+3]);
break;
}
mask = 0xE0;
}
else
{
mask = 0xFF;
}
pos++;
bytes--;
}
// validate the header
bitrateindex = W_BitsGet ( header, 4, 12 );
sampling_frequency = W_BitsGet ( header, 2, 10 );
layer = (W_BitsGet ( header, 2, 17 ));
if ( bitrateindex == 0x0f || sampling_frequency == 0x03 || layer != 1)
{
header = 0;
pos++;
bytes--;
continue;
}
}
if (!header )
{
return FALSE;
}
int mpeg25 = !(W_BitsGet ( header, 1, 20 ));
int mpeg1 = (W_BitsGet ( header, 1, 19 ));
int mode = (W_BitsGet ( header, 2, 6 ));
format->Compression = AUDIO_COMPRESS_MP3;
format->SampleWidth = 2;
format->Channels = (mode == 3) ? 1 : 2;
format->BytesPerSecond = bit_rate[mpeg1][bitrateindex] / 8;
format->Rate = sample_rate[mpeg25][mpeg1][sampling_frequency];
format->Flags = mAUDIO_FORMAT_PCM;
format->cdata.mp3.Header = header;
AudioFormatUpdate ( format );
if ( datasize )
{
*datasize = file->size() - (data_start + pos) ;
}
file->seek ( data_start+pos, File::START );
return TRUE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioFormatSeekToPos ( File *file, const AudioFormat *format, int pos, int data_start )
{
if ( pos )
{
int block_size = 0;
if ( format->Compression == AUDIO_COMPRESS_MP3 )
{
AudioFormat tformat;
file->seek ( pos+data_start, File::START );
AudioFormatInit ( &tformat );
int found = FALSE;
while ( !found )
{
if ( !AudioFormatReadMP3File ( file, &tformat, NULL ) )
{
break;
}
if ( AudioFormatSame ( &tformat, format ) )
{
found = TRUE;
break;
}
file->seek ( 1, File::CURRENT );
}
if ( !found )
{
pos = 0;
}
else
{
pos = file->seek ( 0, File::CURRENT ) - data_start ;
}
}
else
{
switch ( format->Compression )
{
case AUDIO_COMPRESS_NONE:
block_size = format->Channels*format->SampleWidth;
break;
case AUDIO_COMPRESS_IMA_ADPCM:
case AUDIO_COMPRESS_MS_ADPCM:
block_size = format->cdata.adpcm.BlockSize;
break;
}
if ( block_size > 1 )
{
pos = ( pos / block_size ) *block_size;
}
}
}
file->seek ( pos + data_start, File::START );
return pos;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int AudioFormatSame ( const AudioFormat *f1, const AudioFormat *f2 )
{
if ( (f1->Rate != f2->Rate )
|| (f1->Compression != f2->Compression )
|| (f1->SampleWidth != f2->SampleWidth )
|| (f1->Channels != f2->Channels )
|| (f1->Flags != f2->Flags ) )
{
return FALSE;
}
if ( f1->Compression == AUDIO_COMPRESS_IMA_ADPCM && (f1->cdata.adpcm.BlockSize != f2->cdata.adpcm.BlockSize))
{
return FALSE;
}
if ( f1->Compression == AUDIO_COMPRESS_MP3 && (f1->cdata.mp3.Header != f2->cdata.mp3.Header))
{
return FALSE;
}
return TRUE;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,220 @@
/*
** Command & Conquer Generals Zero Hour(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) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: <module> (<prefix>_) **
** **
** Version: $ID$ **
** **
** File name: audtimer.cpp **
** **
** Created by: 04/??/99 TR **
** **
** Description: <description> **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <assert.h>
#include <wpaudio/time.h>
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
static TimeStamp lastTime = 0;
static TimeStamp interval = 0;
static TimeStamp timeOut = 0;
static TimeStamp (*timerFunc)( void ) = NULL;// set to either highResGetTime or
// failsafeGetTime at initialization
static LONGLONG timerMilliSecScale; // res counter millisecond scaling factor
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
static TimeStamp failsafeGetTime( void );
static TimeStamp highResGetTime( void );
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
static TimeStamp highResGetTime( void )
{
LARGE_INTEGER count;
union
{
TimeStamp timeStamp;
LARGE_INTEGER largeInt;
}
myTime;
// read the high res counter
QueryPerformanceCounter(&count);
// convert high res ticks to number of milliseconds
myTime.largeInt.QuadPart = count.QuadPart / timerMilliSecScale;
return myTime.timeStamp;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static TimeStamp failsafeGetTime( void )
{
static volatile TimeStamp time = (TimeStamp) 0x100000000; // last time value
static unsigned int* const pl = (unsigned int* const) &time; // low word of time
static unsigned int* const ph = (unsigned int* const) ((unsigned int)&time + 4); // high word of time
unsigned int now, lw, hw, called;
static volatile unsigned int calls = 0;
calls++;
retry:
called = calls;
hw = *ph; // read high word of time stamp
lw = *pl; // read low word of time stamp
if ( called != calls)
{
// AudioGetTime() has been re-entered. Cannot trust lw and lh values
goto retry;
}
reread:
now = timeGetTime ();
if ( now < lw )
{
// wrap round
hw++; // increment high word by one
}
*ph = hw;
*pl = now;
if ( called != calls )
{
// re-entered. cannot trust *ph and *pl to be correct
called = calls;
goto reread;
}
return time;
}
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
//
// Initialize the high resolution timer by querying the system for it's
// availability. If one does exist then we set the game timer function
// to 'highResGetTime' otherwise we use the original code at 'failsafeGetTime'.
// For the hi res counter we precalculate the millisecond scaling factor to
// convert hi res ticks to millisecond usage.
void InitAudioTimer( void )
{
LARGE_INTEGER freq;
// does hardware exist for high res counter?
if (QueryPerformanceFrequency(&freq))
{
// calculate timer ticks per second
timerMilliSecScale = freq.QuadPart / (LONGLONG) SECONDS(1);
timerFunc = highResGetTime;
}
else
{
// no high res timer, use old code instead
timerFunc = failsafeGetTime;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
TimeStamp AudioGetTime( void )
{
return timerFunc ? timerFunc() : 0 ;
}
@@ -0,0 +1,508 @@
/*
** Command & Conquer Generals Zero Hour(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;
}
@@ -0,0 +1,377 @@
# Microsoft Developer Studio Project File - Name="WPAudio" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=WPAudio - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "WPAudio.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "WPAudio.mak" CFG="WPAudio - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "WPAudio - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "WPAudio - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE "WPAudio - Win32 Internal" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "WPAudio"
# PROP Scc_LocalPath "..\.."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "WPAudio - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /W3 /WX /GX /O2 /Ob2 /I "..\..\include" /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_RELEASE" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "WPAudio - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "WPAudio - Win32 Internal"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Internal"
# PROP BASE Intermediate_Dir "Internal"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Internal"
# PROP Intermediate_Dir "Internal"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /W3 /WX /GX /O2 /Ob1 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "_INTERNAL" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "WPAudio - Win32 Release"
# Name "WPAudio - Win32 Debug"
# Name "WPAudio - Win32 Internal"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\AUD_Assert.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Attributes.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Cache.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Channel.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Device.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_DSoundDriver.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Events.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Level.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_List.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Lock.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Memory.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Profiler.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Source.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_StreamBuffering.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Streamer.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Time.cpp
# End Source File
# Begin Source File
SOURCE=.\AUD_Windows.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\..\Include\WPAudio\Altypes.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Attributes.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Cache.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Channel.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Debug.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Defs.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Device.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Driver.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Errors.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Events.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Handle.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Level.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\List.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Lock.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Memory.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Profiler.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Search.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Source.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\StreamBuffering.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Streamer.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Thread.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Time.h
# End Source File
# Begin Source File
SOURCE=..\..\Include\WPAudio\Win32.h
# End Source File
# End Group
# Begin Group "Asimp3"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\Asimp3\Asimp3asm.asm
!IF "$(CFG)" == "WPAudio - Win32 Release"
# Begin Custom Build
InputDir=.\Asimp3
OutDir=.\Release
InputPath=.\Asimp3\Asimp3asm.asm
BuildCmds= \
$(InputDir)\bin\ml /nologo /coff /Cp /Zm /c /W2 /Zi /Fo$(OutDir)\asi_x86.obj $(InputPath) \
$(InputDir)\bin\ml /nologo /coff /Cp /Zm /c /W2 /Zi /DAMD /Fo$(OutDir)\asi_amd.obj $(InputPath) \
"$(OutDir)\asi_x86.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
"$(OutDir)\asi_amd.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
# End Custom Build
!ELSEIF "$(CFG)" == "WPAudio - Win32 Debug"
# Begin Custom Build
InputDir=.\Asimp3
OutDir=.\Debug
InputPath=.\Asimp3\Asimp3asm.asm
BuildCmds= \
$(InputDir)\bin\ml /nologo /coff /Cp /Zm /c /W2 /Zi /Fo$(OutDir)\asi_x86.obj $(InputPath) \
$(InputDir)\bin\ml /nologo /coff /Cp /Zm /c /W2 /Zi /DAMD /Fo$(OutDir)\asi_amd.obj $(InputPath) \
"$(OutDir)\asi_x86.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
"$(OutDir)\asi_amd.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
# End Custom Build
!ELSEIF "$(CFG)" == "WPAudio - Win32 Internal"
# Begin Custom Build
InputDir=.\Asimp3
OutDir=.\Internal
InputPath=.\Asimp3\Asimp3asm.asm
BuildCmds= \
$(InputDir)\bin\ml /nologo /coff /Cp /Zm /c /W2 /Zi /Fo$(OutDir)\asi_x86.obj $(InputPath) \
$(InputDir)\bin\ml /nologo /coff /Cp /Zm /c /W2 /Zi /DAMD /Fo$(OutDir)\asi_amd.obj $(InputPath) \
"$(OutDir)\asi_x86.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
"$(OutDir)\asi_amd.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
# End Custom Build
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\Asimp3\Datatbl.h
# End Source File
# Begin Source File
SOURCE=.\Asimp3\Imssapi.h
# End Source File
# Begin Source File
SOURCE=.\Asimp3\Mp3api.cpp
# End Source File
# Begin Source File
SOURCE=.\Asimp3\Mp3dec.cpp
# End Source File
# Begin Source File
SOURCE=.\Asimp3\Mp3dec.h
# End Source File
# Begin Source File
SOURCE=.\Asimp3\Mss.h
# End Source File
# Begin Source File
SOURCE=.\Asimp3\Mssasi.h
# End Source File
# Begin Source File
SOURCE=.\Asimp3\Rib.h
# End Source File
# End Group
# End Target
# End Project