Swift 2: аудиограф AVAssetReader и NSInputStream

Я пытаюсь преобразовать пример из книги Боба Маккуна Learning AVFoundation и имею некоторые проблемы с использованием AVAssetReader и NSInputStream. График должен быть чистой синусоидой, но значения каким-то образом отражаются на оси X.

Я пробовал каждую итерацию замены байтов, о которой только мог подумать, и это не сработало.

Площадка размещена на github здесь: https://github.com/justinlevi/AVAssetReader

//: Playground - noun: a place where people can play

import UIKit
import AVFoundation
import XCPlayground

func plotArrayInPlayground<T>(arrayToPlot:Array<T>, title:String) {
  for currentValue in arrayToPlot {
    XCPCaptureValue(title, value: currentValue)
  }
}

class SSSampleDataFilter {
  var sampleData:NSData?

  init(data:NSData) {
    sampleData = data
  }

  func filteredSamplesForSize(size:CGSize) -> [Int]{
    var filterSamples = [UInt16]()

    if let sampleData = sampleData {
      let sampleCount = sampleData.length
      let binSize = CGFloat(sampleCount) / size.width

      let stream = NSInputStream(data: sampleData)
      stream.open()

      var readBuffer = Array<UInt8>(count: 16 * 1024, repeatedValue: 0)
      var totalBytesRead = 0

      let size = sizeof(UInt16)
      while (totalBytesRead < sampleData.length) {
        let numberOfBytesRead = stream.read(&readBuffer, maxLength: size)
        let u16: UInt16 = UnsafePointer<UInt16>(readBuffer).memory

        var sampleBin = [UInt16]()
        for _ in 0..<Int(binSize) {
          sampleBin.append(u16)
        }

        filterSamples.append(sampleBin.maxElement()!)
        totalBytesRead += numberOfBytesRead
      }

      //plotArrayInPlayground(filterSamples, title: "Samples")
    }

    return [0]

  }
}

let sineURL = NSBundle.mainBundle().URLForResource("440.0-sine", withExtension: "aif")!
let asset = AVAsset(URL: sineURL)
var assetReader:AVAssetReader

do{
  assetReader = try AVAssetReader(asset: asset)
}catch{
  fatalError("Unable to read Asset: \(error) : \(__FUNCTION__).")
}

let track = asset.tracksWithMediaType(AVMediaTypeAudio).first
let outputSettings: [String:Int] =
  [ AVFormatIDKey: Int(kAudioFormatLinearPCM),
    AVLinearPCMIsBigEndianKey: 0,
    AVLinearPCMIsFloatKey: 0,
    AVLinearPCMBitDepthKey: 16,
    AVLinearPCMIsNonInterleaved: 0]

let trackOutput = AVAssetReaderTrackOutput(track: track!, outputSettings: outputSettings)

assetReader.addOutput(trackOutput)
assetReader.startReading()

var sampleData = NSMutableData()

while assetReader.status == AVAssetReaderStatus.Reading {
  if let sampleBufferRef = trackOutput.copyNextSampleBuffer() {
    if let blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef) {
      let bufferLength = CMBlockBufferGetDataLength(blockBufferRef)
      var data = NSMutableData(length: bufferLength)
      CMBlockBufferCopyDataBytes(blockBufferRef, 0, bufferLength, data!.mutableBytes)
      var samples = UnsafeMutablePointer<Int16>(data!.mutableBytes)
      sampleData.appendBytes(samples, length: bufferLength)
      CMSampleBufferInvalidate(sampleBufferRef)
    }
  }
}

let view = UIView(frame: CGRectMake(0, 0, 375.0, 667.0))
//view.backgroundColor = UIColor.lightGrayColor()

if assetReader.status == AVAssetReaderStatus.Completed {
  print("complete")

  let filter = SSSampleDataFilter(data: sampleData)
  let filteredSamples = filter.filteredSamplesForSize(view.bounds.size)
}

//XCPShowView("Bezier Path", view: view)
XCPSetExecutionShouldContinueIndefinitely(true)

Вот как должен выглядеть график (взято из Audacity) График синусоиды аудиофайла

Вот как выглядит график на детской площадке

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


person Justin Levi Winter    schedule 21.08.2015    source источник


Ответы (1)


К сожалению, ваша игровая площадка ничего не отображает для меня в Xcode7b5, однако вы просите AVAssetReaderTrackOutput дать вам подписанные 16-битные целые числа, но ваш код обрабатывает их как неподписанные UInt16 (и ваш файл Audacity использует числа с плавающей запятой).

Изменение всех экземпляров UInt16 на Int16 на вашей игровой площадке, кажется, печатает разумно выглядящие синусоидальные данные.

person Rhythmic Fistman    schedule 22.08.2015
comment
Странно, что он не отобразился для вас в Xcode7b5. Вы взяли версию с github, которая включала аудиофайл AIFF? Конечно, как только я изменил все экземпляры UInt16 на «Int16», все, кажется, работает. - person Justin Levi Winter; 22.08.2015
comment
Вчера часами смотрел на это. Спасибо - person Justin Levi Winter; 22.08.2015
comment
Тем не менее, дополнительный вопрос: есть идеи, почему aif, caf, m4a работают нормально, а mp3-версия того же звука - нет? Мне нужно вернуться к документам и посмотреть, могу ли я понять, почему, но я, хотя AVassetReader, также позаботился о сжатии mp3. - person Justin Levi Winter; 22.08.2015
comment
Что происходит с мп3? - person Rhythmic Fistman; 22.08.2015
comment
Трудно сказать на игровой площадке, но ошибка Execution была прервана, причина: EXC_BAD_INSTRUCTION (code=EXC_i386_INVOP, subcode=0x0). Кажется, в проекте iOS все работает нормально, и я опубликую его в своей учетной записи github, хотя, похоже, в этом не стоит разбираться :) Еще раз спасибо. - person Justin Levi Winter; 24.08.2015