Save PCM Stream to AIFF File (was How to play RAW PCM data using CA?)
Save PCM Stream to AIFF File (was How to play RAW PCM data using CA?)
- Subject: Save PCM Stream to AIFF File (was How to play RAW PCM data using CA?)
- From: malcom <email@hidden>
- Date: Sun, 26 Apr 2009 16:46:36 +0200
> However, if that proves too difficult, you could change from saving the raw NSData to using the CoreAudio
> AudioFile API to save a CAF file instead of the raw data. You will certainly be able to open an audio file created > with the AudioFIle API (Or ExtAudioFile, if needed).
I've tried to save the file using AudioFileCreate() (to create the
file itself) and AudioFileSetUserData() to fill up with my samples.
Everything works fine... in fact file data is written correctly but
I'm unable to play it (every player I've used says simply "File Format
Error").
I've also tried to import it in Audacity as RAW file and it works fine
(but I need to set the "endianess" parameter on import. Due to this
fact probability I've set a wrong type in my
AudioStreamBasicDescription's mFormatFlags. Could be the problem?
This is my code. It's pretty simple and you can try it in a second.
Chirp function generate 16bit/mono/44100 sound samples (as an array of shorts).
void WriteChirpAIFFFile(FSRef fsRef, CFStringRef newFile);
short* generateChirpSignalBuffer(double freq_start,double freq_end,int
duration_secs,long sample_rate, int bits_persample, int
*ret_totalSamples);
#define kFileName @"testme.aiff"
#define kDefaultLocation @"~/Desktop/"
- (void) testAiffFileCreation {
FSRef fsRef;
// try to make an AIFF file in desktop (this call fails if the file exists yet)
NSString *fPath = [[NSString
stringWithFormat:@"%@%@",kDefaultLocation,kFileName]
stringByStandardizingPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:fPath] == YES)
[[NSFileManager defaultManager] removeFileAtPath: fPath
handler:nil]; // remove old file if it exists
// make our aiff file
CFURLGetFSRef((CFURLRef)[NSURL fileURLWithPath:[kDefaultLocation
stringByStandardizingPath]], &fsRef);
WriteChirpAIFFFile(fsRef, (CFStringRef)kFileName);
}
void WriteChirpAIFFFile(FSRef fsRef, CFStringRef newFile) {
// setup the format
Float64 sampleRate = 44100; // 44100 sample rate frequency
UInt32 bitsPerChannel = 16; // 16 bits of data
double start_freq = 1000; // starting frequency is 1000Hz
double end_freq = 10000; // end frequency is 10000Hz
int duration = 10; // duration of chirp is 10 seconds
// setup audio stream description
AudioStreamBasicDescription aiffFormat;
aiffFormat.mSampleRate = sampleRate; // sample rate data
aiffFormat.mFormatID = kAudioFormatLinearPCM; // linear pulse-code
modulation data
// importing my stream data in Audacity I need to set the endianess
parameter (not big endian or little endian)
// so... the error could be in here, but I don't know how to solve it.
aiffFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
kLinearPCMFormatFlagIsPacked |
kLinearPCMFormatFlagIsBigEndian;
aiffFormat.mBytesPerPacket = 4; // The number of bytes in a packet of data.
aiffFormat.mFramesPerPacket = 1; // In uncompressed audio, a
Packet is one frame, (mFramesPerPacket == 1)
aiffFormat.mBytesPerFrame = 4; // The number of bytes in a packet of data.
aiffFormat.mChannelsPerFrame = 1;
aiffFormat.mBitsPerChannel = bitsPerChannel;
FSRef outRef;
AudioFileID audioFileID;
// create our AIFF audio file structure (headers only)
OSStatus status = AudioFileCreate(&fsRef, newFile,
kAudioFileAIFFType, &aiffFormat, 0, &outRef, &audioFileID);
if (status == kAudioFormatUnsupportedDataFormatError)
NSLog(@"error: audio format is not supported"); // ops something
wrong in audio format params...
else if (status == noErr) NSLog(@"all done, file was created"); // okay
else NSLog(@"Other error occurred: %d",status); // something else goes wrong
int total_fileSize = 0;
// generate chirp signal from 1000Hz to 10000Hz of 10 secs at
16bit/44100 sample rate
short *arr = generateChirpSignalBuffer(start_freq, end_freq,
duration, (long)sampleRate, bitsPerChannel,&total_fileSize);
// copy buffer data to file
status = AudioFileSetUserData(audioFileID, kAudioFileAIFFType, 0,
total_fileSize, arr);
if (status == noErr)
NSLog(@"%d bytes of data, our chirp stream of shorts, was copied
successfully to aiff file",total_fileSize);
// close and free memory
// AT THIS TIME THE FILE IS CORRECTLY FILLED WITH OUR STREAM DATA BUT
// BOTH THE FINDER AND AUDIO APPS SAYS "FILE FORMAT ERROR".
// IF I TRY TO IMPORT IT AS RAW DATA (or import the raw buffer data
without the aiff headers)
// IT WORKS FINE!
// JUST A NOTE: in Audacity i need to import is as endianess format
AudioFileClose(audioFileID);
free(arr);
}
#define MIN_INT -32768
#define MAX_INT 32767
#define PI 3.141592653
short* generateChirpSignalBuffer(double freq_start,double freq_end,int
duration_secs,long sample_rate, int bits_persample, int
*ret_totalSamples) {
long len_array = (long)duration_secs*sample_rate; // this is the
number of samples to generate
*ret_totalSamples = len_array; // store the total sample we will make
short *wavesamples = malloc(len_array*sizeof(short));
int i; for (i=0; i < len_array; i++) // some funky initializations...
wavesamples[i] = 0;
double k = (freq_end-freq_start)/len_array;
double freq = freq_start; // this is our time-to-time frequency value
double omega = (double)(PI / sample_rate);
long t;
for (t=0; t < len_array; t++) {
freq += k; // increase frequency over the time with the omega value
double c_sample = sin(omega*freq*t)*MAX_INT;
wavesamples[t] = (short)c_sample; // okay we have our sample at time t
}
return wavesamples; // okay, our array now contains a sequence of
mono short signed pcm data
}
_______________________________________________
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