簡體   English   中英

iOS如何從歌曲(iPod庫)中獲取音頻樣本?

[英]iOS How to get audio samples from song (ipod library)?

目前,在我的應用程序中,我正在對來自內置麥克風的音頻樣本進行FFT分析。 我讓用戶使用ipod庫播放歌曲,使用揚聲器,麥克風捕獲聲音,然后可以計算FFT。 我對這種解決方案不滿意。 我想直接從音頻文件(iPod庫)中獲取樣本並計算FFT。 我知道這是可能的,因為我在AppStore中看到了可以分析ipod庫中歌曲的應用程序。 我怎樣才能做到這一點?

您可以使用AVAssetExportSession將歌曲從用戶庫導出到本地文件。 然后使用ExtAudioRead API打開文件,然后執行FFT。 達到此效果的方法:

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;
        }
    }
}];

我最終使用了novocaine 用它來計算FFT很簡單:

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];

嘗試.h

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

在.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.
}

然后,您可以使用[MPMediaQuery songsQuery]訪問iPods庫

要解析每首歌曲,請嘗試以下代碼,其中[myPlayer nowPlayingItem]是查詢中的每個項目:

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM