• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: AudioFile -> AudioConverter -> float PCM
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: AudioFile -> AudioConverter -> float PCM


  • Subject: Re: AudioFile -> AudioConverter -> float PCM
  • From: Art Gillespie <email@hidden>
  • Date: Sat, 13 Aug 2005 09:01:18 -0700


On Aug 1, 2005, at 11:10 AM, Marc Poirier wrote:

I am trying to do the following: I want to use AudioFile to get the contents of an audio file, then use AudioConverter to put it all into arrays of PCM 32-bit float audio data (1 array per audio channel).
<snip>

Anyway, I'm sure that I'm not the only one who has wanted to do this task, so I was wondering if anyone might have some example code for this that they'd like to share?

Here's my code (uncensored and not cleaned up, sorry ) that does that. The function uses AudioFile to open the specified file, and AudioConverter to load it into 'canonical' internal format at the current operating sample rate. It also contains a workaround for an edge case: old AIFF files that are block aligned aren't handled correctly by AudioFile.


HTH.

OSStatus SampleManagerLoadSampleFromFSRef (
                                SampleManagerRef            inRef,
                                FSRef*                        inFile,
                                SampleManagerID*            outID )
{
    /* check parameters */
    if ( NULL == inRef )
        return kSampleManagerErr_InvalidParameter;
    OSStatus                        err = noErr;
    UInt32                            fileFormat;
    UInt32                            dataSize;
    UInt64                            bytesInSample;
    UInt64                          packetsInSample;
    void*                            tmpBuffer;
    AudioFileID                        aFile;
    AudioStreamBasicDescription        srcDesc;
    /* what internal format do we want the data in */
    CAStreamBasicDescription        dstDesc;
    AudioConverterRef                theConverter;
    SampleRef                        theSample;

/* get audio file attributes */
err = AudioFileOpen ( inFile, fsRdPerm, 0, &aFile );
if ( noErr != err )
{
LOGN1 ( kLogLevelError, "Couldn't open audio file: %d", err );
return err;
}
dataSize = sizeof ( UInt32 );
err = AudioFileGetProperty ( aFile, kAudioFilePropertyFileFormat, &dataSize, &fileFormat );
dataSize = sizeof ( AudioStreamBasicDescription );
err = AudioFileGetProperty ( aFile, kAudioFilePropertyDataFormat, &dataSize, &srcDesc );
dataSize = sizeof ( UInt64 );
err = AudioFileGetProperty ( aFile, kAudioFilePropertyAudioDataByteCount, &dataSize, &bytesInSample );


err = AudioFileGetProperty ( aFile, kAudioFilePropertyAudioDataPacketCount, &dataSize, &packetsInSample );

SInt64 pOffset;
dataSize = sizeof ( SInt64 );
err = AudioFileGetProperty ( aFile, kAudioFilePropertyDataOffset, &dataSize, &pOffset );


    GSLog ( kLogLevelDebug, "pOffset: %lld", pOffset );

if ( noErr != err )
{
LOGN1 ( kLogLevelError, "Couldn't get audio file property: % d", err );
AudioFileClose ( aFile );
return err;
}




    /* we only allow samples of certain size */
    if ( kIDMaxSampleLen     < bytesInSample )
    {
        AudioFileClose ( aFile );
        return kSampleManagerErr_SampleTooLarge;
    }

    /* create new SampleRef */
    theSample = (SampleRef) malloc ( sizeof ( Sample ) ) ;
    theSample->_ref = 0;
    theSample->_numFrames = 0;
    theSample->_data = 0;
    theSample->_numChannels = srcDesc.mChannelsPerFrame;
    if ( srcDesc.mChannelsPerFrame == 2 )
        theSample->processStereo = (void*)&DefaultStereoFunction;
    else
        theSample->processStereo = (void*)&DefaultMonoToStereoFunction;

    theSample->processMono = (void*)&DefaultMonoFunction;


/* read the file into temporary memory */ tmpBuffer = malloc ( bytesInSample ); memset(tmpBuffer, 0, bytesInSample);

UInt32 outByteSize = bytesInSample;
UInt32 readOffset = 0;
/* WORKAROUND: check for offset in SSND if this is AIFF */
/* There is an apparent bug in AudioFile that doesn't correctly
report the offset and length correctly for AIFF files that have
block alignment.
*/
if ( fileFormat == kAudioFileAIFFType )
{
OSStatus err;
UInt32 maxPathSize = 1024;
UInt8 cstr_path[maxPathSize];
err = FSRefMakePath(inFile, (UInt8*)cstr_path, maxPathSize );
assert(err == noErr);
FILE* aifFile = fopen((const char*)cstr_path, "r");
assert(aifFile); //wtf? we shouldn't have gotten here if the file is bogus
//skip past the FORM xxxx AIFF header - 12 bytes
fseek ( aifFile, 12, SEEK_CUR );
while ( true )
{
char chunkID[5];
chunkID[4] = 0;
long chunkLen;


            size_t rd = fread( chunkID, 4, 1, aifFile );
            if ( EOF == rd )
            {
                break;
            }
            /* FIXME:  Endian-ness conversion for X86 */
            rd = fread ( &chunkLen, 4, 1, aifFile );
            if ( EOF == rd )
            {
                break;
            }
            if ( strcmp(chunkID, "SSND") == 0 )
            {
                fread ( &readOffset, 4, 1, aifFile );
                GSLog ( kLogLevelDebug, "OFFSET: %d", readOffset );
                break;
            }
            else
            {
                fseek ( aifFile, chunkLen, SEEK_CUR );
            }
        }
        fclose(aifFile);
    }
    outByteSize -= readOffset;

err = AudioFileReadBytes( aFile, false, readOffset, &outByteSize, (void*)tmpBuffer );
UInt32 nPackets = packetsInSample;
if ( noErr != err )
{
free ( tmpBuffer );
free ( theSample );
LOGN1 ( kLogLevelError, "AudioFileReadBytes Failed: %d", err );
return err;
}
if ( bytesInSample != outByteSize )
{
LOGN2 ( kLogLevelError, "!!!!!!!!! AudioFileReadBytes did not read the entire file: %d : %d", bytesInSample, outByteSize );
}


    AudioFileClose(aFile);

    /* do the conversion */

    UInt32 ioOutSize = (UInt32) bytesInSample;

    dstDesc.SetCanonical(srcDesc.mChannelsPerFrame, true);
    dstDesc.mSampleRate = inRef->_sr;
    err = AudioConverterNew( &srcDesc, &dstDesc, &theConverter );
    if ( noErr != err )
    {
        free ( tmpBuffer );
        free ( theSample );
        LOGN1 ( kLogLevelError, "AudioConverterNew Failed: %d", err );
        return err;
    }

dataSize = sizeof ( UInt32 );
err = AudioConverterGetProperty( theConverter, kAudioConverterPropertyCalculateOutputBufferSize,
&dataSize, (void*) &ioOutSize );
if ( noErr != err )
{
free ( tmpBuffer );
free ( theSample );
AudioConverterDispose ( theConverter );
LOGN1 (kLogLevelError, "AudioConverterGetProperty (calculate output buffer size) failed: %d", err );
return err;
}


/* convert into SampleRef's buffer */
theSample->_numFrames = ioOutSize/dstDesc.mBytesPerFrame;
/* 4 extra floats per channel as guard bytes */
theSample->_data = (Float32*) malloc (ioOutSize + 4*sizeof (Float32)*srcDesc.mChannelsPerFrame);
memset(theSample->_data, 0, ioOutSize + 4*sizeof(Float32) *srcDesc.mChannelsPerFrame);
/* carefully now! we move the _data pointer four floats*num channels forward for our guard frames */
/* REMEMBER THIS WHEN YOU FREE _data DUMBASS!!!!! */
theSample->_data += 2*srcDesc.mChannelsPerFrame;
RetainSample ( theSample );
convdata theData;
theData.data = tmpBuffer;
theData.counter = bytesInSample;
theData.dataSize = bytesInSample;


    err=AudioConverterFillBuffer (
                            theConverter,
                            MyConverterDataInputProc,
                            (void*)&theData,
                            &ioOutSize,
                            theSample->_data );

if ( noErr != err )
{
free ( tmpBuffer );
free ( theSample->_data );
free ( theSample );
theSample->_data = NULL;
AudioConverterDispose ( theConverter );
LOGN1 ( kLogLevelError, "AudioConverterFillBuffer failed: % d", err );
return err;
}
AudioConverterDispose(theConverter);
free (tmpBuffer);


/* create new unique SampleManagerID for dictionary key */
UInt32 newId = inRef->_key++;
*outID = CFNumberCreate ( kCFAllocatorDefault, kCFNumberLongType, &newId );
/* store SampleRef in dictionary, return SampleManagerID */
CFDictionaryAddValue ( inRef->_samples, *outID, theSample );
return noErr;
}



_______________________________________________ Do not post admin requests to the list. They will be ignored. Coreaudio-api mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: This email sent to email@hidden
References: 
 >AudioFile -> AudioConverter -> float PCM (From: Marc Poirier <email@hidden>)

  • Prev by Date: Re: Core Audio PowerPC Intel Notes.rtf
  • Next by Date: Sample Rate: 44100 or 48000
  • Previous by thread: Re: AudioFile -> AudioConverter -> float PCM
  • Next by thread: GetTailTime() and Digital Performer
  • Index(es):
    • Date
    • Thread