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:
|
public:
|
||||||
VLAUSoundOut();
|
VLAUSoundOut();
|
||||||
|
|
||||||
virtual void PlayNote(const VLNote & note);
|
virtual void PlayNote(const VLNote & note);
|
||||||
virtual void PlayChord(const VLChord & chord);
|
virtual void PlayChord(const VLChord & chord);
|
||||||
virtual void PlayFile(CFDataRef file);
|
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;
|
AUGraph fGraph;
|
||||||
|
private:
|
||||||
MusicPlayer fPlayer;
|
MusicPlayer fPlayer;
|
||||||
MusicSequence fMusic;
|
MusicSequence fMusic;
|
||||||
bool fRunning;
|
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()
|
VLSoundEvent::~VLSoundEvent()
|
||||||
|
@ -64,12 +83,35 @@ void VLSoundOut::SetScheduler(VLSoundScheduler * scheduler)
|
||||||
sSoundScheduler.reset(scheduler);
|
sSoundScheduler.reset(scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VLSoundOut * VLSoundOut::FileWriter(CFURLRef file)
|
||||||
|
{
|
||||||
|
return new VLAUFileSoundOut(file);
|
||||||
|
}
|
||||||
|
|
||||||
VLSoundOut::~VLSoundOut()
|
VLSoundOut::~VLSoundOut()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
VLAUSoundOut::VLAUSoundOut()
|
VLAUSoundOut::VLAUSoundOut()
|
||||||
: fRunning(false), fMusic(0)
|
: 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;
|
AUNode synthNode, limiterNode, outNode;
|
||||||
ComponentDescription cd;
|
ComponentDescription cd;
|
||||||
|
@ -91,24 +133,35 @@ VLAUSoundOut::VLAUSoundOut()
|
||||||
AUGraphNewNode (fGraph, &cd, 0, NULL, &limiterNode);
|
AUGraphNewNode (fGraph, &cd, 0, NULL, &limiterNode);
|
||||||
|
|
||||||
cd.componentType = kAudioUnitType_Output;
|
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);
|
AUGraphNewNode(fGraph, &cd, 0, NULL, &outNode);
|
||||||
|
|
||||||
AUGraphOpen(fGraph);
|
AUGraphOpen(fGraph);
|
||||||
AUGraphConnectNodeInput(fGraph, synthNode, 0, limiterNode, 0);
|
AUGraphConnectNodeInput(fGraph, synthNode, 0, limiterNode, 0);
|
||||||
AUGraphConnectNodeInput(fGraph, limiterNode, 0, outNode, 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);
|
AUGraphInitialize(fGraph);
|
||||||
|
|
||||||
NewMusicPlayer(&fPlayer);
|
NewMusicPlayer(&fPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
VLAUSoundOut::~VLAUSoundOut()
|
void VLAUSoundOut::SetupOutput(AUNode)
|
||||||
{
|
{
|
||||||
DisposeMusicPlayer(fPlayer);
|
|
||||||
Stop();
|
|
||||||
DisposeAUGraph(fGraph);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLAUSoundOut::PlaySequence(MusicSequence music)
|
void VLAUSoundOut::PlaySequence(MusicSequence music)
|
||||||
|
@ -183,3 +236,136 @@ void VLAUSoundOut::PlayFile(CFDataRef file)
|
||||||
PlaySequence(music);
|
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 {
|
class VLSoundOut {
|
||||||
public:
|
public:
|
||||||
static VLSoundOut * Instance();
|
static VLSoundOut * Instance();
|
||||||
|
static VLSoundOut * FileWriter(CFURLRef file);
|
||||||
|
|
||||||
static void SetScheduler(VLSoundScheduler * scheduler);
|
static void SetScheduler(VLSoundScheduler * scheduler);
|
||||||
|
|
||||||
virtual void PlayNote(const VLNote & note) = 0;
|
virtual void PlayNote(const VLNote & note) = 0;
|
||||||
|
|
|
@ -265,6 +265,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
2A37F4ABFDCFA73011CA2CEA /* Classes */,
|
2A37F4ABFDCFA73011CA2CEA /* Classes */,
|
||||||
|
9546A1090B08B47A0028503B /* CoreAudio SDK Sources */,
|
||||||
2A37F4AFFDCFA73011CA2CEA /* Other Sources */,
|
2A37F4AFFDCFA73011CA2CEA /* Other Sources */,
|
||||||
95C461D40B04403600649F92 /* Tools */,
|
95C461D40B04403600649F92 /* Tools */,
|
||||||
95C461DC0B0442EB00649F92 /* MMA */,
|
95C461DC0B0442EB00649F92 /* MMA */,
|
||||||
|
@ -362,6 +363,13 @@
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
9546A1090B08B47A0028503B /* CoreAudio SDK Sources */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
);
|
||||||
|
name = "CoreAudio SDK Sources";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
955E59560957C0C50045FDA5 /* Tests */ = {
|
955E59560957C0C50045FDA5 /* Tests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
Loading…
Reference in New Issue
Block a user