Find matching Song Titles in iPod library

Discussion in 'iOS Programming' started by xArtx, Jan 2, 2013.

  1. xArtx, Jan 2, 2013
    Last edited: Jan 2, 2013

    xArtx macrumors 6502a

    Joined:
    Mar 30, 2012
    #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:

    [​IMG]

    [​IMG]

    enjoy!
    & points to whomever sees why it's so fast!
     
  2. TheWatchfulOne macrumors 6502

    Joined:
    Jun 19, 2009
    #2
    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.
     
  3. xArtx thread starter macrumors 6502a

    Joined:
    Mar 30, 2012
    #3
    Maybe I just misspelled the track title originally for that one :)

    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.
     

Share This Page