1
votes

Currently in my app, I'm doing FFT analyse on audio samples coming from built-in microphone. I let user play song from ipod library, using speakers, microphone capture the sound and I can calculate FFT. I'm not happy with this solution. I would like to get samples directly from audio file (ipod library) and calculate FFT. I know this is possible, because I saw apps in AppStore, which can analyse song from ipod library. How can I do that?

3
How did you end up being able to calculate FFT on an audio file? I'm trying to do something similar but can't figure out how to capture individual audio samples for analysis.Hundley
@hundley Look at my answer.Wojczitsu

3 Answers

0
votes

You can use AVAssetExportSession to export songs from user's library to a local file. Then open the file using ExtAudioRead API and do your FFT thingy. Something to this effect:

AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset: asset
                                                                  presetName: AVAssetExportPresetPassthrough];
NSString *ext = [url pathExtension];
if ([ext isEqual: @"mp3"])
{
    exporter.outputFileType = AVFileTypeQuickTimeMovie;
    ext = @"mov"; // this is create an mov with mp3 data hidden inside it.. huhuhhaha
}
else if ([ext isEqual: @"m4a"])
{
    exporter.outputFileType = AVFileTypeAppleM4A;
}
else if ([ext isEqual: @"wav"])
{
    exporter.outputFileType = AVFileTypeWAVE;
}
else if ([ext isEqual: @"aif"])
{
    exporter.outputFileType = AVFileTypeAIFF;
}
exporter.outputURL = exportURL;
[exporter exportAsynchronouslyWithCompletionHandler: ^(void){
    int exportStatus = exporter.status;
    switch (exportStatus) {
        case AVAssetExportSessionStatusCompleted: {
            exportedURL = exporter.outputURL;
            break;
        }
    }
}];
0
votes

I ended up using novocaine. Calculating FFT with it, is simple as that:

self.audioManager = [Novocaine audioManager];
self.audioManager.forceOutputToSpeaker = YES;

self.fileReader= [[AudioFileReader alloc]
                   initWithAudioFileURL:inputFileURL
                   samplingRate:self.audioManager.samplingRate
                   numChannels:self.audioManager.numOutputChannels];


[self.fileReader play];

__block COMPLEX_SPLIT AA = A;
__block int nOver = nOver2;
FFTSetup fftSetup2 = fftSetup;
__block int log = log2n;
__block int n2 = n;
__weak MainViewController *listener2 = listener;
__weak AudioManager *wself = self;
__block float *window = (float *)malloc(sizeof(float) * n2);
vDSP_hamm_window(window, n2, 0);
__block BOOL songStarted = NO;
__block float *data = (float *)malloc(sizeof(float) * n2);
[self.audioManager setOutputBlock:^(float *data2, UInt32 numFrames, UInt32 numChannels)
 {
     [wself.fileReader retrieveFreshAudio:data2 numFrames:numFrames numChannels:numChannels];
     if(!wself.fileReader.playing && songStarted)
     {
         [listener2 nextSong:nil];
         [wself.audioManager setOutputBlock:nil];
         return;
     }
     else if(wself.fileReader.playing && !songStarted)
         songStarted = YES;


     vDSP_vmul(data2, 1, window, 1, data, 1, n2);
     vDSP_ctoz((COMPLEX*)data, 2, &AA, 1, nOver);
     vDSP_fft_zrip(fftSetup2, &AA, 1, log, FFT_FORWARD);
     // calculating square of magnitude for each value
     vDSP_zvmags(&AA, 1, AA.realp, 1, nOver);

     float *tab_results = (float *)malloc(32 * sizeof(float));
     for(int i=0;i<32;i++)
         tab_results[i]=AA.realp[i+5];//i+5
     [listener2 sendResults:tab_results];
     memset(data, 0, n2*sizeof(float));
 }];

[self.audioManager play];
-3
votes

Try to .h

#import <MediaPlayer/MediaPlayer.h>
#import <CoreAudio/CoreAudioTypes.h>
@interface ViewController : UIViewController {
MPMusicPlayerController *myPlayer;
}

In .m

- (void)viewDidLoad {
[super viewDidLoad];

myPlayer = [MPMusicPlayerController applicationMusicPlayer];
[myPlayer beginGeneratingPlaybackNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemUpdated) name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification object:nil];
// Do any additional setup after loading the view, typically from a nib.
}

Then you can access to iPods library with [MPMediaQuery songsQuery]

To parse each song try this code, where [myPlayer nowPlayingItem] is each item in query:

NSString *artist = [[myPlayer nowPlayingItem] valueForKey:MPMediaItemPropertyArtist];
NSString *title = [[myPlayer nowPlayingItem] valueForKey:MPMediaItemPropertyTitle];
NSString *genre = [[myPlayer nowPlayingItem] valueForKey:MPMediaItemPropertyGenre];
NSString *duration = [[myPlayer nowPlayingItem] valueForKey:MPMediaItemPropertyPlaybackDuration];
int minutes = floor([duration floatValue]/60);
int seconds = round([duration floatValue] - minutes * 60);
NSLog(@"%@ - %@ (%i:%02d) Genre:%@",artist,title, minutes,seconds,genre);