• 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
AudioConverter challenges
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

AudioConverter challenges


  • Subject: AudioConverter challenges
  • From: Tom Mitchell <email@hidden>
  • Date: Wed, 28 Oct 2009 08:48:49 -0400

Ultimately I need to write compressed audio to a QuickTime file using AddMediaSample2. I can't seem to get that to work, so I'm starting from the ConvertFile sample and trying to migrate towards the QuickTime solution. I have attached below my attempt to write a short sine wave to a Core Audio File using an AudioConverter to compress the data using the Apple Lossless codec. It generates a file that is suspiciously short in length (4096 bytes), and fails to play any audio in QuickTime Player. I'm building and running on Snow Leopard (10.6.1).

Can anyone see what I'm doing wrong, or offer any suggestions? I've tried to compare with the code in ConvertFile, but I must be missing something.

Thanks,
-tom

--- ConvertAudio.m ---

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>

void check_error(OSStatus err, char *errFn)
{
	if (err != noErr) {
		fprintf(stderr, "Error: %s ==> %d", errFn, err);
		exit(1);
	}
}

/* Populate an ASBD for Linear PCM. */
void fill_asbd_for_lpcm(AudioStreamBasicDescription *asbd)
{
bzero(asbd, sizeof(AudioStreamBasicDescription));
asbd->mSampleRate = 16000;
asbd->mFormatID = kAudioFormatLinearPCM;
asbd->mFormatFlags = (kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked);
asbd->mBytesPerPacket = 2;
asbd->mFramesPerPacket = 1;
asbd->mBytesPerFrame = 2;
asbd->mChannelsPerFrame = 1;
asbd->mBitsPerChannel = 16;
}


/* Populate an ASBD for Apple Lossless Compression. */
static void fill_asbd_for_alac(AudioStreamBasicDescription *asbd)
{
	bzero(asbd, sizeof(AudioStreamBasicDescription));
	asbd->mFormatID = kAudioFormatAppleLossless;
	/* asbd->mFormatFlags = kAppleLosslessFormatFlag_16BitSourceData; */
	asbd->mFormatFlags = 0;
	asbd->mSampleRate = 16000;
	asbd->mBytesPerPacket = 0;
	asbd->mFramesPerPacket = 4096; // Is there a constant for this?
	asbd->mBytesPerFrame = 0;
	asbd->mChannelsPerFrame = 1;
	asbd->mBitsPerChannel = 0;
}

/* A struct to hold the audio data and associated info. */
struct MyAudioData {
	UInt32 size;
	UInt32 ptr;
	SInt16 *data;
};
typedef struct MyAudioData MyAudioData;

static MyAudioData *makeSineWave(UInt32 durationSeconds)
{
	MyAudioData *result = (MyAudioData *)malloc(sizeof(MyAudioData));
	UInt32 bytesPerSample = sizeof(SInt16);
	UInt32 sampleRate = 16000;
	UInt32 sampleCount = sampleRate * durationSeconds;
	result->size = bytesPerSample * sampleCount;
	result->ptr = 0;
	result->data = (SInt16 *)calloc(sampleCount, sizeof(SInt16));
	double factor = pow(2.0, 14.0);
	double pi12 = M_PI / 12.0;
	UInt32 i;
	for (i = 0; i < sampleCount; i++) {
		double val = (sin (i * pi12)) * factor;
		result->data[i] = (SInt16) val;
	}
	return result;
}

static OSStatus sineWaveInputProc(AudioConverterRef inAudioConverter,
								  UInt32 *ioNumberDataPackets,
								  AudioBufferList *ioData,
								  AudioStreamPacketDescription **outDataPacketDescription,
								  void *inUserData)
{
	MyAudioData *inputData = (MyAudioData *)inUserData;
	UInt32 bytesLeft = inputData->size - inputData->ptr;
	if (bytesLeft == 0) {
		// signal end of input data.
		*ioNumberDataPackets = 0;
		NSLog(@"Input Proc End Of Data");
		return noErr;
	}

	UInt32 byteCount = *ioNumberDataPackets * sizeof(SInt16);
	if (byteCount > bytesLeft) {
		byteCount = bytesLeft;
		*ioNumberDataPackets = byteCount / sizeof(SInt16);
	}
	ioData->mBuffers[0].mData = inputData->data + inputData->ptr;
	ioData->mBuffers[0].mDataByteSize = byteCount;
	ioData->mBuffers[0].mNumberChannels = 1;
	*outDataPacketDescription = NULL;
	inputData->ptr += byteCount;
	NSLog(@"Input Proc Yielded %d bytes", byteCount);
	return noErr;
}

// Cribbed from ConvertFile sample code
void WriteCookie (AudioConverterRef converter, AudioFileID outfile)
{
// grab the cookie from the converter and write it to the file
UInt32 cookieSize = 0;
OSStatus err = AudioConverterGetPropertyInfo(converter, kAudioConverterCompressionMagicCookie, &cookieSize, NULL);
// if there is an error here, then the format doesn't have a cookie, so on we go
if (!err && cookieSize) {
char* cookie = (char *)calloc(cookieSize, sizeof(char));

err = AudioConverterGetProperty(converter, kAudioConverterCompressionMagicCookie, &cookieSize, cookie);
check_error(err, "Get Cookie From AudioConverter");

err = AudioFileSetProperty (outfile, kAudioFilePropertyMagicCookieData, cookieSize, cookie);
// even though some formats have cookies, some files don't take them
check_error(err, "Set Cookie Property On AudioFile");

free(cookie);
}
}


int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
OSStatus err;

// Create the output file
NSURL *outputFileURL = [NSURL fileURLWithPath:@"sample.caf"];
AudioFileTypeID outputFileType = kAudioFileCAFType;
AudioStreamBasicDescription outputFormat;
fill_asbd_for_alac(&outputFormat);
UInt32 outputFlags = kAudioFileFlags_EraseFile;
AudioFileID outputFile;
err = AudioFileCreateWithURL((CFURLRef) outputFileURL, outputFileType, &outputFormat, outputFlags, &outputFile);
check_error(err, "AudioFileCreateWithURL");

// Create the AudioConverter
AudioStreamBasicDescription inputFormat;
fill_asbd_for_lpcm(&inputFormat);
AudioConverterRef converter;
err = AudioConverterNew(&inputFormat, &outputFormat, &converter);
check_error(err, "AudioConverterNew");


// Set up the buffer
AudioStreamPacketDescription* outputPktDescs = NULL;
UInt32 theOutputBufSize = 32768;
char* outputBuffer = (char *)calloc(theOutputBufSize, sizeof(char));

int outputSizePerPacket = 0;
UInt32 size = sizeof(outputSizePerPacket);
err = AudioConverterGetProperty(converter,
kAudioConverterPropertyMaximumOutputPacketSize,
&size,
&outputSizePerPacket);
check_error(err, "Get Max Packet Size");
NSLog(@"outputSizePerPacket = %d", outputSizePerPacket);
outputPktDescs = (AudioStreamPacketDescription *)calloc (theOutputBufSize / outputSizePerPacket,
sizeof(AudioStreamPacketDescription));
UInt32 numOutputPackets = theOutputBufSize / outputSizePerPacket;

WriteCookie(converter, outputFile);

// Construct the sample data
MyAudioData *inputData = makeSineWave(3);

// Convert data and write to file
UInt64 totalOutputFrames = 0;
SInt64 outputPos = 0;
while (1) {
AudioBufferList fillBufList;
fillBufList.mNumberBuffers = 1;
fillBufList.mBuffers[0].mNumberChannels = inputFormat.mChannelsPerFrame;
fillBufList.mBuffers[0].mDataByteSize = theOutputBufSize;
fillBufList.mBuffers[0].mData = outputBuffer;

UInt32 ioOutputDataPackets = numOutputPackets;
err = AudioConverterFillComplexBuffer(converter,
sineWaveInputProc,
(void *)inputData,
&ioOutputDataPackets,
&fillBufList,
NULL);
check_error(err, "AudioConverterFillComplexBuffer");
if (ioOutputDataPackets == 0) {
// this is the EOF conditon
break;
}

// Write the resulting data to file.
UInt32 inNumBytes = fillBufList.mBuffers[0].mDataByteSize;
err = AudioFileWritePackets(outputFile, false, inNumBytes, outputPktDescs, outputPos, &ioOutputDataPackets, outputBuffer);
check_error(err, "AudioConverterFillComplexBuffer");

// advance output file packet position
outputPos += ioOutputDataPackets;
totalOutputFrames += (ioOutputDataPackets * outputFormat.mFramesPerPacket);
}

AudioConverterPrimeInfo primeInfo;
UInt32 primeSize = sizeof(primeInfo);

err = AudioConverterGetProperty(converter, kAudioConverterPrimeInfo, &primeSize, &primeInfo);
check_error(err, "Get Property Converter Prime Info");
AudioFilePacketTableInfo pti;
pti.mPrimingFrames = primeInfo.leadingFrames;
pti.mRemainderFrames = primeInfo.trailingFrames;
pti.mNumberValidFrames = totalOutputFrames - pti.mPrimingFrames - pti.mRemainderFrames;
err = AudioFileSetProperty(outputFile, kAudioFilePropertyPacketTableInfo, sizeof(pti), &pti);
check_error(err, "Set Property File Packet Table Info");
WriteCookie (converter, outputFile);

// Finish up
AudioConverterDispose(converter);
AudioFileClose(outputFile);

[pool drain];
return 0;
}


_______________________________________________
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


  • Prev by Date: channel layout for 3DMixer
  • Next by Date: Help -- Which framework shoud I choose
  • Previous by thread: Re: channel layout for 3DMixer
  • Next by thread: Help -- Which framework shoud I choose
  • Index(es):
    • Date
    • Thread