Torque3D Documentation / _generateds / sfxInternal.cpp

sfxInternal.cpp

Engine/source/sfx/sfxInternal.cpp

Implementation of async sound I/O.

More...

Namespaces:

namespace

Detailed Description

Implementation of async sound I/O.

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "sfx/sfxInternal.h"
 25#include "sfx/sfxDescription.h"
 26#include "core/util/safeDelete.h"
 27#include "platform/threads/threadPoolAsyncIO.h"
 28
 29
 30/// @file
 31/// Implementation of async sound I/O.
 32
 33
 34//#define DEBUG_SPEW
 35
 36
 37namespace SFXInternal {
 38
 39
 40ThreadSafeRef< SFXUpdateThread>       gUpdateThread;
 41ThreadSafeRef< SFXBufferProcessList>  gBufferUpdateList = new SFXBufferProcessList;
 42ThreadSafeDeque< SFXBuffer*>          gDeadBufferList;
 43
 44
 45//==========================================================================
 46//    SFXAsyncStream implementation.
 47//==========================================================================
 48
 49//--------------------------------------------------------------------------
 50
 51SFXAsyncStream::SFXAsyncStream(  const SFXStreamRef& stream,
 52                                 bool isIncremental,
 53                                 U32 streamPacketLength,
 54                                 U32 numReadAhead,
 55                                 bool isLooping )
 56   : Parent(   stream,
 57               isIncremental
 58               ? streamPacketLength
 59                  * stream->getFormat().getSamplesPerSecond()
 60                  * stream->getFormat().getBytesPerSample()    // Streamed buffer; read in incremental packets.
 61               : stream->getDataLength(),                      // Non-streamed buffer; read entire stream in one packet.
 62               stream->getDataLength()                         // Read all remaining data in stream.
 63               - ( dynamic_cast< IPositionable< U32 >* >( stream.ptr() )
 64                   ? dynamic_cast< IPositionable< U32 >* >( stream.ptr() )->getPosition()
 65                   : 0 ),
 66               numReadAhead,
 67               isLooping,
 68               &THREAD_POOL() ),
 69     mReadSilenceAtEnd( false )
 70{
 71}
 72
 73//--------------------------------------------------------------------------
 74
 75void SFXAsyncStream::_onArrival( SFXStreamPacket* const& packet )
 76{
 77   #ifdef DEBUG_SPEW
 78   Platform::outputDebugString( "[SFXAsyncStream] Packet arrived" );
 79   #endif
 80
 81   Parent::_onArrival( packet );
 82
 83   // Some buffer may be waiting for this data so trigger
 84   // an update.
 85   
 86   if( !mIsStopped )
 87      TriggerUpdate();
 88}
 89
 90//--------------------------------------------------------------------------
 91
 92void SFXAsyncStream::_requestNext()
 93{
 94   #ifdef DEBUG_SPEW
 95   Platform::outputDebugString( "[SFXAsyncStream] Next packet requested" );
 96   #endif
 97
 98   if( !mNumRemainingSourceElements && mReadSilenceAtEnd )
 99   {
100      // Push an artificial packet of silence.
101      
102      SFXStreamPacket* packet = _newPacket( mPacketSize );
103      packet->mIndex = mNextPacketIndex;
104      mNextPacketIndex ++;
105      mReadSilenceAtEnd = false;
106      dMemset( packet->data, 0, packet->size );
107      packet->mIsLast = true;
108      
109      _onArrival( packet );
110   }
111   else
112      Parent::_requestNext();
113}
114
115//==========================================================================
116//    SFXWrapAroundBuffer implementation.
117//==========================================================================
118
119//--------------------------------------------------------------------------
120
121SFXWrapAroundBuffer::SFXWrapAroundBuffer( const ThreadSafeRef< SFXStream>& stream, SFXDescription* description )
122   : Parent( stream, description ),
123     mWriteOffset( 0 )
124{
125   // Determine the device buffer metrics.
126   
127   const U32 maxQueuedPackets = isStreaming() ? SFXAsyncQueue::DEFAULT_STREAM_QUEUE_LENGTH : 1;
128   const U32 packetSize = mAsyncState->mStream->getPacketSize();
129
130   mBufferSize = maxQueuedPackets * packetSize;
131   
132   #ifdef DEBUG_SPEW
133   Platform::outputDebugString( "[SFXWrapAroundBuffer] size=%i, packets=%i",
134      mBufferSize, maxQueuedPackets );
135   #endif
136   
137   // For streaming buffers that are not looping, add a packet of silence to the
138   // source stream.
139
140   if( isStreaming() && !description->mIsLooping )
141      mAsyncState->mStream->setReadSilenceAtEnd( true );
142}
143
144//--------------------------------------------------------------------------
145
146void SFXWrapAroundBuffer::write( SFXStreamPacket* const* packets, U32 num )
147{
148   AssertFatal( SFXInternal::isSFXThread(), "SFXWrapAroundBuffer::write() - not on SFX thread" );
149
150   for( U32 i = 0; i < num; ++ i )
151   {
152      const SFXStreamPacket* packet = packets[ i ];
153      
154      // Determine where in the buffer to copy the data to.  In case we are crossing over
155      // the wrap-around point, we need to copy in two slices.
156
157      U32 offset1    = 0;
158      U32 offset2    = 0;
159      U32 numBytes1  = 0;
160      U32 numBytes2  = 0;
161
162      offset1        = mWriteOffset % mBufferSize;
163      numBytes1      = packet->size;
164
165      if( offset1 + numBytes1 > mBufferSize )
166      {
167         // Crossing wrap-around point.
168         
169         numBytes1   = mBufferSize - offset1;
170         numBytes2   = packet->size - numBytes1;
171      }
172
173      offset2        = offset1 + numBytes1;
174      
175      #ifdef DEBUG_SPEW
176      Platform::outputDebugString( "[SFXWrapAroundBuffer] writing %i bytes from packet #%i at %i (stream offset: %i)",
177         numBytes1, packet->mIndex, offset1, mWriteOffset );
178      #endif
179      
180      // Copy the packet data.
181      
182      _copyData( offset1, packet->data, numBytes1 );
183      if( numBytes2 > 0 )
184      {
185         #ifdef DEBUG_SPEW
186         Platform::outputDebugString( "[SFXWrapAroundBuffer] writing %i more bytes at %i",
187            numBytes2, offset2 );
188         #endif
189         
190         _copyData( offset2, &packet->data[ numBytes1 ], numBytes2 );
191      }
192   
193      dFetchAndAdd( mWriteOffset, packet->size );
194
195      // Free the packet.
196
197      destructSingle( packet );
198   }
199}
200
201} // namespace SFXInternal
202