root/trunk/SMAC/SMACscom.cpp

Revision 1, 15.0 kB (checked in by gbooker, 3 years ago)

Initial Import

Line 
1 /*      Copyright:      © Copyright 2004 Apple Computer, Inc. All rights reserved.
2
3         Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
4                         ("Apple") in consideration of your agreement to the following terms, and your
5                         use, installation, modification or redistribution of this Apple software
6                         constitutes acceptance of these terms.  If you do not agree with these terms,
7                         please do not use, install, modify or redistribute this Apple software.
8
9                         In consideration of your agreement to abide by the following terms, and subject
10                         to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
11                         copyrights in this original Apple software (the "Apple Software"), to use,
12                         reproduce, modify and redistribute the Apple Software, with or without
13                         modifications, in source and/or binary forms; provided that if you redistribute
14                         the Apple Software in its entirety and without modifications, you must retain
15                         this notice and the following text and disclaimers in all such redistributions of
16                         the Apple Software.  Neither the name, trademarks, service marks or logos of
17                         Apple Computer, Inc. may be used to endorse or promote products derived from the
18                         Apple Software without specific prior written permission from Apple.  Except as
19                         expressly stated in this notice, no other rights or licenses, express or implied,
20                         are granted by Apple herein, including but not limited to any patent rights that
21                         may be infringed by your derivative works or by other works in which the Apple
22                         Software may be incorporated.
23
24                         The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
25                         WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
26                         WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27                         PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
28                         COMBINATION WITH YOUR PRODUCTS.
29
30                         IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
31                         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
32                         GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33                         ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
34                         OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
35                         (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
36                         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38 /*=============================================================================
39         SMACscom.cpp
40
41 =============================================================================*/
42
43 //=============================================================================
44 //      Includes
45 //=============================================================================
46 #include <CAConditionalMacros.h>
47
48 #include <string.h>
49
50 #include "SMACscom.h"
51 #include "CADebugMacros.h"
52 #include "CAException.h"
53 #include "SMACSCDUtility.h"
54
55 #if defined( __GNUC__ )
56     #if( __GNUC__ < 3 )
57         #define IS_COMPILER_WORKING     0
58     #else
59         #define IS_COMPILER_WORKING     1
60     #endif
61 #else
62     #define IS_COMPILER_WORKING 1
63 #endif
64
65 #if TARGET_MAC_OS && IS_COMPILER_WORKING
66 #include "PCMBlitterLibDispatch.h"
67 #endif
68
69 #ifndef min
70 #define min(a, b) ((a) < (b) ? (a) : (b))
71 #endif
72
73 //=============================================================================
74 //      SMACscom
75 //=============================================================================
76
77 SMACscom::SMACscom(ComponentInstance inSelf, UInt32 inFormatID)
78 :
79         mSelf(inSelf),
80         mSourceComponent(NULL),
81         mEncoder(NULL),
82         mSourceID(0),
83         mSourceData(NULL),
84         mPacketFrameSize(0),
85         mMaxPacketByteSize(0),
86         mOutputBuffer(NULL)
87 {
88         //      fill out the output ExtendedSoundComponentData
89         memset(&mOutputData, 0, sizeof(ExtendedSoundComponentData));
90         mOutputData.desc.flags = kExtendedSoundData;
91         mOutputData.desc.format = inFormatID;
92         mOutputData.desc.sampleSize = 16;
93         mOutputData.recordSize = sizeof(ExtendedSoundComponentData);
94         mOutputData.extendedFlags = kExtendedSoundBufferSizeValid;
95     mSourceIsExhausted = false;
96 #if TARGET_API_MAC_OSX && TARGET_CPU_PPC       
97         mHasAltiVec = SMACSCDUtility::HasAltiVec();
98 #else
99         mHasAltiVec = false;
100 #endif
101 }
102
103 SMACscom::~SMACscom()
104 {
105         if(mEncoder != NULL)
106         {
107                 CloseComponent(mEncoder);
108         }
109        
110         delete[] mOutputBuffer;
111 }
112
113 void    SMACscom::SetSource(SoundSource inSourceID, ComponentInstance inSourceComponent)
114 {
115         mSourceID = inSourceID;
116         mSourceComponent = inSourceComponent;
117         mSourceData = NULL;
118 }
119
120 void    SMACscom::SetOutput(SoundComponentData* inRequested, SoundComponentData** outActual)
121 {
122         if(inRequested->format == mOutputData.desc.format)
123         {
124                 memset(&mOutputData, 0, sizeof(ExtendedSoundComponentData));
125                 mOutputData.desc = *inRequested;
126                 mOutputData.recordSize = sizeof(ExtendedSoundComponentData);
127                 mOutputData.extendedFlags = kExtendedSoundBufferSizeValid;
128         }
129         else
130         {
131                 *outActual = reinterpret_cast<SoundComponentData*>(&mOutputData);
132                 throw static_cast<ComponentResult>(paramErr);
133         }
134 }
135
136 void    SMACscom::PlaySourceBuffer(SoundSource inSourceID, SoundParamBlock* inPB, SInt32 inActions)
137 {
138         //      get rid of the input data
139         mSourceData = NULL;
140         mOutputData.desc.sampleCount = 0;
141         mOutputData.bufferSize = 0;
142         mOutputData.frameCount = 0;
143         mOutputData.commonFrameSize = 0;
144        
145         ComponentResult theError = SoundComponentPlaySourceBuffer(mSourceComponent, inSourceID, inPB, inActions);
146         ThrowIfError(theError, (CAException)theError, "SMACscom::PlaySourceBuffer: got an error from SoundComponentPlaySourceBuffer");
147 }
148
149 void    SMACscom::StopSource(SInt16 inNumberSources, SoundSource*       inSources)
150 {
151         //      get rid of the input data
152         mSourceData = NULL;
153         mOutputData.desc.sampleCount = 0;
154         mOutputData.bufferSize = 0;
155         mOutputData.frameCount = 0;
156         mOutputData.commonFrameSize = 0;
157        
158         //      reset the encoder
159         if(mEncoder != NULL)
160         {
161                 AudioCodecReset(mEncoder);
162         }
163        
164         ComponentResult theError = SoundComponentStopSource(mSourceComponent, inNumberSources, inSources);
165         ThrowIfError(theError, (CAException)theError, "SMACscom::StopSource: got an error from SoundComponentStopSource");
166 }
167
168 void    SMACscom::GetInfo(SoundSource inSourceID, OSType inSelector, void* outData)
169 {
170         switch(inSelector)
171         {
172                 case siCompressionFactor:
173                         GetCompressionInfo(*static_cast<CompressionInfo*>(outData));
174                         break;
175                
176                 case siCompressionParams:
177                         GetCompressionParams(outData);
178                         break;
179
180                 default:
181                         ThrowIf(mSourceComponent == NULL, siUnknownInfoType, "SMACscom::GetInfo: no source to pass request to")
182                         ComponentResult theError = SoundComponentGetInfo(mSourceComponent, inSourceID, inSelector, outData);
183                         ThrowIfError(theError, (CAException)theError, "SMACscom::GetInfo: got an error from SoundComponentGetInfo");
184                         break;
185         };
186 }
187
188 void    SMACscom::SetInfo(SoundSource inSourceID, OSType inSelector, void* inData)
189 {
190     switch(inSelector)
191     {
192         case siCompressionParams:
193             {
194                 //      process the the new params and produce an initialized
195                 //      AudioCodec instance
196                 ComponentInstance theEncoder = SetCompressionParams(inData);
197                 ThrowIf(theEncoder == NULL, badFormat, "SMACscom::SetInfo: siCompressionParams didn't generate an encoder");
198
199                 //      get rid of the input data
200                 mSourceData = NULL;
201                 mOutputData.desc.sampleCount = 0;
202                 mOutputData.bufferSize = 0;
203                 mOutputData.frameCount = 0;
204                 mOutputData.commonFrameSize = 0;
205
206                 //      close the old encoder if necessary
207                 if((mEncoder != NULL) && (theEncoder != mEncoder))
208                 {
209                     CloseComponent(mEncoder);
210                 }
211                
212                 //      use the new one
213                 mEncoder = theEncoder;
214                
215                 //      get the number of frames in 1 packet of data
216                 UInt32 theSize = sizeof(UInt32);
217                 ComponentResult theError = AudioCodecGetProperty(mEncoder, kAudioCodecPropertyPacketFrameSize, &theSize, &mPacketFrameSize);
218                 ThrowIfError(theError, (CAException)theError, "SMACscom::SetInfo: siCompressionParams got an error from AudioCodecGetProperty while getting the packet frame size");
219                
220                 //      get the maximum number of bytes in 1 packet of data
221                 theSize = sizeof(UInt32);
222                 theError = AudioCodecGetProperty(mEncoder, kAudioCodecPropertyMaximumPacketByteSize, &theSize, &mMaxPacketByteSize);
223                 ThrowIfError(theError, (CAException)theError, "SMACscom::SetInfo: siCompressionParams got an error from AudioCodecGetProperty while getting the maximum packet byte size");
224                
225                 //      toss the old output buffer
226                 delete[] mOutputBuffer;
227                
228                 //      allocate enough space for 1 packet of data, since that's
229                 //      that's all this component will produce per call to GetSourceData
230                 mOutputBuffer = new Byte[mMaxPacketByteSize];
231             }
232             break;
233        
234         case siSourceIsExhausted:
235                         // in this case it seems to be passed by value -- ugh!
236             mSourceIsExhausted = (Boolean)((UInt32)inData);
237             // Now pass this on, so no break!
238         default:
239             ThrowIf(mSourceComponent == NULL, siUnknownInfoType, "SMACscom::SetInfo: no source to pass request to")
240             ComponentResult theError = SoundComponentSetInfo(mSourceComponent, inSourceID, inSelector, inData);
241             ThrowIfError(theError, (CAException)theError, "SMACscom::SetInfo: got an error from SoundComponentSetInfo");
242             break;
243     };
244 }
245
246 void    SMACscom::GetSourceData(SoundComponentData** outData)
247 {
248         ComponentResult theError = 0;
249         UInt32  theNumberOutputPackets = 0;
250         UInt32  theEncoderStatus = 0;
251         UInt32  theActualOutputDataByteSize = 0;
252         UInt32  maxPacketSize = 0;
253 #if !TARGET_MAC_OS || !IS_COMPILER_WORKING
254         float * tempFloatPtr;
255         unsigned long tempULong = 0;
256         float tempFloat;
257 #endif 
258         *outData = NULL;
259        
260         //      make sure we have some source data to start with
261         if(SMACSCDUtility::NeedMoreSourceData(mSourceData))
262         {
263                 theError = SoundComponentGetSourceData(mSourceComponent, &mSourceData);
264                 ThrowIfError(theError, (CAException)theError, "SMACscom::GetSourceData: got an error from SoundComponentGetSourceData");
265         }
266        
267         //      spin until we produce a packet of data or we run completely out of source data
268         UInt32  theFramesProduced = 0;
269         UInt32  theOutputDataByteSize = 0;
270         while(SMACSCDUtility::HasData(mSourceData) && (theFramesProduced < mPacketFrameSize))
271         {
272                 //      stuff as much input data into the encoder as we can
273                 UInt32 theInputDataByteSize = SMACSCDUtility::GetDataByteSize(mSourceData);
274                 UInt32 theNumberOfPackets = 0;
275                 maxPacketSize = min(kMaxInputSamples, theInputDataByteSize/sizeof(SInt16));
276 #if TARGET_MAC_OS && IS_COMPILER_WORKING
277                 NativeInt16ToFloat32( mHasAltiVec, ((short *)(mSourceData->buffer)), mFloatBuffer, maxPacketSize, 16);
278 #else
279                 for (UInt32 i = 0; i < maxPacketSize; i++)
280                 {
281                         tempFloat = (float)(((short *)(mSourceData->buffer))[i]);
282                         tempFloatPtr = &tempFloat;
283                         if (tempFloat != 0.0 && tempFloat != -0.0)
284                         {
285                                 tempULong = *((unsigned long *)tempFloatPtr);
286                                 tempULong -= 0x07800000;
287                                 tempFloatPtr = (float *)(&tempULong);
288                         }
289                         mFloatBuffer[i] = *tempFloatPtr;
290                 }
291 #endif
292                 theInputDataByteSize = maxPacketSize * 4; // this is all we have converted
293                 //theInputDataByteSize *= 2;
294                 theError = AudioCodecAppendInputData(mEncoder, mFloatBuffer, &theInputDataByteSize, &theNumberOfPackets, NULL);
295                 ThrowIfError(theError, (CAException)theError, "SMACscom::GetSourceData: got an error from AudioCodecAppendInputData");
296                
297                 //      update the source data with the amount of data consumed
298                 SMACSCDUtility::ConsumedData(mSourceData, theInputDataByteSize >> 1);
299                
300                 //      see if we can get a packet of output data
301                 theActualOutputDataByteSize = mMaxPacketByteSize;
302                 theNumberOutputPackets = 1;
303                 theEncoderStatus = kAudioCodecProduceOutputPacketFailure;
304                 theError = AudioCodecProduceOutputPackets(mEncoder, mOutputBuffer, &theActualOutputDataByteSize, &theNumberOutputPackets, NULL, &theEncoderStatus);
305                 ThrowIfError(theError, (CAException)theError, "SMACscom::GetSourceData: got an error from AudioCodecProduceOutputPackets");
306                
307                 if(theNumberOutputPackets == 1)
308                 {
309                         //      we produced a full packet of frames, so we're done
310                         theFramesProduced = mPacketFrameSize;
311                         theOutputDataByteSize += theActualOutputDataByteSize;
312                        
313                 }
314                 else
315                 {
316                         //      we didn't get the data, so get more input data if we have to
317                         if(SMACSCDUtility::NeedMoreSourceData(mSourceData))
318                         {
319                                 theError = SoundComponentGetSourceData(mSourceComponent, &mSourceData);
320                                 ThrowIfError(theError, (CAException)theError, "SMACscom::GetSourceData: got an error from SoundComponentGetSourceData");
321                         }
322                 }
323         }
324        
325         if(theFramesProduced < mPacketFrameSize)
326         {
327                 // Tell the encoder to pad with 0s -- this will change once the API is added
328         if (mSourceIsExhausted)
329         {
330             UInt32 theInputDataByteSize = SMACSCDUtility::GetDataByteSize(mSourceData); // better be 0
331             UInt32 theNumberOfPackets = 0;
332                         maxPacketSize = min(kMaxInputSamples, theInputDataByteSize/sizeof(SInt16));
333 #if TARGET_MAC_OS && IS_COMPILER_WORKING
334                         NativeInt16ToFloat32( mHasAltiVec, ((short *)(mSourceData->buffer)), mFloatBuffer, maxPacketSize, 16);
335 #else
336                         for (UInt32 i = 0; i < maxPacketSize; i++)
337                         {
338                                 tempFloat = (float)(((short *)(mSourceData->buffer))[i]);
339                                 tempFloatPtr = &tempFloat;
340                                 if (tempFloat != 0.0 && tempFloat != -0.0)
341                                 {
342                                         tempULong = *((unsigned long *)tempFloatPtr);
343                                         tempULong -= 0x07800000;
344                                         tempFloatPtr = (float *)(&tempULong);
345                                 }
346                                 mFloatBuffer[i] = *tempFloatPtr;
347                         }
348 #endif
349                         theInputDataByteSize = maxPacketSize * 4; // this is all we have converted
350                         //theInputDataByteSize *= 2;
351                         theError = AudioCodecAppendInputData(mEncoder, mFloatBuffer, &theInputDataByteSize, &theNumberOfPackets, NULL);
352             ThrowIfError(theError, (CAException)theError, "SMACscom::GetSourceData: got an error from AudioCodecAppendInputData");
353                 }
354        
355                 //      we ran out of input data, but we still haven't produced enough output data
356                 //      so we have to try one last time to pull on the encoder in case it has
357                 //      some left overs that it can give us
358                 theActualOutputDataByteSize = mMaxPacketByteSize;
359                 theNumberOutputPackets = 1;
360                 theEncoderStatus = kAudioCodecProduceOutputPacketFailure;
361                 theError = AudioCodecProduceOutputPackets(mEncoder, mOutputBuffer, &theActualOutputDataByteSize, &theNumberOutputPackets, NULL, &theEncoderStatus);
362                 ThrowIfError(theError, (CAException)theError, "SMACscom::GetSourceData: got an error from AudioCodecProduceOutputPackets");
363                
364                 if(theNumberOutputPackets == 1)
365                 {
366                         //      we produced a full packet of frames, so we're done
367                         theFramesProduced = mPacketFrameSize;
368                         theOutputDataByteSize += theActualOutputDataByteSize;
369                 }
370         }
371        
372         //      set up the return values if any data was produced
373         if(theFramesProduced > 0)
374         {
375                 mOutputData.desc.buffer = mOutputBuffer;
376                 mOutputData.desc.sampleCount = theFramesProduced;
377                 mOutputData.bufferSize = theOutputDataByteSize;
378                 mOutputData.frameCount = 1;
379                 mOutputData.commonFrameSize = theOutputDataByteSize;
380         mOutputData.desc.numChannels = mSourceData->numChannels;
381                 *outData = reinterpret_cast<SoundComponentData*>(&mOutputData);
382         }
383 }
Note: See TracBrowser for help on using the browser.