Become a MacRumors Supporter for $25/year with no ads, private forums, and more!
  • Did you order new AirTags? We've opened a dedicated AirTags forum.

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Hi Guys,
This is a giveaway, but credit where it's due please,
particularly if you use it in any paid app.
iTunes appears to be doing this itself when you restore downloads,
but what if you provided the mp3's yourself?

This routine searches an iPod library (over 1500 items) in approx 0.5 seconds on iPhone 5.

Code:
int musicsearched = 0; // status flag set once the searchmusic function has run

int totalrecords = 0;
int matchcount = 0;
int cyclerecords = 0;
int nomatch = 0;
int musicsearched = 0;
int nonuniquetitles = 0;
int checked[10000]; // used for searchmusic function
char record[10000][200]; // 10,000 records of 200 bytes iPod library ends up here
char artist[10000][100]; // artists records
char matches[10000][200]; // parallel array - track matches
char amatches[10000][100]; // artist matches
char temprecord[200];
char resultrecord[200];


void searchmusic() {
    
        NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
        //do time-consuming stuff like calculating pi to 50000 places.

         MPMediaQuery *everything = [[MPMediaQuery alloc] init];
         
         oitemcount = 0;
         
         NSArray *itemsFromGenericQuery = [everything items];
         for (MPMediaItem *song in itemsFromGenericQuery) {
         
        songTitle = [song valueForProperty: MPMediaItemPropertyTitle];
        artistTitle = [song valueForProperty: MPMediaItemPropertyArtist];
        
        slength=[songTitle length];
        if (slength > 199) {slength = 199;} // limit string length to buffer size
             
        alength=[artistTitle length];
        if (alength > 99) {alength = 99;} // limit string length to buffer size
             
        const char *c = [songTitle UTF8String];
        strncpy(record[oitemcount], c, slength);
             
        const char *a = [artistTitle UTF8String];
        strncpy(artist[oitemcount], a, alength);
             
        oitemcount++;
        }
        
        totalrecords = oitemcount;
        matchcount = 26;
        cyclerecords = 0;
        oitemcount = 0;
        firstmatch = 0;
    
        while (oitemcount < totalrecords) {
            
        for(int j = 0; j < 199; j++) { // read in temp record at index to compare against all others
        temprecord[j] = record[oitemcount][j];
        }
            
        for(cyclerecords = oitemcount+1; cyclerecords < totalrecords; cyclerecords++) {
            
        nomatch = 0;
            
        for(int k = 0; k < 199; k++) { // compare a single record
        if (temprecord[k] != record[cyclerecords][k]) {nomatch = 1;}
        }
        
        if (nomatch == 1) {cyclerecords = totalrecords;}
                
        if (nomatch == 0) {
                
        if (checked[oitemcount] != 1) {
                
        for(int k = 0; k < 99; k++) { // draw line in text
        amatches[matchcount][k] = 0x5F;
        matches[matchcount][k] = 0x5F;    
        }
                
        if (matchcount < 9999) {matchcount++;} // line seperator
                
        for(int k = 0; k < 99; k++) { // copy artist match
        amatches[matchcount][k] = artist[oitemcount][k];
        }   
        
        for(int k = 0; k < 199; k++) { // copy song match
        matches[matchcount][k] = record[oitemcount][k];
        }
            
        if (matchcount < 9999) {matchcount++;}    
                
        checked[oitemcount] = 1;
        nonuniquetitles++;
            
        } // checked
                
                
        if (checked[cyclerecords] != 1) {
                
        for(int k = 0; k < 99; k++) { // copy artist match
        amatches[matchcount][k] = artist[cyclerecords][k];
        }   
            
        if (matchcount < 9999) {matchcount++;}
                
        checked[cyclerecords] = 1;    
                
        } // checked
        }
        }
        oitemcount++;
        }
    
    NSTimeInterval end =  [NSDate timeIntervalSinceReferenceDate];
    NSTimeInterval elapsed = end - start;
    xelapsed = elapsed;
    //NSLog(@"The search took %.2f seconds", xelapsed);
    
    for(int k = 0; k < 99; k++) { // draw last line in text
    amatches[matchcount][k] = 0x5F;
    matches[matchcount][k] = 0x5F;
    }
    
    if (matchcount < 9999) {matchcount++;} // last line seperator
    if (matchcount < 9999) {matchcount++;} // seperator
    
    sprintf(resultrecord, "Searched %i titles",totalrecords);
    for(int k = 0; k < 99; k++) { // write result line
    matches[matchcount][k] = resultrecord[k];
    if (matches[matchcount][k] == 0x00) {matches[matchcount][k] = 0x20;}
    }
    
    sprintf(resultrecord, "in %.2f seconds.            ",xelapsed);
    for(int k = 0; k < 99; k++) { // write message line
    matches[matchcount+1][k] = resultrecord[k];
    if (matches[matchcount+1][k] == 0x00) {matches[matchcount+1][k] = 0x20;}
    }
    
    sprintf(resultrecord, "Found %i titles!               ",nonuniquetitles);
    for(int k = 0; k < 99; k++) { // write result line
    matches[matchcount+2][k] = resultrecord[k];
    if (matches[matchcount+2][k] == 0x00) {matches[matchcount+2][k] = 0x20;}
    }

    sprintf(resultrecord, "xPod By Art 2013                  ");
    for(int k = 0; k < 99; k++) { // write message line
    matches[matchcount+4][k] = resultrecord[k];
    if (matches[matchcount+4][k] == 0x00) {matches[matchcount+4][k] = 0x20;}
    }
    
    for(int k = 0; k < 99; k++) { // draw last line after footer
    amatches[matchcount+6][k] = 0x5F;
    matches[matchcount+6][k] = 0x5F;
    }
    matchcount--;
    matchcount--;
    musicsearched = 1;
}

The result report is stored in two parallel C char arrays that were intended to produce a fixed width file for emailing, but if printed to screen side by side,
can look like this:

xPod_Match_zps8c02f2fd.jpg


Images002_zpsc7682570.png


enjoy!
& points to whomever sees why it's so fast!
 
Last edited:

TheWatchfulOne

macrumors 6502a
Jun 19, 2009
551
498
Sounds great! Thanks for sharing.

But I think there's a flaw:

"I Think We're Alone Now" is not displaying Tommy James & The Shondells.

I guess it could be a problem with your iTunes library. ;)

Impressive search time none-the-less!:cool:

As to why it's so fast, my guess is this:
You're using plain C and no Objective-C objects (except for NSDate, NSArray, and a custom class, MPMediaQuery.) C is a small language with very little overhead. So you are not spending processing time allocating memory for and then destroying Cocoa objects. That's my conclusion from things I've read in various places. I'm no expert.
 
Comment

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
But I think there's a flaw:

"I Think We're Alone Now" is not displaying Tommy James & The Shondells.

I guess it could be a problem with your iTunes library. ;)

Maybe I just misspelled the track title originally for that one :)

Impressive search time none-the-less!:cool:

As to why it's so fast, my guess is this...

Thanks :)
Um, no!
Arrays are already allocated.

By default the Mediaquery is already in order of track title.
Rather than comparing every title to every other title,
you only need compare every title with those beneath it,
until the next title does not match, then resume the search from there :)

BTW a few well placed NSLOG lines would alleviate the need to work
with the output arrays of this routine in order to test it out.
 
Comment
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.