2017-12-01 1 views
2

AudioKithere과 같이 Google의 Speech-to-Text API로 파이프 처리하려고 시도하고 있지만 어떻게해야하는지 잘 모릅니다.AudioKit 마이크를 Google 음성 인식 텍스트에 연결

음성 대 텍스트 엔진 용 오디오를 준비하려면 인코딩을 설정하고 청크로 전달해야합니다. Google에서 사용하는 예에서는 Apple의 AVFoundation을 사용하지만 저 진폭 커팅과 같은 사전 처리를 수행 할 수 있도록 AudioKit을 사용하고 싶습니다.

나는 올바른 방법은 사용하는 것입니다. Tap : 다음 탭과 같은 만들

var asbd = AudioStreamBasicDescription() 
asbd.mSampleRate = 16000.0 
asbd.mFormatID = kAudioFormatLinearPCM 
asbd.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked 
asbd.mBytesPerPacket = 2 
asbd.mFramesPerPacket = 1 
asbd.mBytesPerFrame = 2 
asbd.mChannelsPerFrame = 1 
asbd.mBitsPerChannel = 16 

AudioKit.format = AVAudioFormat(streamDescription: &asbd)! 

:

첫째,에 의해 형식과 일치해야

open class TestTap { 
    internal let bufferSize: UInt32 = 1_024 

    @objc public init(_ input: AKNode?) { 
     input?.avAudioNode.installTap(onBus: 0, bufferSize: bufferSize, format: AudioKit.format) { buffer, _ in 

     // do work here 

     } 
    } 
} 

을하지만은 않았다 AudioKit으로 실시간으로 streamAudioData 메소드를 통해 Google Speech-to-Text API로 전송할 데이터를 처리하는 올바른 방법을 식별 할 수는 있지만 잘못된 방법일까요?

UPDATE :

내가 생성 한 Tap 같은 :

AKSettings.sampleRate = 16_000 
AKSettings.bufferLength = .shortest 

그러나 구글 :

open class TestTap { 

    internal var audioData = NSMutableData() 
    internal let bufferSize: UInt32 = 1_024 

    func toData(buffer: AVAudioPCMBuffer) -> NSData { 
     let channelCount = 2 // given PCMBuffer channel count is 
     let channels = UnsafeBufferPointer(start: buffer.floatChannelData, count: channelCount) 
     return NSData(bytes: channels[0], length:Int(buffer.frameCapacity * buffer.format.streamDescription.pointee.mBytesPerFrame)) 
    } 

    @objc public init(_ input: AKNode?) { 

     input?.avAudioNode.installTap(onBus: 0, bufferSize: bufferSize, format: AudioKit.format) { buffer, _ in 
      self.audioData.append(self.toData(buffer: buffer) as Data) 

      // We recommend sending samples in 100ms chunks (from Google) 
      let chunkSize: Int /* bytes/chunk */ = Int(0.1 /* seconds/chunk */ 
       * AudioKit.format.sampleRate /* samples/second */ 
       * 2 /* bytes/sample */) 

      if self.audioData.length > chunkSize { 
       SpeechRecognitionService 
        .sharedInstance 
        .streamAudioData(self.audioData, 
            completion: { response, error in 
             if let error = error { 
              print("ERROR: \(error.localizedDescription)") 
              SpeechRecognitionService.sharedInstance.stopStreaming() 
             } else if let response = response { 
              print(response) 
             } 
        }) 
       self.audioData = NSMutableData() 
      } 

     } 
    } 
} 

viewDidLoad:에서

, 나는 함께 AudioKit을 설정하고있어 불평 :

ERROR: Audio data is being streamed too fast. Please stream audio data approximately at real time.

청크 크기와 같은 여러 매개 변수를 변경하지 않으려 고 시도했습니다.

답변

2

AKNodeRecorder를 사용하여 기록하고 결과 AKAudioFile의 버퍼를 API로 전달할 수 있습니다. 좀 더 실시간을 원한다면, 기록 할 AKNode의 avAudioNode 속성에 탭을 설치하고 버퍼를 계속해서 API에 전달할 수 있습니다.

그러나 사전 처리가 필요한 이유가 궁금합니다. Google API는 언급 한 샘플 코드로 생성 된 레코딩에 최적화되어 있습니다.

저는 iOS Speech API으로 많은 성공/재미를 보았습니다. Google API와 함께 가고 싶은 이유가 있는지 확신 할 수 없지만 아직 확인하지 않은 경우 체크 아웃하여 내게 도움이되는지 확인하는 것이 좋습니다.

희망이 도움이됩니다.

+0

안녕 @cgmaier - 응답 해 주셔서 감사합니다. 첨부 된 카디오이드 마이크를 사용 함에도 불구하고 사용자 옆에있는 사람을 태우고 있기 때문에 사전 처리하고 싶습니다.스피치 - 텍스트 시스템은 매우 민감하기 때문에 나는 더 낮은 신호를 차단하고 싶습니다. – barnabus

3

해결책을 찾았습니다. here. 내 Tap에 대한

최종 코드는 다음과 같습니다

open class GoogleSpeechToTextStreamingTap { 

internal var converter: AVAudioConverter! 

@objc public init(_ input: AKNode?, sampleRate: Double = 16000.0) { 

    let format = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: sampleRate, channels: 1, interleaved: false)! 

    self.converter = AVAudioConverter(from: AudioKit.format, to: format) 
    self.converter?.sampleRateConverterAlgorithm = AVSampleRateConverterAlgorithm_Normal 
    self.converter?.sampleRateConverterQuality = .max 

    let sampleRateRatio = AKSettings.sampleRate/sampleRate 
    let inputBufferSize = 4410 // 100ms of 44.1K = 4410 samples. 

    input?.avAudioNode.installTap(onBus: 0, bufferSize: AVAudioFrameCount(inputBufferSize), format: nil) { buffer, time in 

     let capacity = Int(Double(buffer.frameCapacity)/sampleRateRatio) 
     let bufferPCM16 = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(capacity))! 

     var error: NSError? = nil 
     self.converter?.convert(to: bufferPCM16, error: &error) { inNumPackets, outStatus in 
      outStatus.pointee = AVAudioConverterInputStatus.haveData 
      return buffer 
     } 

     let channel = UnsafeBufferPointer(start: bufferPCM16.int16ChannelData!, count: 1) 
     let data = Data(bytes: channel[0], count: capacity * 2) 

     SpeechRecognitionService 
      .sharedInstance 
      .streamAudioData(data, 
          completion: { response, error in 
           if let error = error { 
            print("ERROR: \(error.localizedDescription)") 
            SpeechRecognitionService.sharedInstance.stopStreaming() 
           } else if let response = response { 
            print(response) 
           } 
      }) 
    } 
}