Расположение необработанного аудио GNAudioSourceMic

В настоящее время я разрабатываю приложение, которое использует мобильный клиент Gracenote для создания отпечатка пальца, а также для определения музыки, которую я слушаю. Я успешно реализовал его в своем проекте, но теперь из-за бизнес-требований я должен использовать звук, записанный 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]);
    }

}

Сталкивался ли кто-нибудь с такой же потребностью, как описано выше?

заранее спасибо


person Paulo Miguel Almeida    schedule 27.05.2014    source источник


Ответы (2)


После долгих поисков вчера я нашел решение, которое не соответствует тому, что я ожидал ранее, но оно работает так хорошо, как я хочу. Я решил сам записать микрофон 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

Заметки: если вы используете ARC, не забудьте добавить флаг компилятора -fno-objc-arc в Compiling BuildPhase, как показано ниже.

введите здесь описание изображения

ВашViewController.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

ВашViewController.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

Кредиты принадлежат Брайану Уитману и библиотеке Echo Nest за решение MicrophoneInput.

Надеюсь, это поможет кому-то, кто сталкивается с той же ситуацией.

Ваше здоровье

person Paulo Miguel Almeida    schedule 28.05.2014

Gracenote SDK предоставляет доступ к аудиоданным даже при использовании прилагаемого класса GnMic. Класс 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
}
person user2812322    schedule 29.05.2014
comment
Привет @ user2812322, я не уверен, какую версию вы используете, но в GraceNoteMusicID SDK нет такого класса. - person Paulo Miguel Almeida; 30.05.2014
comment
@PauloMiguelAlmeida Да, вы правы. Я имел в виду более позднюю версию SDK. Но та же функциональность есть и в версии, которую вы используете, отличается только имя класса и протокола. В версии, которую вы используете, класс микрофона должен называться GnAudioSourceMic, а протокол делегата должен называться GNAudioSourceDelegate. Реализация с этим классом и делегатом будет такой же, как и в моем предыдущем ответе. - person user2812322; 05.06.2014