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

View File

@@ -0,0 +1,150 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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 **
*****************************************************************************/

View File

@@ -0,0 +1,230 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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;
}

View File

@@ -0,0 +1,586 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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;
}

View File

@@ -0,0 +1,710 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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

View File

@@ -0,0 +1,288 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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);
}

View File

@@ -0,0 +1,418 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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;
}

View File

@@ -0,0 +1,158 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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

View File

@@ -0,0 +1,277 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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, '.'));
}

View File

@@ -0,0 +1,636 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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

View File

@@ -0,0 +1,632 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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

View File

@@ -0,0 +1,220 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 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 ;
}

View File

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

View File

@@ -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