/*
** 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 .
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: (_) **
** **
** Version: $ID$ **
** **
** File name: audstrm.cpp **
** **
** Created by: 11/10/95 TR **
** **
** Description: **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include
#include
#include
#include
#include
#include
// 'assignment within condition expression'.
#pragma warning(disable : 4706)
DBG_DECLARE_TYPE ( STM_SBUFFER )
DBG_DECLARE_TYPE ( STM_ACCESS )
DBG_DECLARE_TYPE ( STM_STREAM )
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
static STM_SBUFFER* STM_next_sbuffer ( STM_SBUFFER * sbuf );
static void STM_stream_init ( STM_STREAM * stm );
static void STM_stream_reset ( STM_STREAM * stm );
static void STM_access_init ( STM_STREAM * stm, STM_ACCESS *access, int id );
static void STM_access_reset ( STM_ACCESS *access, STM_SBUFFER *first );
static void STM_access_return_to_start ( STM_ACCESS *access );
static void STM_sbuffer_init ( STM_SBUFFER * buf );
static void STM_sbuffer_reset( STM_SBUFFER *sbuf );
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
static STM_SBUFFER* STM_next_sbuffer ( STM_SBUFFER * sbuf )
{
STM_STREAM *stm;
STM_SBUFFER *head;
DBG_Function ("STM_next_sbuffer");
DBG_ASSERT_TYPE ( sbuf, STM_SBUFFER );
stm = sbuf->stream;
head = (STM_SBUFFER *) &stm->buffer_list;
sbuf = (STM_SBUFFER *)sbuf->nd.next;
if ( sbuf == head )
{
sbuf = (STM_SBUFFER *)sbuf->nd.next;
if (sbuf == head )
{
return NULL;
}
}
return sbuf;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void STM_stream_init ( STM_STREAM * stm )
{
int i;
/*DBG_Function ("STM_stream_init"); */
DBG_SET_TYPE ( stm, STM_STREAM );
ListInit ( &stm->buffer_list );
LockInit ( &stm->ref );
/* init access structs */
for ( i = 0; i < vSTM_MAX_ACCESSORS; i++)
{
STM_access_init ( stm, &stm->access[i], i );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_stream_reset( STM_STREAM* stm )
{
STM_SBUFFER *head,
*first,
*buf;
DBG_Function ("STM_StreamReset");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
head = (STM_SBUFFER *) &stm->buffer_list;
if ( (first = (STM_SBUFFER *) head->nd.next) == head )
{
first = NULL;
}
if ( first ) /* there is at least one buffer */
{
int id = 0;
buf = first;
while ( buf != head )
{
STM_sbuffer_reset ( buf );
buf->id = id++;
buf = (STM_SBUFFER *) buf->nd.next;
}
}
{ /* reset the access interfaces */
int i;
for ( i = 0; i < vSTM_MAX_ACCESSORS; i++)
{
STM_access_reset ( &stm->access[i], first );
}
/* kick start the IN accessor */
stm->access[vSTM_ACCESS_ID_IN].bytes_in += stm->bytes;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void STM_access_init ( STM_STREAM * stm, STM_ACCESS *access, int id )
{
DBG_Function ("STM_access_init");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
DBG_SET_TYPE ( access, STM_ACCESS );
access->stream = stm;
DBG_CODE
(
LockInit ( &access->in_service ); /* we use the ref to stop nesting */
)
LockInit ( &access->ref );
access->last_error = vNO_ERROR;
access->id = id;
access->mode = vSTM_ACCESS_MODE_UPDATE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void STM_access_reset( STM_ACCESS *access, STM_SBUFFER *first )
{
DBG_Function ("STM_access_reset");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
access->start_buffer = first;
access->bytes_in = W_UINT_MAX -1000;
access->bytes_out = access->bytes_in;
access->position = 0;
STM_access_return_to_start ( access );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void STM_access_return_to_start ( STM_ACCESS *access )
{
access->access_pos = 0;
access->SBuffer = access->start_buffer;
if ( access->start_buffer )
{
access->Block.Data = access->start_buffer->region[access->id].Data;
}
else
{
access->Block.Data = NULL;
}
access->Block.Bytes = 0;
W_FlagsClear ( access->flags, mSTM_ACCESS_TOP_OF_START);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void STM_sbuffer_init ( STM_SBUFFER *buf )
{
DBG_SET_TYPE ( buf, STM_SBUFFER );
ListNodeInit ( &buf->nd );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void STM_sbuffer_reset( STM_SBUFFER *sbuf )
{
int i;
DBG_Function ("STM_sbuffer_reset");
DBG_ASSERT_TYPE ( sbuf, STM_SBUFFER );
/* init access structs */
for ( i = 0; i < vSTM_MAX_ACCESSORS; i++)
{
sbuf->region[i].Data = sbuf->data_region.Data;
sbuf->region[i].Bytes = sbuf->data_region.Bytes;
}
}
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
STM_STREAM* STM_StreamCreate( void )
{
STM_STREAM *stm;
DBG_Function ("STM_StreamCreate");
MEM_ALLOC_STRUCT ( stm, STM_STREAM, mMEM_INTERNAL| vMEM_ANY );
STM_stream_init ( stm );
/* that was simple ;-) */
return stm;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_StreamDestroy( STM_STREAM* stm )
{
DBG_Function ("STM_StreamDestroy");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
DBG_ASSERT ( ! (stm->flags & mSTM_STREAM_FAKE )); /* you can not destroy a fake stream */
DBG_ASSERT ( !Locked ( &stm->ref) ); /* you are trying to destroy a stream that is still being accessed */
STM_StreamDestroyBuffers ( stm );
DBG_CODE
(
int i;
for ( i = 0; i < vSTM_MAX_ACCESSORS; i++)
{
DBG_INVALIDATE_TYPE ( &stm->access[i] ); /* ensure that nobody tries to use an accessor after it is dead */
}
)
DBG_INVALIDATE_TYPE ( stm );
MEM_Free ( stm );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_StreamDestroyBuffers( STM_STREAM* stm )
{
STM_SBUFFER *buf,
*head;
DBG_Function ("STM_StreamDestroy");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
DBG_ASSERT ( !Locked ( &stm->ref) ); /* you are trying to destroy a stream that is still being accessed */
head = (STM_SBUFFER *) &stm->buffer_list;
while ( ( buf = (STM_SBUFFER *) head->nd.next) != head )
{
STM_SBufferRemove ( buf );
STM_SBufferDestroy ( buf );
}
STM_StreamReset ( stm );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_StreamReset( STM_STREAM* stm )
{
DBG_Function ("STM_StreamReset");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
DBG_ASSERT ( !Locked ( &stm->ref )); /* you cannot reset the stream will it's in use */
STM_stream_reset ( stm );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_StreamAddSBuffer( STM_STREAM* stm, STM_SBUFFER *sbuf )
{
DBG_Function ("STM_StreamAddSBuffer");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
DBG_ASSERT_TYPE ( sbuf, STM_SBUFFER );
DBG_ASSERT ( !(ListNodeInList ( &sbuf->nd ))); /* buffer is already in a list */
ListNodeAppend ( (ListNode *) &stm->buffer_list, &sbuf->nd );
stm->buffers++;
stm->bytes += sbuf->data_region.Bytes;
sbuf->stream = stm;
W_FlagsClear ( stm->flags, mSTM_STREAM_RESET_DONE ); /* make sure that a reset is performed again */
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_StreamCreateSBuffers( STM_STREAM* stm, int num_buffers, int buf_size, int align )
{
int bcount = 0;
STM_SBUFFER *buf;
DBG_Function ("STM_StreamAddBuffers");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
DBG_ASSERT ( num_buffers > 0 );
DBG_ASSERT ( buf_size > 0 );
DBG_ASSERT ( align >= 0 );
while (num_buffers--)
{
if (! (buf = STM_SBufferCreate ( buf_size, align )))
{
break;
}
STM_StreamAddSBuffer ( stm, buf );
bcount++;
}
return bcount;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
STM_ACCESS* STM_StreamAcquireAccess ( STM_STREAM *stm, int access_id )
{
STM_ACCESS *access;
DBG_Function ("STM_StreamAcquireAccess");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
DBG_ASSERT ( access_id >= 0); /* ilegal value */
DBG_ASSERT ( access_id < vSTM_MAX_ACCESSORS ); /* legal values are vSTM_ACCESS_ID_OUT or vSTM_ACCESS_ID_IN */
access = &stm->access[access_id];
if ( Locked ( &access->ref ) ) /* someone has already acquired access */
{
DBGPRINTF (( "%s access to stream failed. Access already acquired.\n",access->id == vSTM_ACCESS_ID_IN ? "Write" : "Read" ));
return NULL;
}
DBG_CODE
(
if ( !stm->buffers)
{
msg_assert ( FALSE, ( "Trying to acquire a stream with no buffers") );
}
) /* you must add at least one buffer to a stream before you can use it */
/* if this is the first time the stream has been acquired then perform a reset on the buffers */
if ( !Locked ( &stm->ref ) )
{
STM_stream_reset ( stm );
}
LockAcquire ( &access->ref ); /* mark access interface as in use */
LockAcquire ( &stm->ref ); /* mark stream as in use */
return access;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint STM_StreamTotalBytesIn ( STM_STREAM *stm )
{
DBG_Function ("STM_StreamTotalBytesIn");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
return STM_AccessTotalBytes (&stm->access[vSTM_ACCESS_ID_OUT]);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint STM_StreamTotalBytesTillFull ( STM_STREAM *stm )
{
DBG_Function ("STM_StreamTotalBytesTillFull");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
return STM_AccessTotalBytes (&stm->access[vSTM_ACCESS_ID_IN]);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint STM_StreamTotalBytes ( STM_STREAM *stm )
{
DBG_Function ("STM_StreamTotalBytes");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
return stm->bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_StreamFull ( STM_STREAM *stm )
{
DBG_Function ("STM_StreamFull");
DBG_ASSERT_TYPE ( stm, STM_STREAM );
return STM_StreamTotalBytesTillFull( stm ) == 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
STM_SBUFFER* STM_SBufferCreate( int bytes, int align )
{
STM_SBUFFER *buf;
DBG_Function ("STM_SBufferCreate");
DBG_ASSERT ( bytes > 0 );
DBG_ASSERT ( align >= 0 );
MEM_ALLOC_STRUCT ( buf, STM_SBUFFER, mMEM_INTERNAL | vMEM_ANY );
DBG_SET_TYPE ( buf, STM_SBUFFER );
STM_sbuffer_init ( buf );
/* allocate the buffer, add space for alignment */
buf->buffer_memory = (uint8 *) AudioMemAlloc ( bytes + ALIGN_UPBY(1,align));
if ( !buf->buffer_memory )
{
goto error;
}
buf->align = align;
buf->data_region.Data = ( uint8 *)ALIGN_UPBY ( buf->buffer_memory, align);
buf->data_region.Bytes = bytes;
return buf;
error:
if ( buf )
{
STM_SBufferDestroy ( buf );
}
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_SBufferDestroy( STM_SBUFFER *sbuf )
{
DBG_Function ("STM_SBufferDestroy");
DBG_ASSERT_TYPE ( sbuf, STM_SBUFFER );
DBG_ASSERT ( !ListNodeInList( &sbuf->nd )); /* you must remove the buffer from its stream */
if ( sbuf->buffer_memory )
{
MEM_Free ( sbuf->buffer_memory );
}
DBG_INVALIDATE_TYPE ( sbuf );
MEM_Free ( sbuf );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_SBufferRemove( STM_SBUFFER *sbuf )
{
STM_STREAM *stm;
DBG_Function ("STM_SBufferRemove");
DBG_ASSERT_TYPE ( sbuf, STM_SBUFFER );
DBG_ASSERT ( ListNodeInList ( &sbuf->nd )); /* buffer is not presently in a stream */
DBG_ASSERT ( sbuf->stream != NULL ); /* bad data */
DBG_ASSERT ( !Locked ( &sbuf->stream->ref)); /* stream is in use */
ListNodeRemove ( &sbuf->nd );
stm = sbuf->stream;
sbuf->stream = NULL;
stm->buffers--;
stm->bytes -= sbuf->data_region.Bytes;
DBG_ASSERT ( stm->bytes >= 0 ); /* somethings gone very wrong */
DBG_ASSERT ( stm->buffers >= 0 ); /* somethings gone very wrong */
W_FlagsClear ( stm->flags, mSTM_STREAM_RESET_DONE ); /* make sure that a reset is performed again */
}
/******************************************************************/
/* */
/* */
/******************************************************************/
STM_SBUFFER* STM_SBufferNext( STM_SBUFFER *sbuf )
{
DBG_Function ("STM_SBufferNext");
DBG_ASSERT_TYPE ( sbuf, STM_SBUFFER );
DBG_ASSERT ( sbuf->stream != NULL ); /* buffer is not currently in a stream */
return STM_next_sbuffer ( sbuf );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_AccessRelease ( STM_ACCESS *access )
{
DBG_Function ("STM_AccessRelease");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( Locked ( &access->ref ) ); /* already released, or was never acquired */
LockRelease ( &access->ref );
LockRelease ( &access->stream->ref );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessSetMode ( STM_ACCESS *access, int mode )
{
DBG_Function ("STM_AccessSetMode");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( mode >= 0 ); /* invalid mode */
DBG_ASSERT ( mode < vSTM_ACCESS_MAX_MODES ); /* see vSTM_ACCESS_MODE_?? in wcore/stream.h */
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
access->mode = mode;
return vNO_ERROR;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessMode ( STM_ACCESS *access )
{
DBG_Function ("STM_AccessMode");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
return access->mode;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessID ( STM_ACCESS *access )
{
DBG_Function ("STM_AccessID");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
return access->id;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessTransfer( STM_ACCESS* access, void *data, int bytes )
{
int transfer,
transfered = 0;
uint8 *data8;
DBG_Function ("STM_AccessTransfer");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( data != NULL );
DBG_ASSERT ( bytes > 0);
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
data8 = (uint8 *) data;
STM_AccessGetBlock ( access );
do
{
/* how much can we transfer this block */
if ( (transfer = access->Block.Bytes) > bytes )
{
transfer = bytes;
}
if ( !transfer )
{
break; /* stream has been exhuasted */
}
/* do the transfer */
switch ( access->id )
{
case vSTM_ACCESS_ID_IN:
{
memcpy ( access->Block.Data, data8, transfer );
break;
}
case vSTM_ACCESS_ID_OUT:
default: /* all accessor default to out */
{
memcpy ( data8, access->Block.Data, transfer );
break;
}
}
/* advance pointers */
STM_AccessAdvance ( access, transfer );
data8 += transfer;
/* record work done */
bytes -= transfer;
transfered += transfer;
} while ( bytes );
return transfered;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessFileTransfer( STM_ACCESS* access, File *file, int bytes, int *transfered)
{
int transfer;
DBG_Function ("STM_AccessFileTransfer");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( file != NULL );
DBG_ASSERT ( bytes >= 0);
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
STM_AccessGetBlock ( access );
int dummy;
if ( !transfered )
{
transfered = &dummy;
}
*transfered = 0;
do
{
if ( (transfer = access->Block.Bytes) > bytes )
{
transfer = bytes;
}
if ( !transfer )
{
break; /* stream has been exhuasted */
}
switch ( access->id )
{
case vSTM_ACCESS_ID_IN:
{
transfer = file->read ( access->Block.Data, transfer );
if ( transfer < 0 )
{
access->last_error = ERROR_CODE_FAIL;
}
break;
}
case vSTM_ACCESS_ID_OUT:
default: /* all accessor default to out */
{
transfer = file->write ( access->Block.Data, transfer );
if ( transfer < 0 )
{
access->last_error = ERROR_CODE_FAIL;
}
break;
}
}
if ( !transfer )
{
return STM_EOF;
}
if ( transfer == -1 )
{
return STM_FAIL;
}
/* do the transfer */
STM_AccessAdvance ( access, transfer );
bytes -= transfer;
*transfered += transfer;
} while ( bytes );
return STM_OK;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessGetError ( STM_ACCESS *access )
{
DBG_Function ("STM_AccessGetError");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
return access->last_error;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessUpdate ( STM_ACCESS *access )
{
STM_SBUFFER *sbuf;
int bytes_to_update;
int bytes_updated;
STM_ACCESS *up_stream_accessor;
DBG_Function ("STM_AccessUpdate");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
if ( (bytes_to_update = access->access_pos ) == 0)
{
return 0; /* no updating to perform */
}
/* first thing to do is to tell the up stream accessor that there is more
buffer area avaiable for him to process */
up_stream_accessor = STM_AccessUpStreamAccessor ( access );
access->bytes_out += bytes_to_update; /* reduce our byte count accordingly */
up_stream_accessor->bytes_in += bytes_to_update;
/* now move our start buffer to its new posistion */
sbuf = access->start_buffer ;
DBG_ASSERT ( sbuf != NULL ); /* fubar */
bytes_updated = bytes_to_update;
do
{
STM_REGION *region;
region = &sbuf->region[access->id];
if ( region->Bytes <= bytes_to_update )
{
bytes_to_update -= region->Bytes;
/* reset the current sbuffer region and move on to the next */
region->Data = sbuf->data_region.Data; /* reset back to top of buffer */
region->Bytes = sbuf->data_region.Bytes;
sbuf = STM_next_sbuffer ( sbuf );
}
else
{
/* adjust start of data pointer and bytes accordingly */
region->Data += bytes_to_update;
region->Bytes -= bytes_to_update;
bytes_to_update = 0; /* no more bytes to up date */
}
} while ( bytes_to_update );
access->start_buffer = sbuf; /* update to new start buffer */
STM_AccessReturnToStart ( access ); /* resycn access */
return bytes_updated;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessAdvance ( STM_ACCESS *access, int bytes_to_advance )
{
int bytes_advanced = 0,
bytes_available,
advance;
int total_bytes;
int ok = TRUE;
DBG_Function ("STM_AccessAdvance");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( bytes_to_advance >= 0);
total_bytes = STM_AccessTotalBytes ( access );
DBG_ASSERT ( access->access_pos <= total_bytes );
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
if ( (bytes_available = total_bytes - access->access_pos ) == 0)
{
/* we are at the end of the data */
access->Block.Bytes = 0;
return 0;
}
DBG_ASSERT ( bytes_available >= 0 );
if ( bytes_available < bytes_to_advance )
{
bytes_to_advance = bytes_available;
}
DBG_ASSERT ( access->SBuffer != NULL ); /* fubar */
do
{
STM_REGION *buf_region;
buf_region = &access->SBuffer->region[access->id];
/* update block Bytes to real value */
if ( access->flags & mSTM_ACCESS_TOP_OF_START )
{
access->Block.Bytes = bytes_available; /* this must be a valid range as total_bytes
cannot be greater then the total stream bytes */
}
else
{
int actual_bytes =buf_region->Bytes - ( (uint) access->Block.Data - (uint) buf_region->Data );
if ( actual_bytes < bytes_available )
{
access->Block.Bytes = actual_bytes;
}
else
{
access->Block.Bytes = bytes_available;
}
}
/* advance access */
if ( (advance = bytes_to_advance) == 0 )
{
break; /* we are done */
}
if ( advance >= access->Block.Bytes )
{
advance = access->Block.Bytes;
/* move on to next buffer */
access->SBuffer = STM_next_sbuffer ( access->SBuffer );
if ( access->SBuffer == access->start_buffer )
{
/* this is a special case where we have come back round
to the start buffer. This means that area we are interested in
the area at the top of the buffer */
W_FlagsSet ( access->flags, mSTM_ACCESS_TOP_OF_START);
access->Block.Data = access->SBuffer->data_region.Data; /* this is the top of the buffer */
}
else
{
access->Block.Data = access->SBuffer->region[access->id].Data;
}
}
else
{
access->Block.Data += advance;
}
bytes_to_advance -= advance;
bytes_advanced += advance;
bytes_available -= advance;
} while ( ok );
access->access_pos += bytes_advanced; /* update our position */
access->position += bytes_advanced;
if ( access->position >= STM_StreamTotalBytes(access->stream) )
{
access->position = access->position % STM_StreamTotalBytes ( access->stream );
}
if ( (access->access_pos )&& (STM_AccessMode ( access ) == vSTM_ACCESS_MODE_UPDATE) )
{
STM_AccessUpdate ( access );
}
return bytes_advanced;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_AccessReturnToStart ( STM_ACCESS *access )
{
DBG_Function ("STM_AccessReturnToStart");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
STM_access_return_to_start ( access );
STM_AccessAdvance ( access, 0 ); /* make sure data block is valid */
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessNextBlock ( STM_ACCESS *access )
{
DBG_Function ("STM_AccessNextBlock");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
STM_AccessGetBlock ( access );
if ( access->Block.Bytes )
{
STM_AccessAdvance ( access, access->Block.Bytes );
}
return ERROR_CODE_FAIL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_AccessGetBlock ( STM_ACCESS *access )
{
DBG_Function ("STM_AccessGetBlock");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
STM_AccessAdvance ( access, 0 ); /* kick start access */
return access->Block.Bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint STM_AccessTotalBytes ( STM_ACCESS *access )
{
uint total_bytes,
bytes_in,
bytes_out;
DBG_Function ("STM_AccessTotalBytes");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
bytes_in = access->bytes_in;
bytes_out = access->bytes_out;
if ( (bytes_in < bytes_out))
{
total_bytes = (W_UINT_MAX - bytes_out) +1 + bytes_in;
}
else
{
total_bytes = bytes_in - bytes_out;
}
return total_bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint STM_AccessPosition ( STM_ACCESS *access )
{
DBG_ASSERT_TYPE ( access, STM_ACCESS );
return access->position;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
STM_ACCESS* STM_AccessUpStreamAccessor ( STM_ACCESS *access )
{
int id;
DBG_Function ("STM_AccessUpStreamAccessor");
DBG_ASSERT_TYPE ( access, STM_ACCESS );
DBG_ASSERT ( access->id >= 0 );
DBG_ASSERT ( access->id < vSTM_MAX_ACCESSORS ); /* something has gone wrong. id should not be out of range */
DBG_ASSERT ( Locked ( &access->ref ) ); /* you did not re-acquired access*/
if ( (id = access->id + 1 ) == vSTM_MAX_ACCESSORS )
{
id = 0;
}
return &access->stream->access[id];
}
#ifdef _DEBUG
#include
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_ProfileStart ( STM_PROFILE *pf )
{
DBG_Function ("STM_ProfileStart");
DBG_ASSERT ( pf != NULL );
pf->bytes = 0;
pf->last_update = AudioGetTime ();
pf->update_interval = SECONDS(3);
W_FlagsSet ( pf->flags, mSTM_PROFILE_ACTIVE );
pf->rate = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_ProfileStop ( STM_PROFILE *pf )
{
DBG_Function ("STM_ProfileStop");
DBG_ASSERT ( pf != NULL );
W_FlagsClear ( pf->flags, mSTM_PROFILE_ACTIVE );
pf->rate = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void STM_ProfileUpdate ( STM_PROFILE *pf, int bytes )
{
TimeStamp duration;
DBG_Function ("STM_ProfileUpdate");
DBG_ASSERT ( pf != NULL );
if ( pf->flags & mSTM_PROFILE_ACTIVE )
{
duration = AudioGetTime() - pf->last_update;
pf->bytes += bytes;
if ( duration > pf->update_interval )
{
pf->rate = (int) ((pf->bytes * SECONDS(1)) / duration);
pf->last_update = AudioGetTime ();
pf->bytes = 0;
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_ProfileResult ( STM_PROFILE *pf )
{
DBG_Function ("STM_ProfileResult");
DBG_ASSERT ( pf != NULL );
if ( pf->flags & mSTM_PROFILE_ACTIVE )
{
return pf->rate;
}
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int STM_ProfileActive ( STM_PROFILE *pf )
{
return pf->flags & mSTM_PROFILE_ACTIVE ;
}
#endif // _DEBUG