iOS 如何从歌曲(ipod 库)中获取音频样本?

Posted

技术标签:

【中文标题】iOS 如何从歌曲(ipod 库)中获取音频样本?【英文标题】:iOS How to get audio samples from song (ipod library)? 【发布时间】:2013-06-07 10:09:59 【问题描述】:

目前在我的应用中,我正在对来自内置麦克风的音频样本进行 FFT 分析。我让用户从 ipod 库播放歌曲,使用扬声器、麦克风捕捉声音,我可以计算 FFT。我对这个解决方案不满意。我想直接从音频文件(ipod 库)中获取样本并计算 FFT。我知道这是可能的,因为我在 AppStore 中看到了可以分析 ipod 库中的歌曲的应用程序。我怎样才能做到这一点?

【问题讨论】:

您最终是如何计算音频文件的 FFT 的?我正在尝试做类似的事情,但不知道如何捕获单个音频样本进行分析。 @hundley 看看我的回答。 【参考方案1】:

您可以使用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;
        
    
];

【讨论】:

【参考方案2】:

我最终使用了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];

【讨论】:

【参考方案3】:

尝试 .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);

【讨论】:

这不是我要找的

以上是关于iOS 如何从歌曲(ipod 库)中获取音频样本?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 的 iPod 库中获取歌曲的物理文件位置

如何在 iOS 的 iPod 库中获取歌曲的文件位置

如何从 ipod 库歌曲中获取歌曲的歌词

如何将音频歌曲放入 iPhone 中的 NSdata

快速查找 iPod 库中歌曲的位置?

IOS - 从 Ipod 访问音频流、暂停和更改音量