GNAudioSourceMic原始音频位置

时间:2014-05-27 20:25:46

标签: ios audio gracenote audio-fingerprinting

我目前正在开发一款应用程序,该应用程序使用Gracenote Mobile Client创建指纹以及识别我正在收听的音乐。我已经在我的项目中成功实现了它,但现在由于业务需求,我将使用Gracenote录制的音频进行不同的处理。

重点是:由于GNAudioSourceMic封装了整个麦克风录音操作,例如startRecording / stopRecording,因此我无法访问麦克风原始音频。

这是我使用的代码:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setNeedsStatusBarAppearanceUpdate];
    [self setupUI];

    @try {
        self.config = [GNConfig init:GRACENOTE_CLIENTID];
    }
    @catch (NSException * e) {
        NSLog(@"%s clientId can't be nil or the empty string",__PRETTY_FUNCTION__);
        [self.view setUserInteractionEnabled:FALSE];
        return;
    }

    // Debug is disabled in the GUI by default
#ifdef DEBUG
    [self.config setProperty:@"debugEnabled" value:@"1"];
#else
    [self.config setProperty:@"debugEnabled" value:@"0"];
#endif
    [self.config setProperty:@"lookupmodelocalonly" value:@"0"];

    // -------------------------------------------------------------------------------
    //Init AudioSource to Start Recording.
    // -------------------------------------------------------------------------------

    self.recognizeFromPCM = [GNRecognizeStream gNRecognizeStream:self.config];
    self.audioConfig = [GNAudioConfig gNAudioConfigWithSampleRate:44100 bytesPerSample:2 numChannels:1];

    self.objAudioSource = [GNAudioSourceMic gNAudioSourceMic:self.audioConfig];
    self.objAudioSource.delegate=self;

    NSError *err;

    RecognizeStreamOperation *op = [RecognizeStreamOperation recognizeStreamOperation:self.config];
    op.viewControllerDelegate = self;
    err = [self.recognizeFromPCM startRecognizeSession:op audioConfig:self.audioConfig];

    if (err) {
        NSLog(@"ERROR: %@",[err localizedDescription]);
    }

    [self.objAudioSource startRecording];

    [self performSelectorInBackground:@selector(setUpRecognizePCMSession) withObject:nil];

}

-(void) startRecordMicrophone{
    #ifdef DEBUG
        NSLog(@"%s startRecording",__PRETTY_FUNCTION__);
    #endif

    NSError *error;
    error = [self.recognizeFromPCM idNow];

    if (error) {
        NSLog(@"ERROR: %@",[error localizedDescription]);
    }

}

是否有人接触到与上述相同的需求?

提前致谢

2 个答案:

答案 0 :(得分:0)

昨天经过大量的谷歌搜索后,我想出了一个解决方案,这个解决方案不是我以前所期待的,但它的效果和我想要的一样好。我决定自己录制iOS麦克风,然后在Grancenote SDK上调用一个方法来识别我刚录制的内容。

这对我有用。

<强> MicrophoneInput.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface MicrophoneInput : UIViewController {
    AVAudioPlayer *audioPlayer;
    AVAudioRecorder *audioRecorder;
    int recordEncoding;
    enum
    {
        ENC_AAC = 1,
        ENC_ALAC = 2,
        ENC_IMA4 = 3,
        ENC_ILBC = 4,
        ENC_ULAW = 5,
        ENC_PCM = 6,
    } encodingTypes;
}

-(IBAction) startRecording;
-(IBAction) stopRecording;

@end

<强> MicrophoneInput.m

#import "MicrophoneInput.h"


@implementation MicrophoneInput

- (void)viewDidLoad
{
    [super viewDidLoad];
    recordEncoding = ENC_PCM;
}

-(IBAction) startRecording
{
    NSLog(@"startRecording");
    [audioRecorder release];
    audioRecorder = nil;

    // Init audio with record capability
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryRecord error:nil];

    NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] initWithCapacity:10];
    recordSettings[AVFormatIDKey] = @(kAudioFormatLinearPCM);
    recordSettings[AVSampleRateKey] = @8000.0f;
    recordSettings[AVNumberOfChannelsKey] = @1;
    recordSettings[AVLinearPCMBitDepthKey] = @16;
    recordSettings[AVLinearPCMIsBigEndianKey] = @NO;
    recordSettings[AVLinearPCMIsFloatKey] = @NO;   

    //set the export session's outputURL to <Documents>/output.caf
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = paths[0];
    NSURL* outURL = [NSURL fileURLWithPath:[documentsDirectory stringByAppendingPathComponent:@"output.caf"]];
    [[NSFileManager defaultManager] removeItemAtURL:outURL error:nil];
    NSLog(@"url loc is %@", outURL);

    NSError *error = nil;
    audioRecorder = [[ AVAudioRecorder alloc] initWithURL:outURL settings:recordSettings error:&error];

    if ([audioRecorder prepareToRecord] == YES){
        [audioRecorder record];
    }else {
        int errorCode = CFSwapInt32HostToBig ([error code]); 
        NSLog(@"Error: %@ [%4.4s])" , [error localizedDescription], (char*)&errorCode); 

    }
    NSLog(@"recording");
}

-(IBAction) stopRecording
{
    NSLog(@"stopRecording");
    [audioRecorder stop];
    NSLog(@"stopped");
}


- (void)dealloc
{
    [audioPlayer release];
    [audioRecorder release];
    [super dealloc];
}


@end

Obs。:如果您正在使用ARC,请不要忘记在Compiling BuildPhase上添加-fno-objc-arc编译器标志,如下所示。

enter image description here

<强> YourViewController.h

//Libraries
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

//Echonest Codegen
#import "MicrophoneInput.h"

//GracenoteMusic
#import <GracenoteMusicID/GNRecognizeStream.h>
#import <GracenoteMusicID/GNAudioSourceMic.h>
#import <GracenoteMusicID/GNAudioConfig.h>
#import <GracenoteMusicID/GNCacheStatus.h>
#import <GracenoteMusicID/GNConfig.h>
#import <GracenoteMusicID/GNSampleBuffer.h>
#import <GracenoteMusicID/GNOperations.h>
#import <GracenoteMusicID/GNSearchResponse.h>

@interface YourViewController : UIViewController<GNSearchResultReady>


@end

<强> YourViewController.m

#import "YourViewController.h"

@interface YourViewController ()
//Record
@property(strong,nonatomic) MicrophoneInput* recorder;
@property (strong,nonatomic) GNConfig *config;
@end

@implementation YourViewController


#pragma mark - UIViewController lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.recorder = [[MicrophoneInput alloc] init];

    @try {
        self.config = [GNConfig init:GRACENOTE_CLIENTID];
    }
    @catch (NSException * e) {
        NSLog(@"%s clientId can't be nil or the empty string",__PRETTY_FUNCTION__);
        [self.view setUserInteractionEnabled:FALSE];
        return;
    }

    // Debug is disabled in the GUI by default
#ifdef DEBUG
    [self.config setProperty:@"debugEnabled" value:@"1"];
#else
    [self.config setProperty:@"debugEnabled" value:@"0"];
#endif
    [self.config setProperty:@"lookupmodelocalonly" value:@"0"];
}    

-(void)viewDidAppear:(BOOL)animated{
    [self performSelectorInBackground:@selector(startRecordMicrophone) withObject:nil];
}

-(void) startRecordMicrophone{
    #ifdef DEBUG
        NSLog(@"%s startRecording",__PRETTY_FUNCTION__);
    #endif
    [self.recorder startRecording];
    [self performSelectorOnMainThread:@selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO];
}

-(void) stopRecordMicrophone{
#ifdef DEBUG
    NSLog(@"%s stopRecording",__PRETTY_FUNCTION__);
#endif
    [self.recorder stopRecording];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = paths[0];
    NSString *filePath =[documentsDirectory stringByAppendingPathComponent:@"output.caf"];

    NSData* sampleData = [[NSData alloc] initWithContentsOfFile:filePath];
        GNSampleBuffer *sampleBuffer = [GNSampleBuffer gNSampleBuffer:sampleData numChannels:1 sampleRate:8000];
    [GNOperations recognizeMIDStreamFromPcm:self config:self.config sampleBuffer:sampleBuffer];
}

#pragma mark - UI methods

-(void)makeMyProgressBarMoving {

    float actual = [self.progressBar progress];
    if (actual < 1) {
        [self.loadingAnimationView showNextLevel];
        self.progressBar.progress = actual + 0.0125;
        [NSTimer scheduledTimerWithTimeInterval:0.25f target:self selector:@selector(makeMyProgressBarMoving) userInfo:nil repeats:NO];
    }
    else{
        self.progressBar.hidden = YES;
        [self stopRecordMicrophone];
    }

}            

#pragma mark - GNSearchResultReady methods
- (void) GNResultReady:(GNSearchResult*)result{
    NSLog(@"%s",__PRETTY_FUNCTION__);
}

@end

有关MicrophoneInput解决方案的信息,请转到Brian Whitman和Echo Nest Library。

希望能帮助那些面临同样情况的人。

干杯

答案 1 :(得分:0)

即使使用附带的GnMic类,Gracenote SDK也能提供对音频数据的访问。 GnMic类定义了一个GnMicDelegate协议,您可以使用该协议在新的音频缓冲区可用时收到通知。你必须:

<强> GnViewController.h

将GnMicDelegate协议添加到类定义

@interface GnViewController : UIViewController<CLLocationManagerDelegate, UITableViewDataSource, UITableViewDelegate, UINavigationBarDelegate, UIActionSheetDelegate, GnMicDelegate>

<强> GnViewController.m

将您的类指定为GnMic实例的委托

self.gnMic = [[GnMic alloc] initWithSampleRate: 44100 bitsPerChannel: 16 numberOfChannels: 1 delegate:nil];
self.gnMic.gnMicDelegate = self;

实施协议方法。每次有新的音频缓冲区可用于处理时,都会调用此方法

- (void) audioBufferDidBecomeReady:(NSData *)samples {
    // Do something with the audio samples
}