Torque3D Documentation / _generateds / sfxALBuffer.cpp

sfxALBuffer.cpp

Engine/source/sfx/openal/sfxALBuffer.cpp

More...

Detailed Description

  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/openal/sfxALBuffer.h"
 25#include "sfx/openal/sfxALVoice.h"
 26#include "sfx/openal/sfxALDevice.h"
 27#include "sfx/sfxDescription.h"
 28#include "console/console.h"
 29
 30
 31//#define DEBUG_SPEW
 32
 33
 34SFXALBuffer* SFXALBuffer::create(   const OPENALFNTABLE &oalft,
 35                                    const ThreadSafeRef< SFXStream>& stream,
 36                                    SFXDescription* description,
 37                                    bool useHardware )
 38{
 39   if( !_sfxFormatToALFormat( stream->getFormat() ) )
 40   {
 41      Con::errorf( "SFXALBuffer::create() - SFXFormat not supported by OpenAL" );
 42      return NULL;
 43   }
 44
 45   SFXALBuffer *buffer = new SFXALBuffer( oalft,
 46                                          stream,
 47                                          description,
 48                                          useHardware );
 49
 50   return buffer;
 51}
 52
 53SFXALBuffer::SFXALBuffer(  const OPENALFNTABLE &oalft, 
 54                           const ThreadSafeRef< SFXStream>& stream,
 55                           SFXDescription* description,
 56                           bool useHardware )
 57   :  Parent( stream, description ),
 58      mIs3d( description->mIs3D ),
 59      mUseHardware( useHardware ),
 60      mOpenAL( oalft )
 61{
 62   // Set up device buffers.
 63
 64   if( !isStreaming() )
 65      mOpenAL.alGenBuffers( 1, &mALBuffer );
 66}
 67
 68SFXALBuffer::~SFXALBuffer()
 69{
 70   if( _getUniqueVoice() )
 71      _getUniqueVoice()->stop();
 72
 73   // Release buffers.
 74   if ( mOpenAL.alIsBuffer( mALBuffer ))
 75      mOpenAL.alDeleteBuffers( 1, &mALBuffer );
 76
 77   while( mFreeBuffers.size() )
 78   {
 79      ALuint buffer = mFreeBuffers.last();
 80      mOpenAL.alDeleteBuffers( 1, &buffer );
 81      mFreeBuffers.pop_back();
 82   }
 83}
 84
 85void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
 86{
 87   using namespace SFXInternal;
 88   
 89   if( !num )
 90      return;
 91   
 92   // If this is not a streaming buffer, just load the data into our single
 93   // static buffer.
 94   
 95   if( !isStreaming() )
 96   {
 97      SFXStreamPacket* packet = packets[ num - 1 ];
 98      
 99      ALenum alFormat = _sfxFormatToALFormat( getFormat() );
100      AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
101      
102      mOpenAL.alBufferData( mALBuffer, alFormat,
103         packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
104         
105      destructSingle( packet );
106      return;
107   }
108
109   MutexHandle mutex;
110   mutex.lock( &_getUniqueVoice()->mMutex, true );
111
112   // Unqueue processed packets.
113
114   ALuint source = _getUniqueVoice()->mSourceName;
115   ALint numProcessed;
116   mOpenAL.alGetSourcei( source, AL_BUFFERS_PROCESSED, &numProcessed );
117   
118   for( U32 i = 0; i < numProcessed; ++ i )
119   {
120      // Unqueue the buffer.
121      
122      ALuint buffer;
123      mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
124      
125      // Update the sample offset on the voice.
126      
127      ALint size;
128      mOpenAL.alGetBufferi( buffer, AL_SIZE, &size );
129      _getUniqueVoice()->mSampleOffset += size / getFormat().getBytesPerSample();
130      
131      // Push the buffer onto the freelist.
132      
133      mFreeBuffers.push_back( buffer );
134   }
135
136   // Queue buffers.
137
138   for( U32 i = 0; i < num; ++ i )
139   {
140      SFXStreamPacket* packet = packets[ i ];
141      
142      // Allocate a buffer.
143      
144      ALuint buffer;
145      if( mFreeBuffers.size() )
146      {
147         buffer = mFreeBuffers.last();
148         mFreeBuffers.pop_back();
149      }
150      else
151         mOpenAL.alGenBuffers( 1, &buffer );
152         
153      // Upload the data.
154      
155      ALenum alFormat = _sfxFormatToALFormat( getFormat() );
156      AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
157      AssertFatal( mOpenAL.alIsBuffer( buffer ), "SFXALBuffer::write() - buffer invalid" );
158      
159      mOpenAL.alBufferData( buffer, alFormat,
160         packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
161      
162      destructSingle( packet );
163      
164      // Queue the buffer.
165      
166      mOpenAL.alSourceQueueBuffers( source, 1, &buffer );
167   }
168}
169
170void SFXALBuffer::_flush()
171{
172   AssertFatal( isStreaming(), "SFXALBuffer::_flush() - not a streaming buffer" );
173   AssertFatal( SFXInternal::isSFXThread(), "SFXALBuffer::_flush() - not on SFX thread" );
174
175   #ifdef DEBUG_SPEW
176   Platform::outputDebugString( "[SFXALBuffer] Flushing buffer" );
177   #endif
178
179   _getUniqueVoice()->_stop();
180
181   MutexHandle mutex;
182   mutex.lock( &_getUniqueVoice()->mMutex, true );
183
184   ALuint source = _getUniqueVoice()->mSourceName;
185
186   ALint numQueued;
187   mOpenAL.alGetSourcei( source, AL_BUFFERS_QUEUED, &numQueued );
188
189   for( U32 i = 0; i < numQueued; ++ i )
190   {
191      ALuint buffer;
192      mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
193      mFreeBuffers.push_back( buffer );
194   }
195
196   _getUniqueVoice()->mSampleOffset = 0;
197   
198   //RD: disabling hack for now; rewritten queueing should be able to cope
199   #if 0 //def TORQUE_OS_MAC
200   
201   //WORKAROUND: Ugly hack on Mac.  Apparently there's a bug in the OpenAL implementation
202   // that will cause AL_BUFFERS_PROCESSED to not be reset as it should be causing write()
203   // to fail.  Brute-force this and just re-create the source.  Let's pray that nobody
204   // issues any concurrent state changes on the voice resulting in us losing state here.
205   
206   ALuint newSource;
207   alGenSources( 1, &newSource );
208   
209   #define COPY_F( name ) \
210   { \
211      F32 val; \
212      mOpenAL.alGetSourcef( source, name, &val ); \
213      mOpenAL.alSourcef( source, name, val ); \
214   }
215   
216   #define COPY_FV( name ) \
217   { \
218      VectorF val; \
219      mOpenAL.alGetSourcefv( source, name, val ); \
220      mOpenAL.alSourcefv( source, name, val ); \
221   }
222   
223   COPY_F( AL_REFERENCE_DISTANCE );
224   COPY_F( AL_MAX_DISTANCE );
225   COPY_F( AL_GAIN );
226   COPY_F( AL_PITCH );
227   COPY_F( AL_CONE_INNER_ANGLE );
228   COPY_F( AL_CONE_OUTER_ANGLE );
229   COPY_F( AL_CONE_OUTER_GAIN );
230   
231   COPY_FV( AL_VELOCITY );
232   COPY_FV( AL_POSITION );
233   COPY_FV( AL_DIRECTION );
234   
235   mSourceName = newSource;
236   source );
237
238   #endif
239}
240