Accelerate Framework FFT to create audio fingerprint in iOS - objective-c

First of all, sorry for my bad English.
I just started with the Objective-C a couple of week ago. I'm doing a project that require me to compared two audio signals recorded from two iOS devices. So far, I managed to record two .aif files from an iPhone 4s and iPhone 4. Then I try to apply the following algorithm A Highly Robust Audio Fingerprinting System. by: Jaap Haitsma" to get two fingerprints (in binary bit patterns 101011010) and then compare them with each other bits by bits. But so far, the result I got is somewhere between 45% and 55% which is pretty much the random probability between 0s and 1s. So can somebody give me any advice. Here's the code so far:
CalculateFingerprint *myCalculateFingerprint = [CalculateFingerprint alloc];
SInt16 *inputBuffer;
path4 = [documentsDirectory stringByAppendingPathComponent:fileName4];
/////////Calculate for the 4 file
fileURL = [NSURL fileURLWithPath:path4];
status = AudioFileOpenURL((__bridge CFURLRef)fileURL, kAudioFileReadPermission,kAudioFileAIFFType, &myAudioFile);
status = AudioFileGetPropertyInfo(myAudioFile,
kAudioFilePropertyAudioDataPacketCount,
&propertySizeDataPacketCount,
&writabilityDataPacketCount);
status = AudioFileGetProperty(myAudioFile,
kAudioFilePropertyAudioDataPacketCount,
&propertySizeDataPacketCount,
&numberOfPackets);
status = AudioFileGetPropertyInfo (myAudioFile,
kAudioFilePropertyMaximumPacketSize,
&propertySizeMaxPacketSize,
&writabilityMaxPacketSize);
status = AudioFileGetProperty(myAudioFile,
kAudioFilePropertyMaximumPacketSize,
&propertySizeMaxPacketSize,
&maxPacketSize);
inputBuffer = (SInt16 *)malloc(numberOfPackets * maxPacketSize);
currentPacket = 0;
status = AudioFileReadPackets(myAudioFile,
false, &numberOfBytesRead,
NULL,
currentPacket,
&numberOfPackets,
inputBuffer);
[myCalculateFingerprint calculateFingerprint:inputBuffer sampleCount:numberOfPackets index:indexFile];
status = AudioFileClose(myAudioFile);
Here's the calculation of fingerprint code:
-(void)calculateFingerprint :(SInt16*)samples
sampleCount:(int)sampleCount
index:(int)indexFile{
//Divide the audio signal into 32 frames
frames myFrames [32];
int stepFrames = sampleCount / 62;
int number = 0;
int index ;
for (int i = 0; i < 32; ++i){
index = 0;
myFrames[i].start = number;
myFrames[i].end = number + (32*stepFrames);
myFrames[i].dataFrames = (SInt16*)malloc((myFrames[i].end -number+1)*sizeof(SInt16));
for (int j = number;j<=myFrames[i].end; ++j){
myFrames[i].dataFrames[index] = samples[j];
++index;
}
number = number + stepFrames;
}
//Calculate FFT for each of the audio signal frames.
CalculateFFT *myCalculateFFT = [[CalculateFFT alloc] init];
theFFT myFFTData [32];
for (int i = 0; i <32; ++i){
myFFTData[i].FFTdata = [myCalculateFFT calculateFFTForData:myFrames[i].dataFrames];
}
//each index represent the frequency as followed:
// index i is frequency i * 44100/1024
//We only need 33 bands from 300 Hz to 2000Hz, so we will get the FFTdata from the index 7 to 40
float energy [33][33];
for (int i =0; i < 33; ++i){
energy[0][i] = 0;
}
int stepBand;
for (int i = 1; i < 33; ++i){
for (int j = 0; j < 33; ++j){
energy[i][j] = myFFTData[i].FFTdata[j+7];
}
}
//next we calculate the bits for the audio fingerprint
Float32 check = 0;
int fingerPrint [32][32];
NSMutableString *result = [[NSMutableString alloc]init];
for (int i = 0; i < 32; ++i){
for (int j = 0; j <32; ++j){
check = energy[i+1][j] -energy[i+1][j+1] -energy[i][j] +energy[i][j+1];
if (check > 0){
fingerPrint[i][j] = 1;//[tempBitFingerPrint addObject:[NSNumber numberWithInt:1]];
}else {
fingerPrint[i][j] = 0;//[tempBitFingerPrint addObject:[NSNumber numberWithInt:0]];
}
[result appendString:[NSString stringWithFormat:#"%d",fingerPrint[i][j]]];
}
}
And finally the FFT calculation code:
-(void)FFTSetup{
UInt32 maxFrames = 1024;
originalReal = (float*) malloc(maxFrames*sizeof(float));
originalRealTransfer = (float*)malloc(maxFrames*sizeof(float));
obtainedReal = (float*) malloc(maxFrames *sizeof(float));
freqArray = (Float32*) malloc((maxFrames/2) *sizeof(Float32));
fftLog2n = log2f(maxFrames);
fftN = 1 << fftLog2n;
fftNOver2 = maxFrames/2;
fftBufferCapacity = maxFrames;
fftIndex = 0;
fftA.realp = (float*)malloc(fftNOver2*sizeof(float));
fftA.imagp = (float*)malloc(fftNOver2*sizeof(float));
fftSetup = vDSP_create_fftsetup(fftLog2n,FFT_RADIX2);
}
-(Float32*) calculateFFTForData:(SInt16*)sampleData
{
[self FFTSetup];
int stride = 1;
for (int i = 0; i < fftN; ++i){
originalReal[i] = (float) sampleData[i];
}
UInt32 maxFrames = 1024;
//Apply Hann window on the data
int windowSize = maxFrames;
float * window = (float*)malloc(sizeof(float)*windowSize);
memset(window, 0, sizeof(float)*windowSize);
vDSP_hann_window(window, windowSize, vDSP_HANN_NORM);
vDSP_vmul(originalReal,1,window,1,originalRealTransfer,1,windowSize);
vDSP_ctoz((COMPLEX*) originalRealTransfer,2,&fftA,1,fftNOver2);
vDSP_fft_zrip(fftSetup,&fftA, stride,fftLog2n,FFT_FORWARD);
float scale = (float) 1.0 /(2*fftN);
vDSP_vsmul(fftA.realp,1,&scale,fftA.realp,1,fftNOver2);
vDSP_vsmul(fftA.imagp,1,&scale,fftA.imagp,1,fftNOver2);
vDSP_ztoc(&fftA,1,(COMPLEX*)obtainedReal,2,fftNOver2);
int index = 0;
NSMutableString *testResult = [[NSMutableString alloc]init];
for (int i = 0; i < fftN; i=i+2){
freqArray[index] = (obtainedReal[i]*obtainedReal[i])+(obtainedReal[i+1]*obtainedReal[i+1]);
[testResult appendString:[NSString stringWithFormat:#"%f ",freqArray[index]]];
++index;
}
return freqArray;
}

Related

Dividing file into 10MB chunks

I have a script that divides file into 10MB chunks. Haven't had a problem with this script until I tried to do it on a 6GB file. Getting negative values on ranges even if they are uint64_t. Any suggestions on where is the error?
NSData *conData = [NSURLConnection sendSynchronousRequest:fileSizeRequest returningResponse:&response error:&error];
if (conData)
{
NSDictionary *headers = [response allHeaderFields];
NSString *fileSizeString = [headers objectForKey:#"Content-Length"];
uint64_t fileSize = strtoull([fileSizeString UTF8String], NULL, 0);
self.size += fileSize;
uint64_t amountOfRanges = fileSize / 10485760;
for (int i = 0; i <= amountOfRanges; i++)
{
uint64_t rangeMin = 0;
uint64_t rangeMax = 0;
if (i != amountOfRanges)
{
rangeMin = i * 10485760;
rangeMax = (i + 1) * 10485760 - 1;
}
else
{
if (i == 0)
{
rangeMin = 0;
rangeMax = fileSize - 1;
}
else
{
rangeMin = i * 10485760;
rangeMax = i * 10485760 - 1 + (fileSize - rangeMin);
}
}
}
}
You have a problem with expressions such as this:
rangeMin = i * 10485760;
Note that i is an int and 10485760 is an int literal, so the resulting int expression can easily overflow. You should ideally make i a uint64_t and/or use unsigned long long literals, e.g.
rangeMin = i * 10485760ULL;

Converting Objective C to C Matrix Manipulation

Okay, so I had working code written in all objective c (yes, I know that objc is technically just C. But i mean I had it written with messages and stuff. I only have a java background and do not know much about plain old C) but it ran incredibly slow. So I wrote out (what i thought) was the same code, but now this set of loops produces different values (for only some of the numbers) and I cannot, for the life of me, figure out whats different. What I am doing is looping 10 times and doing 1 multiplication and 1 addition between matricies. I'm hoping someone with more background with the two languages can pick out the part of code that I transcribed incorrectly. I did not change anything beforehand for any of the arrays (those were hardcoded in and uneffected) so A1, A2, etc have the same values in both parts of code.
Current code in C:
for (int m = 0; m < 10; m++) {
//Do matrix multiplication between A1 and A2. Store in temporary B1
for( int i = 0; i < 13; i++ )
for( int j = 0; j < 43; j++ ) {
double tempTotal = 0;
for( int k = 0; k < 43; k++){
tempTotal = tempTotal + A1[i][k] * A2[k][j];
}
B1[i][j] = tempTotal;
}
//Assign B1 data back into A1 after the multiplication is finished
for(int i = 0; i < 13; i++)
for(int j = 0; j<43; j++)
A1[i][j] = B1[i][j];
//Add C1 and A1. Store into C1.
for (int l = 0; l < 13; l++)
for (int n = 0; n < 43; n++)
C1[l][n] = C1[l][n] + A1[l][n];
}//end m for loop
This was the old Obj c code:
for (int m = 0; m < 10; m++) {
//multiply A1 and A2. Store into A1
A1 = [LCA_Computation multiply:A1 withArray:A2]; //LCA_Computation is the name of the .m class file in which this all happens.
//Add C1 and A1. Store into C1
for (int i = 0; i < 13; i++)
for (int j = 0; j < 43; j++)
[[C1 objectAtIndex:i] replaceObjectAtIndex:j withObject:[NSNumber numberWithDouble: [[[C1 objectAtIndex: i] objectAtIndex: j] doubleValue] + [[[A1 objectAtIndex: i] objectAtIndex: j] doubleValue]]];
}//end m for loop
//multiply method
+ (NSMutableArray*)multiply:(NSMutableArray*)a1 withArray:(NSMutableArray*)a2
{
int a1_rowNum = [a1 count];
int a2_rowNum = [a2 count];
int a2_colNum = [[a2 objectAtIndex:0] count];
NSMutableArray *result = [NSMutableArray arrayWithCapacity:a1_rowNum];
for (int i = 0; i < a1_rowNum; i++) {
NSMutableArray *tempRow = [NSMutableArray arrayWithCapacity:a2_colNum];
for (int j = 0; j < a2_colNum; j++) {
double tempTotal = 0;
for (int k = 0; k < a2_rowNum; k++) {
double temp1 = [[[a1 objectAtIndex:i] objectAtIndex:k] doubleValue];
double temp2 = [[[a2 objectAtIndex:k] objectAtIndex:j] doubleValue];
tempTotal += temp1 * temp2;
}
//the String format is intentional. I convert them all to strings later. I just put it in the method here where as it is done later in the C code
[tempRow addObject:[NSString stringWithFormat:#"%f",tempTotal]];
}
[result addObject:tempRow];
}
return result;
}
This issue had to do with prior memory management issues causing 0's to be used in some calculations.

audio unit playing m4a files

I've been working on this task for 12 days and i cant find any solution pleaaaaase help
i'm supposed to load about 80 m4a files and play some of them with augraph which contains mixer and remoteIO units thats how i load the files
OSStatus result;
for (int i = 0; i < [filePaths count]; i++) {
NSMutableArray *linearr=[[NSMutableArray alloc] init];
for (int j = 0; j < [[filePaths objectAtIndex:i] count]; j++) {
NSString *str=[[filePaths objectAtIndex:i] objectAtIndex:j];
CFURLRef audioFileURL = CFURLCreateFromFileSystemRepresentation (NULL, (const UInt8 *)[str cStringUsingEncoding:[NSString defaultCStringEncoding]] , strlen([str cStringUsingEncoding:[NSString defaultCStringEncoding]]), false);
ExtAudioFileRef audiofile;
ExtAudioFileOpenURL(audioFileURL, &audiofile);
assert(audiofile);
OSStatus err;
AudioStreamBasicDescription fileFormat;
UInt32 size = sizeof(fileFormat);
err = ExtAudioFileGetProperty(audiofile, kExtAudioFileProperty_FileDataFormat, &size, &fileFormat);
AudioFileID aFile;
//size = sizeof(aFile);
PropertySize =sizeof(PacketsToRead);
err = ExtAudioFileGetProperty(audiofile, kExtAudioFileProperty_AudioFile, &PropertySize, &aFile);
AudioFileTypeID fileType;
PropertySize = sizeof(fileType);
err = AudioFileGetProperty(aFile, kAudioFilePropertyFileFormat, &PropertySize, &fileType);
AudioStreamBasicDescription clientFormat;
bzero(&clientFormat, sizeof(clientFormat));
clientFormat.mChannelsPerFrame = 2;
clientFormat.mBytesPerFrame = 4;
clientFormat.mBytesPerPacket = clientFormat.mBytesPerFrame;
clientFormat.mFramesPerPacket = 1;
clientFormat.mBitsPerChannel = 32;
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mSampleRate = 44100.00;
clientFormat.mFormatFlags =kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved; //kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved;
err = ExtAudioFileSetProperty(audiofile, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat);
SInt64 numFrames = 0;
PropertySize = sizeof(numFrames);
err = ExtAudioFileGetProperty(audiofile, kExtAudioFileProperty_FileLengthFrames, &PropertySize, &numFrames);
NSNumber *pc = [NSNumber numberWithLongLong:numFrames];
[[packetCount objectAtIndex:i] replaceObjectAtIndex:j withObject:pc];
// create the buffers for reading in data
bufferList = malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer) * (clientFormat.mChannelsPerFrame - 1));
bufferList->mNumberBuffers = clientFormat.mChannelsPerFrame;
for (int ii=0; ii < bufferList->mNumberBuffers; ++ii) {
bufferList->mBuffers[ii].mDataByteSize = sizeof(float) * numFrames;
bufferList->mBuffers[ii].mNumberChannels = 2;
bufferList->mBuffers[ii].mData = malloc(bufferList->mBuffers[ii].mDataByteSize);
}
UInt32 rFrames = 0;
rFrames =(UInt32)numFrames;
err = ExtAudioFileRead(audiofile, &rFrames, bufferList);
[linearr addObject:[NSData dataWithBytes:bufferList->mBuffers[1].mData length:numFrames]];
err = ExtAudioFileDispose(audiofile);
}
[audioData addObject:linearr];
}
and that's how i play it:
UInt32 *buslist;
buslist=( UInt32*)[[[audioData objectAtIndex:0] objectAtIndex:4]bytes ];
in rendercallback func:
for (int i = 0 ; i < ioData->mNumberBuffers; i++){
UInt32 *au3=au->mBuffers[0].mData;
AudioBuffer buffer = ioData->mBuffers[i];
UInt32 *frameBuffer = buffer.mData;
for (int j = 0; j < inNumberFrames; j++)
{
frameBuffer[j] = buflist[counter];
if(counter>=529200)
counter=0;
else
counter++;
}}}
Now when i play the sound i get the first part played with double speed then the second part only distortion.
I was having the exact same problem I think;
The incoming sound was at a lower sample rate, so the array I allocated wasn't big enough for the higher sample rate of the auGraph, and was too fast and short.
make sure you allocate an array to read the file something like this:
sarray->frames = totalFramesInFile * graphSampleRate / fileAudioFormat.mSampleRate;

ExtAudioFileWrite puzzler (kExtAudioFileError_InvalidOperationOrder error)

The following code skips the first second of audio in a pcm caf file and removes the last 5 seconds, writing to a temp file (which will be 6 seconds shorter than the input). The loop, everytime, produces a kExtAudioFileError_InvalidOperationOrder on the ExtAudioFileWrite. What am I doing wrong?
NSString *destURLString = [self.track.location absoluteString];
destURLString = [destURLString substringToIndex:([destURLString length] - 4)]; //remove .caf
destURLString = [NSString stringWithFormat:#"%#TMP.caf",destURLString]; //add tmp.caf
NSURL *destinationURL = [NSURL URLWithString:destURLString];
ExtAudioFileRef inputFile = NULL;
ExtAudioFileRef outputFile = NULL;
AudioStreamBasicDescription destFormat;
destFormat.mFormatID = kAudioFormatLinearPCM;
destFormat.mFormatFlags = kAudioFormatFlagsCanonical;
destFormat.mSampleRate = 22000;
destFormat.mFormatFlags = 0;
destFormat.mBytesPerPacket = 2;
destFormat.mFramesPerPacket = 1;
destFormat.mBytesPerFrame = 2;
destFormat.mChannelsPerFrame = 1;
destFormat.mBitsPerChannel = 16;
destFormat.mReserved = 0;
ExtAudioFileCreateWithURL((CFURLRef)destinationURL, kAudioFileCAFType, &destFormat, NULL, kAudioFileFlags_EraseFile, &outputFile);
OSStatus fileStatus = ExtAudioFileOpenURL((CFURLRef)track.location, &inputFile);
//AudioFileID fileID;
//OSStatus fileStatus = AudioFileOpenURL((CFURLRef)track.location, kAudioFileReadPermission, 0, &fileID);
//ExtAudioFileWrapAudioFileID (fileID, true, &inputFile);
OSStatus fileStatus2 = ExtAudioFileOpenURL((CFURLRef)destinationURL, &outputFile);
//NSLog(#"open status: %i", fileStatus2);
//find out how many frames long this file is
SInt64 length = 0;
UInt32 dataSize2 = (UInt32)sizeof(length);
OSStatus propStatus2 = ExtAudioFileGetProperty(inputFile, kExtAudioFileProperty_FileLengthFrames, &dataSize2, &length);
AudioStreamBasicDescription clientFormat;
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mSampleRate = 22000;
clientFormat.mFormatFlags = kAudioFormatFlagsCanonical;
clientFormat.mBitsPerChannel = 16;
clientFormat.mChannelsPerFrame = 1;
clientFormat.mFramesPerPacket = 1;
clientFormat.mBytesPerPacket = 2;
clientFormat.mBytesPerFrame = 2;
destFormat.mReserved = 0;
UInt32 size = sizeof(clientFormat);
//set the intermediate format to canonical on the source file for conversion (?)
OSStatus setpropstatus = ExtAudioFileSetProperty(inputFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
OSStatus setpropstatusout = ExtAudioFileSetProperty(outputFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
//UInt32 size = sizeof(destFormat);
//OSStatus setpropstatus = ExtAudioFileSetProperty(inputFile, kAudioFilePropertyDataFormat, size, &destFormat);
//NSLog(#"set prop status in %i", setpropstatus);
//NSLog(#"set prop status out %i", setpropstatusout);
OSStatus seekStatus = ExtAudioFileSeek(inputFile, (SInt64)22000); // skip one second of audio
NSLog(#"seekstatus %i", seekStatus);
SInt64 newLength = length - (5*22000); //shorten by 5 seconds worth of frames
NSLog(#"length: %i frames", length);
UInt8 *buffer = malloc(65536); //64K
UInt32 totalFramecount = 0;
while(true) {
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = 1;
bufferList.mBuffers[0].mData = buffer; //pointer to buffer of audio data
bufferList.mBuffers[0].mDataByteSize = 65536; //number of bytes in the buffer
UInt32 frameCount = 65536 / 2; //2 bytes per frame
// Read a chunk of input
OSStatus status = ExtAudioFileRead(inputFile, &frameCount, &bufferList);
totalFramecount += frameCount;
NSLog(#"read status %i", status);
//NSLog(#"loaded %f KB of data in %i frames", frameCount*2 / 1024.0, frameCount);
NSLog(#"loaded %i frames and stopping at %i", totalFramecount, newLength);
if (!frameCount || totalFramecount >= newLength) {
//termination condition
break;
}
OSStatus writeStatus = ExtAudioFileWrite(outputFile, frameCount, &bufferList);
NSLog(#"ws: %i", writeStatus);
}
free(buffer);
ExtAudioFileDispose(inputFile);
ExtAudioFileDispose(outputFile);
Turns out ExtAudioFileCreateWithURL returns a file already open, so the call to ExtAudioFileOpenURL was not needed, even though it returns successfully. I removed that and all works correctly.

Selecting random numbers iphone sdk

I want to select 10 random numbers from 1 to 35.
I am trying to do the following, but I get some repeated numbers
int totalNumberCnt = 1;
while (totalNumberCnt < 11) {
int randomNumber1 = 1 + arc4random() % 35;
NSString *numberString = [NSString stringWithFormat: #"%d",randomNumber1];
NSLog(numberString);
[firstNumber addObject:numberString];
[secondNumber addObject:numberString];
totalNumberCnt++;
}
Thank you for your help.
Repeated numbers are to be expected; it is random after all, and any random sample will contain repeats.
int unique = 0;
int numbers[35];
for (int i = 0; i < 35; i++) {
numbers[i] = 0;
}
while (unique < 10) {
int x = arc4random() % 35;
if (numbers[x] == 0) {
numbers[x] = 1;
++unique;
}
}
for (int i = 0; i < 35; i++) {
if (numbers[i] == 1) {
NSString *str = [NSString stringWithFormat: #"%d", i];
NSLog(#"%#", str);
}
}