2015-06-20 20 views
12

Tôi đã tìm thấy rất nhiều ví dụ trực tuyến để làm việc với âm thanh trong iOS, nhưng hầu hết trong số đó là khá lỗi thời và không áp dụng cho những gì tôi đang cố gắng hoàn thành. Đây là dự án của tôi:Làm cách nào để ghi lại các mẫu âm thanh trong iOS bằng Swift?

Tôi cần chụp mẫu âm thanh từ hai nguồn - đầu vào micrô và tệp âm thanh được lưu trữ. Tôi cần phải thực hiện FFT trên các mẫu này để tạo ra một "dấu vân tay" cho toàn bộ clip, cũng như áp dụng một số bộ lọc bổ sung. Mục tiêu cuối cùng là xây dựng một loại phần mềm nhận dạng bài hát tương tự như Shazam, v.v.

Cách tốt nhất để nắm bắt các mẫu âm thanh riêng lẻ trong iOS 8 để thực hiện Chuyển đổi Fourier nhanh là gì? Tôi tưởng tượng kết thúc với một mảng lớn trong số họ, nhưng tôi nghi ngờ rằng nó có thể không hoạt động như thế. Thứ hai, làm cách nào tôi có thể sử dụng khung tăng tốc để xử lý âm thanh? Nó có vẻ là cách hiệu quả nhất để thực hiện phân tích phức tạp về âm thanh trong iOS.

Tất cả các ví dụ tôi đã xem trực tuyến đang sử dụng các phiên bản cũ hơn của iOS và Objective-C và tôi không thể dịch thành công các phiên bản đó thành Swift. IOS 8 có cung cấp một số khung công tác mới cho loại điều này không?

+0

Bạn có thể bắt đầu bằng cách xem các ví dụ của Apple. Chúng có thể nằm trong Objective-C, nhưng các API không thay đổi. Tất cả các hàm vDSP_xx đều có API C trong mọi trường hợp, và thực tế, phần phân tích của dự án của bạn có thể sẽ được viết bằng C hoặc C++ (điều này, một cách ngẫu nhiên, lời khuyên từ các kỹ sư của Apple tại WWDC năm nay cho viết xử lý âm thanh/xử lý hiển thị). Đối với ghi vân tay âm thanh, đây là một vấn đề không tầm thường và quá hội đồng cho SO. – marko

+0

bạn có tìm thấy gì không? – hoangpx

Trả lời

7

nhanh chóng

Recording trong iOS:

  • Tạo và duy trì một thể hiện của một AVAudioRecorder, như trong var audioRecorder: AVAudioRecorder? = nil
  • Khởi AVAudioRecorder của bạn với một URL để lưu trữ các mẫu và một số cài đặt kỷ lục

Buổi ghi hình chuỗi:

  1. gọi prepareToRecord()
  2. gọi record()
  3. gọi stop()

Hoàn Swift/AVAudioRecorder Ví dụ

Tại trung tâm của phương pháp ghi âm của bạn, bạn có thể có:

func record() { 
    self.prepareToRecord() 
    if let recorder = self.audioRecorder { 
     recorder.record() 
    } 
} 

Để chuẩn bị ghi âm (truyền đến một file), bạn có thể có:

func prepareToRecord() { 
    var error: NSError? 
    let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString 
    let soundFileURL: NSURL? = NSURL.fileURLWithPath("\(documentsPath)/recording.caf") 

    self.audioRecorder = AVAudioRecorder(URL: soundFileURL, settings: recordSettings as [NSObject : AnyObject], error: &error) 
    if let recorder = self.audioRecorder { 
     recorder.prepareToRecord() 
    } 
} 

Cuối cùng, để ngừng quay, sử dụng này:

func stopRecording() { 
    if let recorder = self.audioRecorder { 
     recorder.stop() 
    } 
} 

Ví dụ trên cũng cần import AVFoundation và một số recordSettings, còn lại cho bạn lựa chọn. Một ví dụ về recordSettings có thể trông như thế này:

let recordSettings = [ 
    AVFormatIDKey: kAudioFormatAppleLossless, 
    AVEncoderAudioQualityKey : AVAudioQuality.Max.rawValue, 
    AVEncoderBitRateKey : 320000, 
    AVNumberOfChannelsKey: 2, 
    AVSampleRateKey : 44100.0 
] 

Làm điều này, bạn đã hoàn tất.


Bạn cũng có thể muốn kiểm tra this Stack Overflow answer, trong đó bao gồm một demo project.

+2

Thông tin này hữu ích, nhưng làm cách nào tôi có thể trích xuất từng mẫu âm thanh từ bản ghi? Tôi cần dữ liệu thô - tốt nhất là một mảng Floats mà tôi có thể thực hiện phân tích. Cùng một câu hỏi áp dụng cho một tệp đã có trên đĩa. – hundley

+0

Giả sử bạn sử dụng định dạng 'kAudioFormatAppleLossless' ở trên, các mẫu được lưu trữ trong tệp CAF được ghi trên https://developer.apple.com/library/ios/documentation/MusicAudio/Reference/CAFSpec/CAF_overview/CAF_overview.html#//apple_ref/doc/uid/TP40001862-CH209-TPXREF101. Đọc các mẫu từ một tệp như vậy được trả lời tại http://stackoverflow.com/questions/13996236/how-to-convert-wav-caf-files-sample-data-to-byte-array. – SwiftArchitect

+1

Tôi thấy http://swiftarchitect.com/recipes/#SO-32342486 của bạn rất hữu ích. Cảm ơn. – vivin

0

AVAudioEngine là cách để thực hiện việc này. Từ tài liệu của Apple:

  • Đối với phát lại và ghi âm của một ca khúc duy nhất, sử dụng AVAudioPlayer và AVAudioRecorder.
  • Để xử lý âm thanh phức tạp hơn, hãy sử dụng AVAudioEngine. AVAudioEngine bao gồm AVAudioInputNode và AVAudioOutputNode cho đầu vào và đầu ra âm thanh. Bạn cũng có thể sử dụng đối tượng AVAudioNode cho chế biến và các hiệu ứng trộn vào âm thanh của bạn

Sẽ thẳng với bạn: AVAudioEngine là một API cực kỳ khó tính với tài liệu hướng dẫn mơ hồ, tin nhắn báo lỗi hiếm khi hữu ích, và hầu như không trực tuyến các ví dụ mã thể hiện nhiều hơn các tác vụ cơ bản nhất. NHƯNG nếu bạn dành thời gian để vượt qua đường cong học tập nhỏ, bạn có thể thực sự làm một số điều kỳ diệu với nó tương đối dễ dàng.

tôi đã xây dựng một đơn giản "sân chơi" điều khiển xem đó chứng tỏ cả hai micro và lấy mẫu tập tin âm thanh làm việc song song:

import UIKit 

class AudioEnginePlaygroundViewController: UIViewController { 
    private var audioEngine: AVAudioEngine! 
    private var mic: AVAudioInputNode! 
    private var micTapped = false 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     configureAudioSession() 
     audioEngine = AVAudioEngine() 
     mic = audioEngine.inputNode! 
    } 

    static func getController() -> AudioEnginePlaygroundViewController { 
     let me = AudioEnginePlaygroundViewController(nibName: "AudioEnginePlaygroundViewController", bundle: nil) 
     return me 
    } 

    @IBAction func toggleMicTap(_ sender: Any) { 
     if micTapped { 
      mic.removeTap(onBus: 0) 
      micTapped = false 
      return 
     } 

     let micFormat = mic.inputFormat(forBus: 0) 
     mic.installTap(onBus: 0, bufferSize: 2048, format: micFormat) { (buffer, when) in 
      let sampleData = UnsafeBufferPointer(start: buffer.floatChannelData![0], count: Int(buffer.frameLength)) 
     } 
     micTapped = true 
     startEngine() 
    } 

    @IBAction func playAudioFile(_ sender: Any) { 
     stopAudioPlayback() 
     let playerNode = AVAudioPlayerNode() 

     let audioUrl = Bundle.main.url(forResource: "test_audio", withExtension: "wav")! 
     let audioFile = readableAudioFileFrom(url: audioUrl) 
     audioEngine.attach(playerNode) 
     audioEngine.connect(playerNode, to: audioEngine.outputNode, format: audioFile.processingFormat) 
     startEngine() 

     playerNode.scheduleFile(audioFile, at: nil) { 
      playerNode .removeTap(onBus: 0) 
     } 
     playerNode.installTap(onBus: 0, bufferSize: 4096, format: playerNode.outputFormat(forBus: 0)) { (buffer, when) in 
      let sampleData = UnsafeBufferPointer(start: buffer.floatChannelData![0], count: Int(buffer.frameLength)) 
     } 
     playerNode.play() 
    } 

    // MARK: Internal Methods 

    private func configureAudioSession() { 
     do { 
      try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: [.mixWithOthers, .defaultToSpeaker]) 
      try AVAudioSession.sharedInstance().setActive(true) 
     } catch { } 
    } 

    private func readableAudioFileFrom(url: URL) -> AVAudioFile { 
     var audioFile: AVAudioFile! 
     do { 
      try audioFile = AVAudioFile(forReading: url) 
     } catch { } 
     return audioFile 
    } 

    private func startEngine() { 
     guard !audioEngine.isRunning else { 
      return 
     } 

     do { 
      try audioEngine.start() 
     } catch { } 
    } 

    private func stopAudioPlayback() { 
     audioEngine.stop() 
     audioEngine.reset() 
    } 
} 

Các mẫu âm thanh được trao cho bạn qua xử lý hoàn installTap 's mà liên tục được gọi là âm thanh đi qua nút khai thác (micrô hoặc trình phát tệp âm thanh) trong thời gian thực. Bạn có thể truy cập các mẫu riêng lẻ bằng cách lập chỉ mục con trỏ mẫuData mà tôi đã tạo trong mỗi khối.

Các vấn đề liên quan