mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 19:23:59 +00:00
Added unfinished audio code, switching machines
This commit is contained in:
parent
ff05955b00
commit
26f135cb88
160
Sources/CoreAudioSDK/AUOutputBL.cpp
Normal file
160
Sources/CoreAudioSDK/AUOutputBL.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
||||
copyrights in this original Apple software (the "Apple Software"), to use,
|
||||
reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions of
|
||||
the Apple Software. Neither the name, trademarks, service marks or logos of
|
||||
Apple Computer, Inc. may be used to endorse or promote products derived from the
|
||||
Apple Software without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or implied,
|
||||
are granted by Apple herein, including but not limited to any patent rights that
|
||||
may be infringed by your derivative works or by other works in which the Apple
|
||||
Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*=============================================================================
|
||||
AUOutputBL.h
|
||||
|
||||
=============================================================================*/
|
||||
#include "AUOutputBL.h"
|
||||
|
||||
/*
|
||||
struct AudioBufferList
|
||||
{
|
||||
UInt32 mNumberBuffers;
|
||||
AudioBuffer mBuffers[1];
|
||||
};
|
||||
struct AudioBuffer
|
||||
{
|
||||
UInt32 mNumberChannels; // number of interleaved channels in the buffer
|
||||
UInt32 mDataByteSize; // the size of the buffer pointed to by mData
|
||||
void* mData; // the pointer to the buffer
|
||||
};
|
||||
*/
|
||||
|
||||
AUOutputBL::AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames)
|
||||
: mFormat (inDesc),
|
||||
mBufferMemory(NULL),
|
||||
mBufferList (NULL),
|
||||
mNumberBuffers (0), // keep this here, so can ensure integrity of ABL
|
||||
mBufferSize (0),
|
||||
mFrames(inDefaultNumFrames)
|
||||
{
|
||||
mNumberBuffers = mFormat.IsInterleaved() ? 1 : mFormat.NumberChannels();
|
||||
mBufferList = reinterpret_cast<AudioBufferList*>(new Byte[sizeof(UInt32) + (mNumberBuffers * sizeof(AudioBuffer))]);
|
||||
}
|
||||
|
||||
AUOutputBL::~AUOutputBL()
|
||||
{
|
||||
if (mBufferMemory)
|
||||
delete[] mBufferMemory;
|
||||
|
||||
if (mBufferList)
|
||||
delete [] mBufferList;
|
||||
}
|
||||
|
||||
void AUOutputBL::Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated)
|
||||
{
|
||||
UInt32 channelsPerBuffer = mFormat.IsInterleaved() ? mFormat.NumberChannels() : 1;
|
||||
|
||||
if (mBufferMemory == NULL || inWantNullBufferIfAllocated)
|
||||
{
|
||||
mBufferList->mNumberBuffers = mNumberBuffers;
|
||||
AudioBuffer *buf = &mBufferList->mBuffers[0];
|
||||
for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) {
|
||||
buf->mNumberChannels = channelsPerBuffer;
|
||||
buf->mDataByteSize = mFormat.FramesToBytes (inNumFrames);
|
||||
buf->mData = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 nBytes = mFormat.FramesToBytes (inNumFrames);
|
||||
if ((nBytes * mNumberBuffers) > AllocatedBytes())
|
||||
throw OSStatus(-10874);//(kAudioUnitErr_TooManyFramesToProcess);
|
||||
|
||||
mBufferList->mNumberBuffers = mNumberBuffers;
|
||||
AudioBuffer *buf = &mBufferList->mBuffers[0];
|
||||
Byte* p = mBufferMemory;
|
||||
for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) {
|
||||
buf->mNumberChannels = channelsPerBuffer;
|
||||
buf->mDataByteSize = nBytes;
|
||||
buf->mData = p;
|
||||
p += mBufferSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AUOutputBL::Allocate (UInt32 inNumFrames)
|
||||
{
|
||||
if (inNumFrames)
|
||||
{
|
||||
UInt32 nBytes = mFormat.FramesToBytes (inNumFrames);
|
||||
|
||||
if (nBytes <= AllocatedBytes())
|
||||
return;
|
||||
|
||||
// align successive buffers for Altivec and to take alternating
|
||||
// cache line hits by spacing them by odd multiples of 16
|
||||
if (mNumberBuffers > 1)
|
||||
nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10;
|
||||
|
||||
mBufferSize = nBytes;
|
||||
|
||||
UInt32 memorySize = mBufferSize * mNumberBuffers;
|
||||
Byte *newMemory = new Byte[memorySize];
|
||||
memset(newMemory, 0, memorySize); // make buffer "hot"
|
||||
|
||||
Byte *oldMemory = mBufferMemory;
|
||||
mBufferMemory = newMemory;
|
||||
delete[] oldMemory;
|
||||
|
||||
mFrames = inNumFrames;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mBufferMemory) {
|
||||
delete [] mBufferMemory;
|
||||
mBufferMemory = NULL;
|
||||
}
|
||||
mBufferSize = 0;
|
||||
mFrames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
void AUOutputBL::Print()
|
||||
{
|
||||
printf ("AUOutputBL::Print\n");
|
||||
mFormat.Print();
|
||||
printf ("Num Buffers:%d, mFrames:%d, allocatedMemory:%c\n", (int)mBufferList->mNumberBuffers, (int)mFrames, (mBufferMemory != NULL ? 'T' : 'F'));
|
||||
AudioBuffer *buf = &mBufferList->mBuffers[0];
|
||||
for (UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i, ++buf)
|
||||
printf ("\tBuffer:%d, Size:%d, Chans:%d, Buffer:%p\n", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData);
|
||||
}
|
||||
#endif
|
||||
|
116
Sources/CoreAudioSDK/AUOutputBL.h
Normal file
116
Sources/CoreAudioSDK/AUOutputBL.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
||||
copyrights in this original Apple software (the "Apple Software"), to use,
|
||||
reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions of
|
||||
the Apple Software. Neither the name, trademarks, service marks or logos of
|
||||
Apple Computer, Inc. may be used to endorse or promote products derived from the
|
||||
Apple Software without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or implied,
|
||||
are granted by Apple herein, including but not limited to any patent rights that
|
||||
may be infringed by your derivative works or by other works in which the Apple
|
||||
Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*=============================================================================
|
||||
AUOutputBL.h
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#ifndef __AUOutputBL_h__
|
||||
#define __AUOutputBL_h__
|
||||
|
||||
#include "CAStreamBasicDescription.h"
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#else
|
||||
#include <AssertMacros.h>
|
||||
#endif
|
||||
|
||||
// ____________________________________________________________________________
|
||||
//
|
||||
// AUOutputBL - Simple Buffer List wrapper targetted to use with retrieving AU output
|
||||
// Works in one of two ways (both adjustable)... Can use it with NULL pointers, or allocate
|
||||
// memory to receive the data in.
|
||||
|
||||
// Before using this with any call to AudioUnitRender, it needs to be Prepared
|
||||
// as some calls to AudioUnitRender can reset the ABL
|
||||
|
||||
class AUOutputBL {
|
||||
public:
|
||||
|
||||
// you CANNOT use one of these - it will crash!
|
||||
// AUOutputBL ();
|
||||
|
||||
// this is the constructor that you use
|
||||
// it can't be reset once you've constructed it
|
||||
AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames = 512);
|
||||
~AUOutputBL();
|
||||
|
||||
void Prepare ()
|
||||
{
|
||||
Prepare (mFrames);
|
||||
}
|
||||
|
||||
// this version can throw if this is an allocted ABL and inNumFrames is > AllocatedFrames()
|
||||
// you can set the bool to true if you want a NULL buffer list even if allocated
|
||||
// inNumFrames must be a valid number (will throw if inNumFrames is 0)
|
||||
void Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated = false);
|
||||
|
||||
AudioBufferList* ABL() { return mBufferList; }
|
||||
|
||||
// You only need to call this if you want to allocate a buffer list
|
||||
// if you want an empty buffer list, just call Prepare()
|
||||
// if you want to dispose previously allocted memory, pass in 0
|
||||
// then you either have an empty buffer list, or you can re-allocate
|
||||
// Memory is kept around if an Allocation request is less than what is currently allocated
|
||||
void Allocate (UInt32 inNumberFrames);
|
||||
|
||||
UInt32 AllocatedFrames() const { return mFrames; }
|
||||
|
||||
const CAStreamBasicDescription& GetFormat() const { return mFormat; }
|
||||
|
||||
#if DEBUG
|
||||
void Print();
|
||||
#endif
|
||||
|
||||
private:
|
||||
UInt32 AllocatedBytes () const { return (mBufferSize * mNumberBuffers); }
|
||||
|
||||
CAStreamBasicDescription mFormat;
|
||||
Byte* mBufferMemory;
|
||||
AudioBufferList* mBufferList;
|
||||
UInt32 mNumberBuffers;
|
||||
UInt32 mBufferSize;
|
||||
UInt32 mFrames;
|
||||
|
||||
// don't want to copy these.. can if you want, but more code to write!
|
||||
AUOutputBL () {}
|
||||
AUOutputBL (const AUOutputBL &c) {}
|
||||
AUOutputBL& operator= (const AUOutputBL& c) { return *this; }
|
||||
};
|
||||
|
||||
#endif // __AUOutputBL_h__
|
393
Sources/CoreAudioSDK/CAAudioFileFormats.cpp
Normal file
393
Sources/CoreAudioSDK/CAAudioFileFormats.cpp
Normal file
|
@ -0,0 +1,393 @@
|
|||
/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
||||
copyrights in this original Apple software (the "Apple Software"), to use,
|
||||
reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions of
|
||||
the Apple Software. Neither the name, trademarks, service marks or logos of
|
||||
Apple Computer, Inc. may be used to endorse or promote products derived from the
|
||||
Apple Software without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or implied,
|
||||
are granted by Apple herein, including but not limited to any patent rights that
|
||||
may be infringed by your derivative works or by other works in which the Apple
|
||||
Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*=============================================================================
|
||||
CAAudioFileFormats.cpp
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include "CAAudioFileFormats.h"
|
||||
#include <algorithm>
|
||||
#include <ctype.h>
|
||||
|
||||
CAAudioFileFormats *CAAudioFileFormats::sInstance = NULL;
|
||||
|
||||
CAAudioFileFormats *CAAudioFileFormats::Instance()
|
||||
{
|
||||
if (sInstance == NULL)
|
||||
sInstance = new CAAudioFileFormats;
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/*
|
||||
class CompareFileFormatNames {
|
||||
public:
|
||||
bool operator() (const CAAudioFileFormats::FileFormatInfo &a, const CAAudioFileFormats::FileFormatInfo &b)
|
||||
{
|
||||
return CFStringCompare(a.mFileTypeName, b.mFileTypeName,
|
||||
kCFCompareCaseInsensitive | kCFCompareLocalized) == kCFCompareLessThan;
|
||||
}
|
||||
};*/
|
||||
|
||||
static int CompareFileFormatNames(const void *va, const void *vb)
|
||||
{
|
||||
CAAudioFileFormats::FileFormatInfo *a = (CAAudioFileFormats::FileFormatInfo *)va,
|
||||
*b = (CAAudioFileFormats::FileFormatInfo *)vb;
|
||||
return CFStringCompare(a->mFileTypeName, b->mFileTypeName,
|
||||
kCFCompareCaseInsensitive | kCFCompareLocalized);
|
||||
}
|
||||
|
||||
CAAudioFileFormats::CAAudioFileFormats() :
|
||||
mNumFileFormats(0), mFileFormats(NULL)
|
||||
{
|
||||
OSStatus err;
|
||||
UInt32 size;
|
||||
UInt32 *fileTypes = NULL, *writableFormats = NULL, *readableFormats = NULL;
|
||||
int nWritableFormats, nReadableFormats;
|
||||
|
||||
// get all file types
|
||||
err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_WritableTypes, 0, NULL, &size);
|
||||
if (err != noErr) goto bail;
|
||||
mNumFileFormats = size / sizeof(UInt32);
|
||||
mFileFormats = new FileFormatInfo[mNumFileFormats];
|
||||
fileTypes = new UInt32[mNumFileFormats];
|
||||
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_WritableTypes, 0, NULL, &size, fileTypes);
|
||||
if (err != noErr) goto bail;
|
||||
|
||||
// get all writable formats
|
||||
err = AudioFormatGetPropertyInfo(kAudioFormatProperty_EncodeFormatIDs, 0, NULL, &size);
|
||||
if (err != noErr) goto bail;
|
||||
nWritableFormats = size / sizeof(UInt32);
|
||||
writableFormats = new UInt32[nWritableFormats];
|
||||
err = AudioFormatGetProperty(kAudioFormatProperty_EncodeFormatIDs, 0, NULL, &size, writableFormats);
|
||||
if (err != noErr) goto bail;
|
||||
|
||||
// get all readable formats
|
||||
err = AudioFormatGetPropertyInfo(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size);
|
||||
if (err != noErr) goto bail;
|
||||
nReadableFormats = size / sizeof(UInt32);
|
||||
readableFormats = new UInt32[nReadableFormats];
|
||||
err = AudioFormatGetProperty(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size, readableFormats);
|
||||
if (err != noErr) goto bail;
|
||||
|
||||
// get info for each file type
|
||||
for (int i = 0; i < mNumFileFormats; ++i) {
|
||||
FileFormatInfo *ffi = &mFileFormats[i];
|
||||
OSType filetype = fileTypes[i];
|
||||
|
||||
ffi->mFileTypeID = filetype;
|
||||
|
||||
// file type name
|
||||
ffi->mFileTypeName = NULL;
|
||||
size = sizeof(CFStringRef);
|
||||
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_FileTypeName, sizeof(UInt32), &filetype, &size, &ffi->mFileTypeName);
|
||||
if (ffi->mFileTypeName)
|
||||
CFRetain(ffi->mFileTypeName);
|
||||
|
||||
// file extensions
|
||||
size = sizeof(CFArrayRef);
|
||||
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_ExtensionsForType,
|
||||
sizeof(OSType), &filetype, &size, &ffi->mExtensions);
|
||||
if (err)
|
||||
ffi->mExtensions = NULL;
|
||||
|
||||
// file data formats
|
||||
ffi->mNumDataFormats = 0;
|
||||
ffi->mDataFormats = NULL;
|
||||
|
||||
err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AvailableFormatIDs,
|
||||
sizeof(UInt32), &filetype, &size);
|
||||
if (err == noErr) {
|
||||
ffi->mNumDataFormats = size / sizeof(OSType);
|
||||
OSType *formatIDs = new OSType[ffi->mNumDataFormats];
|
||||
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AvailableFormatIDs,
|
||||
sizeof(UInt32), &filetype, &size, formatIDs);
|
||||
if (err == noErr) {
|
||||
ffi->mDataFormats = new DataFormatInfo[ffi->mNumDataFormats];
|
||||
for (int j = 0; j < ffi->mNumDataFormats; ++j) {
|
||||
int k;
|
||||
bool anyBigEndian = false, anyLittleEndian = false;
|
||||
DataFormatInfo *dfi = &ffi->mDataFormats[j];
|
||||
dfi->mFormatID = formatIDs[j];
|
||||
dfi->mReadable = (dfi->mFormatID == kAudioFormatLinearPCM);
|
||||
dfi->mWritable = (dfi->mFormatID == kAudioFormatLinearPCM);
|
||||
for (k = 0; k < nReadableFormats; ++k)
|
||||
if (readableFormats[k] == dfi->mFormatID) {
|
||||
dfi->mReadable = true;
|
||||
break;
|
||||
}
|
||||
for (k = 0; k < nWritableFormats; ++k)
|
||||
if (writableFormats[k] == dfi->mFormatID) {
|
||||
dfi->mWritable = true;
|
||||
break;
|
||||
}
|
||||
|
||||
dfi->mNumVariants = 0;
|
||||
AudioFileTypeAndFormatID tf = { filetype, dfi->mFormatID };
|
||||
err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AvailableStreamDescriptionsForFormat,
|
||||
sizeof(AudioFileTypeAndFormatID), &tf, &size);
|
||||
if (err == noErr) {
|
||||
dfi->mNumVariants = size / sizeof(AudioStreamBasicDescription);
|
||||
dfi->mVariants = new AudioStreamBasicDescription[dfi->mNumVariants];
|
||||
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AvailableStreamDescriptionsForFormat,
|
||||
sizeof(AudioFileTypeAndFormatID), &tf, &size, dfi->mVariants);
|
||||
if (err) {
|
||||
dfi->mNumVariants = 0;
|
||||
delete[] dfi->mVariants;
|
||||
dfi->mVariants = NULL;
|
||||
} else {
|
||||
for (k = 0; k < dfi->mNumVariants; ++k) {
|
||||
AudioStreamBasicDescription *desc = &dfi->mVariants[k];
|
||||
if (desc->mBitsPerChannel > 8) {
|
||||
if (desc->mFormatFlags & kAudioFormatFlagIsBigEndian)
|
||||
anyBigEndian = true;
|
||||
else
|
||||
anyLittleEndian = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dfi->mEitherEndianPCM = (anyBigEndian && anyLittleEndian);
|
||||
}
|
||||
}
|
||||
delete[] formatIDs;
|
||||
}
|
||||
}
|
||||
|
||||
// sort file formats by name
|
||||
qsort(mFileFormats, mNumFileFormats, sizeof(FileFormatInfo), CompareFileFormatNames);
|
||||
bail:
|
||||
delete[] fileTypes;
|
||||
delete[] readableFormats;
|
||||
delete[] writableFormats;
|
||||
}
|
||||
|
||||
// note that the outgoing format will have zero for the sample rate, channels per frame, bytesPerPacket, bytesPerFrame
|
||||
bool CAAudioFileFormats::InferDataFormatFromFileFormat(AudioFileTypeID filetype, CAStreamBasicDescription &fmt)
|
||||
{
|
||||
// if the file format only supports one data format
|
||||
for (int i = 0; i < mNumFileFormats; ++i) {
|
||||
FileFormatInfo *ffi = &mFileFormats[i];
|
||||
if (ffi->mFileTypeID == filetype && ffi->mNumDataFormats == 1) {
|
||||
DataFormatInfo *dfi = &ffi->mDataFormats[0];
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
fmt.mFormatID = dfi->mFormatID;
|
||||
if (dfi->mNumVariants > 0) {
|
||||
// take the first variant as a default
|
||||
fmt = dfi->mVariants[0];
|
||||
if (dfi->mNumVariants > 1 && dfi->mFormatID == kAudioFormatLinearPCM) {
|
||||
// look for a 16-bit variant as a better default
|
||||
for (int j = 0; j < dfi->mNumVariants; ++j) {
|
||||
AudioStreamBasicDescription *desc = &dfi->mVariants[j];
|
||||
if (desc->mBitsPerChannel == 16) {
|
||||
fmt = *desc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CAAudioFileFormats::InferFileFormatFromFilename(CFStringRef filename, AudioFileTypeID &filetype)
|
||||
{
|
||||
bool result = false;
|
||||
CFRange range = CFStringFind(filename, CFSTR("."), kCFCompareBackwards);
|
||||
if (range.location == kCFNotFound) return false;
|
||||
range.location += 1;
|
||||
range.length = CFStringGetLength(filename) - range.location;
|
||||
CFStringRef ext = CFStringCreateWithSubstring(NULL, filename, range);
|
||||
for (int i = 0; i < mNumFileFormats; ++i) {
|
||||
FileFormatInfo *ffi = &mFileFormats[i];
|
||||
if (ffi->MatchExtension(ext)) {
|
||||
filetype = ffi->mFileTypeID;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CFRelease(ext);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CAAudioFileFormats::InferFileFormatFromFilename(const char *filename, AudioFileTypeID &filetype)
|
||||
{
|
||||
if (filename == NULL) return false;
|
||||
CFStringRef cfname = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8);
|
||||
bool result = InferFileFormatFromFilename(cfname, filetype);
|
||||
CFRelease(cfname);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CAAudioFileFormats::InferFileFormatFromDataFormat(const CAStreamBasicDescription &fmt,
|
||||
AudioFileTypeID &filetype)
|
||||
{
|
||||
// if there's exactly one file format that supports this data format
|
||||
FileFormatInfo *theFileFormat = NULL;
|
||||
for (int i = 0; i < mNumFileFormats; ++i) {
|
||||
FileFormatInfo *ffi = &mFileFormats[i];
|
||||
DataFormatInfo *dfi = ffi->mDataFormats, *dfiend = dfi + ffi->mNumDataFormats;
|
||||
for ( ; dfi < dfiend; ++dfi)
|
||||
if (dfi->mFormatID == fmt.mFormatID) {
|
||||
if (theFileFormat != NULL)
|
||||
return false; // ambiguous
|
||||
theFileFormat = ffi; // got a candidate
|
||||
}
|
||||
}
|
||||
if (theFileFormat == NULL)
|
||||
return false;
|
||||
filetype = theFileFormat->mFileTypeID;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CAAudioFileFormats::IsKnownDataFormat(OSType dataFormat)
|
||||
{
|
||||
for (int i = 0; i < mNumFileFormats; ++i) {
|
||||
FileFormatInfo *ffi = &mFileFormats[i];
|
||||
DataFormatInfo *dfi = ffi->mDataFormats, *dfiend = dfi + ffi->mNumDataFormats;
|
||||
for ( ; dfi < dfiend; ++dfi)
|
||||
if (dfi->mFormatID == dataFormat)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CAAudioFileFormats::FileFormatInfo * CAAudioFileFormats::FindFileFormat(UInt32 formatID)
|
||||
{
|
||||
for (int i = 0; i < mNumFileFormats; ++i) {
|
||||
FileFormatInfo *ffi = &mFileFormats[i];
|
||||
if (ffi->mFileTypeID == formatID)
|
||||
return ffi;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CAAudioFileFormats::FileFormatInfo::AnyWritableFormats()
|
||||
{
|
||||
DataFormatInfo *dfi = mDataFormats, *dfiend = dfi + mNumDataFormats;
|
||||
for ( ; dfi < dfiend; ++dfi)
|
||||
if (dfi->mWritable)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
char *OSTypeToStr(char *buf, OSType t)
|
||||
{
|
||||
char *p = buf;
|
||||
char str[4], *q = str;
|
||||
*(UInt32 *)str = EndianU32_NtoB(t);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (isprint(*q) && *q != '\\')
|
||||
*p++ = *q++;
|
||||
else {
|
||||
sprintf(p, "\\x%02x", *q++);
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
int StrToOSType(const char *str, OSType &t)
|
||||
{
|
||||
char buf[4];
|
||||
const char *p = str;
|
||||
int x;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (*p != '\\') {
|
||||
if ((buf[i] = *p++) == '\0') {
|
||||
// special-case for 'aac ': if we only got three characters, assume the last was a space
|
||||
if (i == 3) {
|
||||
--p;
|
||||
buf[i] = ' ';
|
||||
break;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (*++p != 'x') goto fail;
|
||||
if (sscanf(++p, "%02X", &x) != 1) goto fail;
|
||||
buf[i] = x;
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
t = EndianU32_BtoN(*(UInt32 *)buf);
|
||||
return p - str;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
void CAAudioFileFormats::DebugPrint()
|
||||
{
|
||||
for (int i = 0; i < mNumFileFormats; ++i)
|
||||
mFileFormats[i].DebugPrint();
|
||||
}
|
||||
|
||||
void CAAudioFileFormats::FileFormatInfo::DebugPrint()
|
||||
{
|
||||
char ftype[20];
|
||||
char ftypename[64];
|
||||
CFStringGetCString(mFileTypeName, ftypename, sizeof(ftypename), kCFStringEncodingUTF8);
|
||||
printf("File type: '%s' = %s\n Extensions:", OSTypeToStr(ftype, mFileTypeID), ftypename);
|
||||
int i, n = NumberOfExtensions();
|
||||
for (i = 0; i < n; ++i) {
|
||||
GetExtension(i, ftype, sizeof(ftype));
|
||||
printf(" .%s", ftype);
|
||||
}
|
||||
printf("\n Formats:\n");
|
||||
for (i = 0; i < mNumDataFormats; ++i)
|
||||
mDataFormats[i].DebugPrint();
|
||||
}
|
||||
|
||||
void CAAudioFileFormats::DataFormatInfo::DebugPrint()
|
||||
{
|
||||
char buf[20];
|
||||
static char *ny[] = { "not ", "" };
|
||||
printf(" '%s': %sreadable %swritable\n", OSTypeToStr(buf, mFormatID), ny[mReadable], ny[mWritable]);
|
||||
for (int i = 0; i < mNumVariants; ++i) {
|
||||
CAStreamBasicDescription desc(mVariants[i]);
|
||||
desc.PrintFormat(stdout, " ", "");
|
||||
//printf(" %d bytes/frame\n", desc.mBytesPerFrame);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
142
Sources/CoreAudioSDK/CAAudioFileFormats.h
Normal file
142
Sources/CoreAudioSDK/CAAudioFileFormats.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
||||
copyrights in this original Apple software (the "Apple Software"), to use,
|
||||
reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions of
|
||||
the Apple Software. Neither the name, trademarks, service marks or logos of
|
||||
Apple Computer, Inc. may be used to endorse or promote products derived from the
|
||||
Apple Software without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or implied,
|
||||
are granted by Apple herein, including but not limited to any patent rights that
|
||||
may be infringed by your derivative works or by other works in which the Apple
|
||||
Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*=============================================================================
|
||||
CAAudioFileFormats.h
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#ifndef __CAAudioFileFormats_h__
|
||||
#define __CAAudioFileFormats_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#else
|
||||
#include <AudioToolbox.h>
|
||||
#endif
|
||||
#include "CAStreamBasicDescription.h"
|
||||
|
||||
class CAAudioFileFormats {
|
||||
public:
|
||||
struct DataFormatInfo {
|
||||
DataFormatInfo() : mVariants(NULL) { }
|
||||
~DataFormatInfo() { delete[] mVariants; }
|
||||
|
||||
UInt32 mFormatID;
|
||||
int mNumVariants;
|
||||
AudioStreamBasicDescription * mVariants;
|
||||
bool mReadable;
|
||||
bool mWritable;
|
||||
bool mEitherEndianPCM;
|
||||
|
||||
#if DEBUG
|
||||
void DebugPrint();
|
||||
#endif
|
||||
};
|
||||
|
||||
struct FileFormatInfo {
|
||||
FileFormatInfo() : mFileTypeName(NULL), mExtensions(NULL), mDataFormats(NULL) { }
|
||||
~FileFormatInfo() {
|
||||
delete[] mDataFormats;
|
||||
if (mFileTypeName)
|
||||
CFRelease(mFileTypeName);
|
||||
if (mExtensions)
|
||||
CFRelease(mExtensions);
|
||||
}
|
||||
|
||||
AudioFileTypeID mFileTypeID;
|
||||
CFStringRef mFileTypeName;
|
||||
CFArrayRef mExtensions;
|
||||
int mNumDataFormats;
|
||||
DataFormatInfo * mDataFormats;
|
||||
|
||||
int NumberOfExtensions() { return mExtensions ? CFArrayGetCount(mExtensions) : 0; }
|
||||
char * GetExtension(int index, char *buf, int buflen) {
|
||||
CFStringRef cfext = (CFStringRef)CFArrayGetValueAtIndex(mExtensions, index);
|
||||
CFStringGetCString(cfext, buf, buflen, kCFStringEncodingUTF8);
|
||||
return buf;
|
||||
}
|
||||
bool MatchExtension(CFStringRef testExt) { // testExt should not include "."
|
||||
CFIndex n = NumberOfExtensions();
|
||||
for (CFIndex i = 0; i < n; ++i) {
|
||||
CFStringRef ext = (CFStringRef)CFArrayGetValueAtIndex(mExtensions, i);
|
||||
if (CFStringCompare(ext, testExt, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AnyWritableFormats();
|
||||
|
||||
#if DEBUG
|
||||
void DebugPrint();
|
||||
#endif
|
||||
};
|
||||
|
||||
private: // use Instance()
|
||||
CAAudioFileFormats();
|
||||
~CAAudioFileFormats();
|
||||
public:
|
||||
|
||||
bool InferDataFormatFromFileFormat(AudioFileTypeID filetype, CAStreamBasicDescription &fmt);
|
||||
|
||||
bool InferFileFormatFromFilename(const char *filename, AudioFileTypeID &filetype);
|
||||
|
||||
bool InferFileFormatFromFilename(CFStringRef filename, AudioFileTypeID &filetype);
|
||||
|
||||
bool InferFileFormatFromDataFormat(const CAStreamBasicDescription &fmt, AudioFileTypeID &filetype);
|
||||
|
||||
bool IsKnownDataFormat(UInt32 dataFormat);
|
||||
|
||||
#if DEBUG
|
||||
void DebugPrint();
|
||||
#endif
|
||||
|
||||
int mNumFileFormats;
|
||||
FileFormatInfo * mFileFormats;
|
||||
|
||||
FileFormatInfo * FindFileFormat(UInt32 formatID);
|
||||
|
||||
static CAAudioFileFormats * Instance();
|
||||
|
||||
private:
|
||||
static CAAudioFileFormats * sInstance;
|
||||
};
|
||||
|
||||
char * OSTypeToStr(char *buf, UInt32 t);
|
||||
int StrToOSType(const char *str, UInt32 &t);
|
||||
|
||||
#endif // __CAAudioFileFormats_h__
|
528
Sources/CoreAudioSDK/CAStreamBasicDescription.cpp
Normal file
528
Sources/CoreAudioSDK/CAStreamBasicDescription.cpp
Normal file
|
@ -0,0 +1,528 @@
|
|||
/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
||||
copyrights in this original Apple software (the "Apple Software"), to use,
|
||||
reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions of
|
||||
the Apple Software. Neither the name, trademarks, service marks or logos of
|
||||
Apple Computer, Inc. may be used to endorse or promote products derived from the
|
||||
Apple Software without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or implied,
|
||||
are granted by Apple herein, including but not limited to any patent rights that
|
||||
may be infringed by your derivative works or by other works in which the Apple
|
||||
Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*=============================================================================
|
||||
CAStreamBasicDescription.cpp
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include "CAConditionalMacros.h"
|
||||
|
||||
#include "CAStreamBasicDescription.h"
|
||||
#include "CAMath.h"
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CFByteOrder.h>
|
||||
#else
|
||||
#include <CFByteOrder.h>
|
||||
#endif
|
||||
|
||||
#pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it
|
||||
|
||||
const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID,
|
||||
UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
|
||||
UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
|
||||
UInt32 inBitsPerChannel, UInt32 inFormatFlags)
|
||||
{
|
||||
mSampleRate = inSampleRate;
|
||||
mFormatID = inFormatID;
|
||||
mBytesPerPacket = inBytesPerPacket;
|
||||
mFramesPerPacket = inFramesPerPacket;
|
||||
mBytesPerFrame = inBytesPerFrame;
|
||||
mChannelsPerFrame = inChannelsPerFrame;
|
||||
mBitsPerChannel = inBitsPerChannel;
|
||||
mFormatFlags = inFormatFlags;
|
||||
mReserved = 0;
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::PrintFormat(FILE *f, const char *indent, const char *name) const
|
||||
{
|
||||
fprintf(f, "%s%s ", indent, name);
|
||||
char formatID[5];
|
||||
*(UInt32 *)formatID = CFSwapInt32HostToBig(mFormatID);
|
||||
formatID[4] = '\0';
|
||||
fprintf(f, "%2d ch, %6.0f Hz, '%-4.4s' (0x%08X) ",
|
||||
(int)NumberChannels(), mSampleRate, formatID,
|
||||
(int)mFormatFlags);
|
||||
if (mFormatID == kAudioFormatLinearPCM) {
|
||||
bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat);
|
||||
int wordSize = SampleWordSize();
|
||||
const char *endian = (wordSize > 1) ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : "";
|
||||
const char *sign = isInt ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : "";
|
||||
const char *floatInt = isInt ? "integer" : "float";
|
||||
char packed[32];
|
||||
if (wordSize > 0 && PackednessIsSignificant()) {
|
||||
if (mFormatFlags & kLinearPCMFormatFlagIsPacked)
|
||||
sprintf(packed, "packed in %d bytes", wordSize);
|
||||
else
|
||||
sprintf(packed, "unpacked in %d bytes", wordSize);
|
||||
} else
|
||||
packed[0] = '\0';
|
||||
const char *align = (wordSize > 0 && AlignmentIsSignificant()) ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : "";
|
||||
const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : "";
|
||||
const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : "";
|
||||
|
||||
fprintf(f, "%d-bit%s%s %s%s%s%s%s\n",
|
||||
(int)mBitsPerChannel, endian, sign, floatInt,
|
||||
commaSpace, packed, align, deinter);
|
||||
} else if (mFormatID == 'alac') { // kAudioFormatAppleLossless
|
||||
int sourceBits = 0;
|
||||
switch (mFormatFlags)
|
||||
{
|
||||
case 1: // kAppleLosslessFormatFlag_16BitSourceData
|
||||
sourceBits = 16;
|
||||
break;
|
||||
case 2: // kAppleLosslessFormatFlag_20BitSourceData
|
||||
sourceBits = 20;
|
||||
break;
|
||||
case 3: // kAppleLosslessFormatFlag_24BitSourceData
|
||||
sourceBits = 24;
|
||||
break;
|
||||
case 4: // kAppleLosslessFormatFlag_32BitSourceData
|
||||
sourceBits = 32;
|
||||
break;
|
||||
}
|
||||
if (sourceBits)
|
||||
fprintf(f, "from %d-bit source, ", sourceBits);
|
||||
else
|
||||
fprintf(f, "from UNKNOWN source bit depth, ");
|
||||
|
||||
fprintf(f, "%d frames/packet\n", (int)mFramesPerPacket);
|
||||
}
|
||||
else
|
||||
fprintf(f, "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame\n",
|
||||
(int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame);
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
// the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
|
||||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
// the canonical linear PCM format is 32 bit native endian floats
|
||||
ioDescription.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
|
||||
ioDescription.mBytesPerPacket = sizeof(Float32) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mFramesPerPacket = 1;
|
||||
ioDescription.mBytesPerFrame = sizeof(Float32) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mBitsPerChannel = 8 * sizeof(Float32);
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
ioDescription.mSampleRate = 0;
|
||||
ioDescription.mFormatID = 0;
|
||||
ioDescription.mBytesPerPacket = 0;
|
||||
ioDescription.mFramesPerPacket = 0;
|
||||
ioDescription.mBytesPerFrame = 0;
|
||||
ioDescription.mChannelsPerFrame = 0;
|
||||
ioDescription.mBitsPerChannel = 0;
|
||||
ioDescription.mFormatFlags = 0;
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription)
|
||||
{
|
||||
if(fiszero(ioDescription.mSampleRate))
|
||||
{
|
||||
ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
|
||||
}
|
||||
if(ioDescription.mFormatID == 0)
|
||||
{
|
||||
ioDescription.mFormatID = inTemplateDescription.mFormatID;
|
||||
}
|
||||
if(ioDescription.mFormatFlags == 0)
|
||||
{
|
||||
ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
|
||||
}
|
||||
if(ioDescription.mBytesPerPacket == 0)
|
||||
{
|
||||
ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
|
||||
}
|
||||
if(ioDescription.mFramesPerPacket == 0)
|
||||
{
|
||||
ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
|
||||
}
|
||||
if(ioDescription.mBytesPerFrame == 0)
|
||||
{
|
||||
ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
|
||||
}
|
||||
if(ioDescription.mChannelsPerFrame == 0)
|
||||
{
|
||||
ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
|
||||
}
|
||||
if(ioDescription.mBitsPerChannel == 0)
|
||||
{
|
||||
ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate)
|
||||
{
|
||||
switch(inDescription.mFormatID)
|
||||
{
|
||||
case kAudioFormatLinearPCM:
|
||||
{
|
||||
const char* theEndianString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
|
||||
{
|
||||
#if TARGET_RT_LITTLE_ENDIAN
|
||||
theEndianString = "Big Endian";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
theEndianString = "Little Endian";
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* theKindString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
|
||||
{
|
||||
theKindString = (inAbbreviate ? "Float" : "Floating Point");
|
||||
}
|
||||
else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
|
||||
{
|
||||
theKindString = (inAbbreviate ? "SInt" : "Signed Integer");
|
||||
}
|
||||
else
|
||||
{
|
||||
theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer");
|
||||
}
|
||||
|
||||
const char* thePackingString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
|
||||
{
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
|
||||
{
|
||||
thePackingString = "High";
|
||||
}
|
||||
else
|
||||
{
|
||||
thePackingString = "Low";
|
||||
}
|
||||
}
|
||||
|
||||
const char* theMixabilityString = NULL;
|
||||
if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0)
|
||||
{
|
||||
theMixabilityString = "Mixable";
|
||||
}
|
||||
else
|
||||
{
|
||||
theMixabilityString = "Unmixable";
|
||||
}
|
||||
|
||||
if(inAbbreviate)
|
||||
{
|
||||
if(theEndianString != NULL)
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
sprintf(outName, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(outName, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
sprintf(outName, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(outName, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(theEndianString != NULL)
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
sprintf(outName, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(outName, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
sprintf(outName, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(outName, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioFormatAC3:
|
||||
strcpy(outName, "AC-3");
|
||||
break;
|
||||
|
||||
case kAudioFormat60958AC3:
|
||||
strcpy(outName, "AC-3 for SPDIF");
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char* the4CCString = (char*)&inDescription.mFormatID;
|
||||
outName[0] = the4CCString[0];
|
||||
outName[1] = the4CCString[1];
|
||||
outName[2] = the4CCString[2];
|
||||
outName[3] = the4CCString[3];
|
||||
outName[4] = 0;
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
#if CoreAudio_Debug
|
||||
#include "CALogMacros.h"
|
||||
|
||||
void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc)
|
||||
{
|
||||
PrintFloat (" Sample Rate: ", inDesc.mSampleRate);
|
||||
Print4CharCode (" Format ID: ", inDesc.mFormatID);
|
||||
PrintHex (" Format Flags: ", inDesc.mFormatFlags);
|
||||
PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket);
|
||||
PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket);
|
||||
PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame);
|
||||
PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame);
|
||||
PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
|
||||
{
|
||||
bool theAnswer = false;
|
||||
bool isDone = false;
|
||||
|
||||
// note that if either side is 0, that field is skipped
|
||||
|
||||
// format ID is the first order sort
|
||||
if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
|
||||
{
|
||||
if(x.mFormatID != y.mFormatID)
|
||||
{
|
||||
// formats are sorted numerically except that linear
|
||||
// PCM is always first
|
||||
if(x.mFormatID == kAudioFormatLinearPCM)
|
||||
{
|
||||
theAnswer = true;
|
||||
}
|
||||
else if(y.mFormatID == kAudioFormatLinearPCM)
|
||||
{
|
||||
theAnswer = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = x.mFormatID < y.mFormatID;
|
||||
}
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// mixable is always better than non-mixable for linear PCM and should be the second order sort item
|
||||
if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
|
||||
{
|
||||
if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0))
|
||||
{
|
||||
theAnswer = true;
|
||||
isDone = true;
|
||||
}
|
||||
else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
theAnswer = false;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// floating point vs integer for linear PCM only
|
||||
if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
|
||||
{
|
||||
if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
|
||||
{
|
||||
// floating point is better than integer
|
||||
theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// bit depth
|
||||
if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
|
||||
{
|
||||
if(x.mBitsPerChannel != y.mBitsPerChannel)
|
||||
{
|
||||
// deeper bit depths are higher quality
|
||||
theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// sample rate
|
||||
if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate))
|
||||
{
|
||||
if(fnotequal(x.mSampleRate, y.mSampleRate))
|
||||
{
|
||||
// higher sample rates are higher quality
|
||||
theAnswer = x.mSampleRate < y.mSampleRate;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// number of channels
|
||||
if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
|
||||
{
|
||||
if(x.mChannelsPerFrame != y.mChannelsPerFrame)
|
||||
{
|
||||
// more channels is higher quality
|
||||
theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
|
||||
{
|
||||
UInt32 xFlags = x.mFormatFlags;
|
||||
UInt32 yFlags = y.mFormatFlags;
|
||||
|
||||
// match wildcards
|
||||
if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0)
|
||||
return true;
|
||||
|
||||
if (x.mFormatID == kAudioFormatLinearPCM)
|
||||
{
|
||||
// knock off the all clear flag
|
||||
xFlags = xFlags & ~kAudioFormatFlagsAreAllClear;
|
||||
yFlags = yFlags & ~kAudioFormatFlagsAreAllClear;
|
||||
|
||||
// if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit.
|
||||
if (xFlags & yFlags & kAudioFormatFlagIsPacked) {
|
||||
xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh;
|
||||
yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh;
|
||||
}
|
||||
|
||||
// if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit.
|
||||
if (xFlags & yFlags & kAudioFormatFlagIsFloat) {
|
||||
xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger;
|
||||
yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger;
|
||||
}
|
||||
|
||||
// if the bit depth is 8 bits or less and the format is packed, we don't care about endianness
|
||||
if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
|
||||
{
|
||||
xFlags = xFlags & ~kAudioFormatFlagIsBigEndian;
|
||||
}
|
||||
if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
|
||||
{
|
||||
yFlags = yFlags & ~kAudioFormatFlagIsBigEndian;
|
||||
}
|
||||
|
||||
// if the number of channels is 0 or 1, we don't care about non-interleavedness
|
||||
if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) {
|
||||
xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
|
||||
yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
return xFlags == yFlags;
|
||||
}
|
||||
|
||||
bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
|
||||
{
|
||||
// the semantics for equality are:
|
||||
// 1) Values must match exactly
|
||||
// 2) wildcard's are ignored in the comparison
|
||||
|
||||
#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
|
||||
|
||||
return
|
||||
// check the sample rate
|
||||
(fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate))
|
||||
|
||||
// check the format ids
|
||||
&& MATCH(mFormatID)
|
||||
|
||||
// check the format flags
|
||||
&& MatchFormatFlags(x, y)
|
||||
|
||||
// check the bytes per packet
|
||||
&& MATCH(mBytesPerPacket)
|
||||
|
||||
// check the frames per packet
|
||||
&& MATCH(mFramesPerPacket)
|
||||
|
||||
// check the bytes per frame
|
||||
&& MATCH(mBytesPerFrame)
|
||||
|
||||
// check the channels per frame
|
||||
&& MATCH(mChannelsPerFrame)
|
||||
|
||||
// check the channels per frame
|
||||
&& MATCH(mBitsPerChannel) ;
|
||||
}
|
||||
|
||||
bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const
|
||||
{
|
||||
if (interpretingWildcards)
|
||||
return *this == other;
|
||||
return memcmp(this, &other, offsetof(AudioStreamBasicDescription, mReserved)) == 0;
|
||||
}
|
||||
|
||||
bool SanityCheck(const AudioStreamBasicDescription& x)
|
||||
{
|
||||
return (x.mSampleRate >= 0.);
|
||||
}
|
226
Sources/CoreAudioSDK/CAStreamBasicDescription.h
Normal file
226
Sources/CoreAudioSDK/CAStreamBasicDescription.h
Normal file
|
@ -0,0 +1,226 @@
|
|||
/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
||||
copyrights in this original Apple software (the "Apple Software"), to use,
|
||||
reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions of
|
||||
the Apple Software. Neither the name, trademarks, service marks or logos of
|
||||
Apple Computer, Inc. may be used to endorse or promote products derived from the
|
||||
Apple Software without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or implied,
|
||||
are granted by Apple herein, including but not limited to any patent rights that
|
||||
may be infringed by your derivative works or by other works in which the Apple
|
||||
Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*=============================================================================
|
||||
CAStreamBasicDescription.h
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#ifndef __CAStreamBasicDescription_h__
|
||||
#define __CAStreamBasicDescription_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#include "CoreFoundation.h"
|
||||
#endif
|
||||
|
||||
#include "CADebugMacros.h"
|
||||
#include <string.h> // for memset, memcpy
|
||||
#include <stdio.h> // for FILE *
|
||||
|
||||
#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it
|
||||
|
||||
// define the IsMixable format flag for all versions of the system
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3)
|
||||
enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable };
|
||||
#else
|
||||
enum { kIsNonMixableFlag = (1L << 6) };
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CAStreamBasicDescription
|
||||
//
|
||||
// This is a wrapper class for the AudioStreamBasicDescription struct.
|
||||
// It adds a number of convenience routines, but otherwise adds nothing
|
||||
// to the footprint of the original struct.
|
||||
//=============================================================================
|
||||
class CAStreamBasicDescription :
|
||||
public AudioStreamBasicDescription
|
||||
{
|
||||
|
||||
// Constants
|
||||
public:
|
||||
static const AudioStreamBasicDescription sEmpty;
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAStreamBasicDescription() { memset (this, 0, sizeof(AudioStreamBasicDescription)); }
|
||||
|
||||
CAStreamBasicDescription(const AudioStreamBasicDescription &desc)
|
||||
{
|
||||
SetFrom(desc);
|
||||
}
|
||||
|
||||
CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID,
|
||||
UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
|
||||
UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
|
||||
UInt32 inBitsPerChannel, UInt32 inFormatFlags);
|
||||
|
||||
// Assignment
|
||||
CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; }
|
||||
|
||||
void SetFrom(const AudioStreamBasicDescription &desc)
|
||||
{
|
||||
memcpy(this, &desc, sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// interrogation
|
||||
|
||||
bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; }
|
||||
|
||||
bool PackednessIsSignificant() const
|
||||
{
|
||||
Assert(IsPCM(), "PackednessIsSignificant only applies for PCM");
|
||||
return (SampleWordSize() << 3) != mBitsPerChannel;
|
||||
}
|
||||
|
||||
bool AlignmentIsSignificant() const
|
||||
{
|
||||
return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0;
|
||||
}
|
||||
|
||||
bool IsInterleaved() const
|
||||
{
|
||||
return !IsPCM() || !(mFormatFlags & kAudioFormatFlagIsNonInterleaved);
|
||||
}
|
||||
|
||||
// for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these:
|
||||
UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; }
|
||||
UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; }
|
||||
UInt32 NumberChannels() const { return mChannelsPerFrame; }
|
||||
UInt32 SampleWordSize() const { return (mBytesPerFrame > 0) ? mBytesPerFrame / NumberInterleavedChannels() : 0;}
|
||||
|
||||
UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; }
|
||||
UInt32 BytesToFrames(UInt32 nbytes) const {
|
||||
Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames");
|
||||
return nbytes / mBytesPerFrame;
|
||||
}
|
||||
|
||||
bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const
|
||||
{
|
||||
return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved();
|
||||
}
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// manipulation
|
||||
|
||||
void SetCanonical(UInt32 nChannels, bool interleaved)
|
||||
// note: leaves sample rate untouched
|
||||
{
|
||||
mFormatID = kAudioFormatLinearPCM;
|
||||
mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
|
||||
mBitsPerChannel = 32;
|
||||
mChannelsPerFrame = nChannels;
|
||||
mFramesPerPacket = 1;
|
||||
if (interleaved)
|
||||
mBytesPerPacket = mBytesPerFrame = nChannels * sizeof(Float32);
|
||||
else {
|
||||
mBytesPerPacket = mBytesPerFrame = sizeof(Float32);
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
|
||||
void ChangeNumberChannels(UInt32 nChannels, bool interleaved)
|
||||
// alter an existing format
|
||||
{
|
||||
Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats");
|
||||
UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING
|
||||
if (wordSize == 0)
|
||||
wordSize = (mBitsPerChannel + 7) / 8;
|
||||
mChannelsPerFrame = nChannels;
|
||||
mFramesPerPacket = 1;
|
||||
if (interleaved) {
|
||||
mBytesPerPacket = mBytesPerFrame = nChannels * wordSize;
|
||||
mFormatFlags &= ~kAudioFormatFlagIsNonInterleaved;
|
||||
} else {
|
||||
mBytesPerPacket = mBytesPerFrame = wordSize;
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// other
|
||||
|
||||
bool IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards=true) const;
|
||||
|
||||
void Print() const
|
||||
{
|
||||
Print (stdout);
|
||||
}
|
||||
|
||||
void Print(FILE* file) const
|
||||
{
|
||||
PrintFormat (file, "", "AudioStreamBasicDescription:");
|
||||
}
|
||||
|
||||
void PrintFormat(FILE *f, const char *indent, const char *name) const;
|
||||
|
||||
OSStatus Save(CFPropertyListRef *outData) const;
|
||||
|
||||
OSStatus Restore(CFPropertyListRef &inData);
|
||||
|
||||
// Operations
|
||||
static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); }
|
||||
static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription);
|
||||
static void ResetFormat(AudioStreamBasicDescription& ioDescription);
|
||||
static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription);
|
||||
static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate);
|
||||
#if CoreAudio_Debug
|
||||
static void PrintToLog(const AudioStreamBasicDescription& inDesc);
|
||||
#endif
|
||||
};
|
||||
|
||||
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y);
|
||||
bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y);
|
||||
#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600))
|
||||
inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); }
|
||||
inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); }
|
||||
inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); }
|
||||
inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); }
|
||||
#endif
|
||||
|
||||
bool SanityCheck(const AudioStreamBasicDescription& x);
|
||||
|
||||
|
||||
#endif // __CAStreamBasicDescription_h__
|
|
@ -19,21 +19,40 @@ class VLAUSoundOut : public VLSoundOut {
|
|||
public:
|
||||
VLAUSoundOut();
|
||||
|
||||
virtual void PlayNote(const VLNote & note);
|
||||
virtual void PlayChord(const VLChord & chord);
|
||||
virtual void PlayFile(CFDataRef file);
|
||||
virtual void PlayNote(const VLNote & note);
|
||||
virtual void PlayChord(const VLChord & chord);
|
||||
virtual void PlayFile(CFDataRef file);
|
||||
|
||||
virtual ~VLAUSoundOut();
|
||||
virtual ~VLAUSoundOut();
|
||||
|
||||
void Stop();
|
||||
protected:
|
||||
VLAUSoundOut(bool fileOutput);
|
||||
|
||||
void InitSoundOut(bool fileOutput);
|
||||
virtual void SetupOutput(AUNode outputNode);
|
||||
virtual void PlaySequence(MusicSequence music);
|
||||
MusicTimeStamp SequenceLength(MusicSequence music);
|
||||
|
||||
void Stop();
|
||||
private:
|
||||
AUGraph fGraph;
|
||||
private:
|
||||
MusicPlayer fPlayer;
|
||||
MusicSequence fMusic;
|
||||
bool fRunning;
|
||||
|
||||
void PlaySequence(MusicSequence music);
|
||||
void Play(const int8_t * note, size_t numNotes = 1);
|
||||
void Play(const int8_t * note, size_t numNotes = 1);
|
||||
};
|
||||
|
||||
class VLAUFileSoundOut : public VLAUSoundOut {
|
||||
public:
|
||||
VLAUFileSoundOut(CFURLRef file);
|
||||
~VLAUFileSoundOut();
|
||||
protected:
|
||||
virtual void SetupOutput(AUNode outputNode);
|
||||
virtual void PlaySequence(MusicSequence music);
|
||||
private:
|
||||
AudioUnit fOutput;
|
||||
CFURLRef fFile;
|
||||
};
|
||||
|
||||
VLSoundEvent::~VLSoundEvent()
|
||||
|
@ -64,12 +83,35 @@ void VLSoundOut::SetScheduler(VLSoundScheduler * scheduler)
|
|||
sSoundScheduler.reset(scheduler);
|
||||
}
|
||||
|
||||
VLSoundOut * VLSoundOut::FileWriter(CFURLRef file)
|
||||
{
|
||||
return new VLAUFileSoundOut(file);
|
||||
}
|
||||
|
||||
VLSoundOut::~VLSoundOut()
|
||||
{
|
||||
}
|
||||
|
||||
VLAUSoundOut::VLAUSoundOut()
|
||||
: fRunning(false), fMusic(0)
|
||||
{
|
||||
InitSoundOutput(false);
|
||||
}
|
||||
|
||||
VLAUSoundOut::VLAUSoundOut(bool fileOutput)
|
||||
: fRunning(false), fMusic(0)
|
||||
{
|
||||
InitSoundOutput(fileOutput);
|
||||
}
|
||||
|
||||
VLAUSoundOut::~VLAUSoundOut()
|
||||
{
|
||||
DisposeMusicPlayer(fPlayer);
|
||||
Stop();
|
||||
DisposeAUGraph(fGraph);
|
||||
}
|
||||
|
||||
void VLAUSoundOut::InitSoundOutput(bool fileOutput)
|
||||
{
|
||||
AUNode synthNode, limiterNode, outNode;
|
||||
ComponentDescription cd;
|
||||
|
@ -91,7 +133,10 @@ VLAUSoundOut::VLAUSoundOut()
|
|||
AUGraphNewNode (fGraph, &cd, 0, NULL, &limiterNode);
|
||||
|
||||
cd.componentType = kAudioUnitType_Output;
|
||||
cd.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
if (fileOutput)
|
||||
cd.componentSubType = kAudioUnitSubType_GenericOutput;
|
||||
else
|
||||
cd.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
|
||||
AUGraphNewNode(fGraph, &cd, 0, NULL, &outNode);
|
||||
|
||||
|
@ -99,16 +144,24 @@ VLAUSoundOut::VLAUSoundOut()
|
|||
AUGraphConnectNodeInput(fGraph, synthNode, 0, limiterNode, 0);
|
||||
AUGraphConnectNodeInput(fGraph, limiterNode, 0, outNode, 0);
|
||||
|
||||
if (fileOutput) {
|
||||
UInt32 value = 1;
|
||||
AudioUnit synth;
|
||||
AUGraphGetNodeInfo(fGraph, synthNode, 0, 0, 0, &synth)
|
||||
AudioUnitSetProperty(synth,
|
||||
kAudioUnitProperty_OfflineRender,
|
||||
kAudioUnitScope_Global, 0,
|
||||
&value, sizeof(value));
|
||||
}
|
||||
SetupOutput(outNode);
|
||||
|
||||
AUGraphInitialize(fGraph);
|
||||
|
||||
NewMusicPlayer(&fPlayer);
|
||||
}
|
||||
|
||||
VLAUSoundOut::~VLAUSoundOut()
|
||||
void VLAUSoundOut::SetupOutput(AUNode)
|
||||
{
|
||||
DisposeMusicPlayer(fPlayer);
|
||||
Stop();
|
||||
DisposeAUGraph(fGraph);
|
||||
}
|
||||
|
||||
void VLAUSoundOut::PlaySequence(MusicSequence music)
|
||||
|
@ -183,3 +236,136 @@ void VLAUSoundOut::PlayFile(CFDataRef file)
|
|||
PlaySequence(music);
|
||||
}
|
||||
|
||||
MusicTimeStamp VLAUSoundOut::SequenceLength(MusicSequence music)
|
||||
{
|
||||
UInt32 ntracks;
|
||||
MusicSequenceGetTrackCount(sequence, &ntracks);
|
||||
MusicTimeStamp sequenceLength = 0;
|
||||
for (UInt32 i = 0; i < ntracks; ++i) {
|
||||
MusicTrack track;
|
||||
MusicTimeStamp trackLength;
|
||||
UInt32 propsize = sizeof(MusicTimeStamp);
|
||||
MusicSequenceGetIndTrack(sequence, i, &track);
|
||||
MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
|
||||
&trackLength, &propsize);
|
||||
sequenceLength = std::max(sequenceLength, trackLength);
|
||||
}
|
||||
return sequenceLength;
|
||||
}
|
||||
|
||||
VLAUFileSoundOut::VLAUFileSoundOut(CFURLRef file)
|
||||
: VLAUSoundOut(true), fFile(file)
|
||||
{
|
||||
CFRetain(fFile);
|
||||
}
|
||||
|
||||
VLAUFileSoundOut::~VLAUFileSoundOut()
|
||||
{
|
||||
CFRelease(fFile);
|
||||
}
|
||||
|
||||
void VLAUFileSoundOut::SetupOutput(AUNode outputNode)
|
||||
{
|
||||
AUGraphGetNodeInfo(fGraph, outputNode, 0, 0, 0, &fOutput);
|
||||
Float64 sampleRate = 22050.0;
|
||||
AudioUnitSetProperty(fOutput,
|
||||
kAudioUnitProperty_SampleRate,
|
||||
kAudioUnitScope_Output, 0,
|
||||
&sampleRate, sizeof(sampleRate));
|
||||
}
|
||||
|
||||
void VLAUFileSoundOut::PlaySequence(MusicSequence music)
|
||||
{
|
||||
SInt32 urlErr;
|
||||
CFURLDestroyResource(fFile, &urlErr);
|
||||
|
||||
OSStatus result = 0;
|
||||
UInt32 size;
|
||||
MusicTimeStamp musicLen = SequenceLength(music)+8;
|
||||
CFStringRef name =
|
||||
CFURLCopyLastPathComponent(fFile);
|
||||
CAAudioFileFormats formats = CAAudioFileFormats::Instance();
|
||||
|
||||
AudioFileTypeID fileType;
|
||||
formats->InferFileFormatFromFilename(name, fileType);
|
||||
|
||||
CAStreamBasicDescription outputFormat;
|
||||
formats->InferDataFormatFromFileFormat(fileType, outputFormat);
|
||||
outputFormat.mChannelsPerFrame = 2;
|
||||
|
||||
if (outputFormat.mFormatID == kAudioFormatLinearPCM) {
|
||||
outputFormat.mBytesPerPacket = outputFormat.mChannelsPerFrame * 2;
|
||||
outputFormat.mFramesPerPacket = 1;
|
||||
outputFormat.mBytesPerFrame = outputFormat.mBytesPerPacket;
|
||||
outputFormat.mBitsPerChannel = 16;
|
||||
|
||||
if (fileType == kAudioFileWAVEType)
|
||||
outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
|
||||
| kLinearPCMFormatFlagIsPacked;
|
||||
else
|
||||
outputFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian
|
||||
| kLinearPCMFormatFlagIsSignedInteger
|
||||
| kLinearPCMFormatFlagIsPacked;
|
||||
} else {
|
||||
// use AudioFormat API to fill out the rest.
|
||||
size = sizeof(outputFormat);
|
||||
AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL,
|
||||
&size, &outputFormat);
|
||||
}
|
||||
|
||||
CFURLRef dir =
|
||||
CFURLCreateCopyDeletingLastPathComponent(NULL, fFile);
|
||||
FSRef parentDir;
|
||||
CFURLGetFSRef(dir, &parentDir);
|
||||
CFRelease(dir);
|
||||
|
||||
ExtAudioFileRef outfile;
|
||||
ExtAudioFileCreateNew(&parentDir, name,
|
||||
fileType, &outputFormat, NULL, &outfile);
|
||||
CFRelease(name);
|
||||
|
||||
{
|
||||
CAStreamBasicDescription clientFormat;
|
||||
size = sizeof(clientFormat);
|
||||
require_noerr (result = AudioUnitGetProperty (outputUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Output, 0,
|
||||
&clientFormat, &size), fail);
|
||||
size = sizeof(clientFormat);
|
||||
require_noerr (result = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat), fail);
|
||||
|
||||
{
|
||||
MusicTimeStamp currentTime;
|
||||
AUOutputBL outputBuffer (clientFormat, numFrames);
|
||||
AudioTimeStamp tStamp;
|
||||
memset (&tStamp, 0, sizeof(AudioTimeStamp));
|
||||
tStamp.mFlags = kAudioTimeStampSampleTimeValid;
|
||||
int i = 0;
|
||||
int numTimesFor10Secs = (int)(10. / (numFrames / srate));
|
||||
do {
|
||||
outputBuffer.Prepare();
|
||||
AudioUnitRenderActionFlags actionFlags = 0;
|
||||
require_noerr (result = AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, outputBuffer.ABL()), fail);
|
||||
|
||||
tStamp.mSampleTime += numFrames;
|
||||
|
||||
require_noerr (result = ExtAudioFileWrite(outfile, numFrames, outputBuffer.ABL()), fail);
|
||||
|
||||
require_noerr (result = MusicPlayerGetTime (player, ¤tTime), fail);
|
||||
if (shouldPrint && (++i % numTimesFor10Secs == 0))
|
||||
printf ("current time: %6.2f beats\n", currentTime);
|
||||
} while (currentTime < sequenceLength);
|
||||
}
|
||||
}
|
||||
|
||||
// close
|
||||
ExtAudioFileDispose(outfile);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
printf ("Problem: %ld\n", result);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ public:
|
|||
class VLSoundOut {
|
||||
public:
|
||||
static VLSoundOut * Instance();
|
||||
static VLSoundOut * FileWriter(CFURLRef file);
|
||||
|
||||
static void SetScheduler(VLSoundScheduler * scheduler);
|
||||
|
||||
virtual void PlayNote(const VLNote & note) = 0;
|
||||
|
|
|
@ -265,6 +265,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
2A37F4ABFDCFA73011CA2CEA /* Classes */,
|
||||
9546A1090B08B47A0028503B /* CoreAudio SDK Sources */,
|
||||
2A37F4AFFDCFA73011CA2CEA /* Other Sources */,
|
||||
95C461D40B04403600649F92 /* Tools */,
|
||||
95C461DC0B0442EB00649F92 /* MMA */,
|
||||
|
@ -362,6 +363,13 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9546A1090B08B47A0028503B /* CoreAudio SDK Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = "CoreAudio SDK Sources";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
955E59560957C0C50045FDA5 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
Loading…
Reference in New Issue
Block a user