2016-12-23 11 views
2

私はAUAudioUnitsの背後にあるアイディアを掴みようと努力していましたが、AppleのWWDC 2016からpresentation videoトピック。このコードはSwift 2用に書かれており、Swift 3はポインタを行う新しい方法を紹介しています(herehere)。今はSwiftでプログラミングを始めたことがあり、そのコンセプトに慣れていないので、Swift 2からSwift 3への変換を手動で行う方法を理解できませんでした。ビルド設定を使用してもは、Swift 2からSwift 3に変換中に "pointee"の置き換えを見つける問題を修正しました。

Use Legacy Swift Language Version = yes

私はそれを稼働させることができませんでした。ここ

ビデオから正確にコードされスイフト2、ためのコードである:

import Foundation 
import AVFoundation 


class SquareWaveGenerator { 
    let sampleRate: Double 
    let frequency: Double 
    let amplitude: Float 

    var counter: Double = 0.0 

    init(sampleRate: Double, frequency: Double, amplitude: Float) { 
     self.sampleRate = sampleRate 
     self.frequency = frequency 
     self.amplitude = amplitude 
    } 

    func render(buffer: AudioBuffer) { 
     let nframes = Int(buffer.mDataByteSize)/sizeof(Float) 
     var ptr = UnsafeMutablePointer<Float>(buffer.mData) 

     var j = self.counter 
     let cycleLength = self.sampleRate/self.frequency 
     let halfCycleLength = cycleLength/2 

     let amp = self.amplitude, minusAmp = -amp 

     for _ in 0..<nframes { 
      if j < halfCycleLength { 
       ptr.pointee = amp 
      } else { 
       ptr.pointee = minusAmp 
      } 
      ptr = ptr.successor() 
      j += 1.0 
      if (j > cycleLength) { 
       j -= cycleLength 
      } 
     } 

     self.counter = j 
    } 
} 

func main() { 
    //Create an AudioComponentDescription for the input/output unit we want to use. 
#if os(iOS) 
    let kOutputUnitSubType = kAudioUnitSubType_RemoteIO 
#else 
    let kOutputUnitSubType = kAudioUnitSubType_HALOutput 
#endif 

    let ioUnitDesc = AudioComponentDescription(
     componentType: kAudioUnitType_Output, 
     componentSubType: kOutputUnitSubType, 
     componentManufacturer: kAudioUnitManufacturer_Apple, 
     componentFlags: 0, 
     componentFlagsMask: 0) 

    let ioUnit = try! AUAudioUnit(componentDescription: ioUnitDesc, options: AudioComponentInstantiationOptions()) 

    /* 
     Set things up to render at the same sample rate as the hardware, 
     up to 2 channels. Note that the hardware format may not be a standard 
     format, so we make a separate render format with the same sample rate 
     and the desired channel count. 
    */ 
    let hardwareFormat = ioUnit.outputBusses[0].format 
    let renderFormat = AVAudioFormat(standardFormatWithSampleRate: hardwareFormat.sampleRate, channels: min(2,hardwareFormat.channelCount)) 

    try! ioUnit.inputBusses[0].setFormat(renderFormat) 

    // Create square wave generators. 
    let generatorLeft = SquareWaveGenerator(sampleRate: renderFormat.sampleRate, frequency: 440.0, amplitude: 0.1) 
    let generatorRight = SquareWaveGenerator(sampleRate: renderFormat.sampleRate, frequency: 440.0, amplitude: 0.1) 

    // Install a block which will be called to render. 
    ioUnit.outputProvider = { (actionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, timestamp: UnsafePointer<AudioTimeStamp>, frameCount: AUAudioFrameCount, busIndex: Int, rawBufferList: UnsafeMutablePointer<AudioBufferList>) -> AUAudioUnitStatus in 

    let bufferList = UnsafeMutableAudioBufferListPointer(rawBufferList) 
     if bufferList.count > 0 { 
      generatorLeft.render(bufferList[0]) 
      if bufferList.count > 1 { 
       generatorRight.render(bufferList[1]) 
      } 
     } 

     return noErr 

    } 

    // Allocate render resources, then start the audio hardware. 
    try! ioUnit.allocateRenderResources() 

    try! ioUnit.startHardware() 

    sleep(3) 
    ioUnit.stopHardware() 
} 

main() 

このコード:

ptr.pointee = amp 
[...] 
ptr.pointee = minusAmp 

次のエラーをスロー:

Value of type 'UnsafeMutablePointer' has no member 'pointee'

手動でこの問題を解決できなかったので、コードを手動でSwift 3に変換しようとしましたが、問題が解決することを願っていましたそれから夢中になった。ここでは、次のとおりです。

再び私は最終的には

Value of type 'UnsafeMutablePointer' has no member 'pointee'

上記のエラーに遭遇し、私は

ptr?.storeBytes(of: T, as: T.Type) 

のようなものは、「指示先」を交換することができるはず考え出し

import Foundation 
import AVFoundation 


class SquareWaveGenerator { 
    let sampleRate: Double 
    let frequency: Double 
    let amplitude: Float 

    var counter: Double = 0.0 

    init(sampleRate: Double, frequency: Double, amplitude: Float) { 
     self.sampleRate = sampleRate 
     self.frequency = frequency 
     self.amplitude = amplitude 
    } 

    func render(buffer: AudioBuffer) { 
     let nframes = Int(buffer.mDataByteSize)/MemoryLayout<Float>.size 
     var ptr = buffer.mData 

     var j = self.counter 
     let cycleLength = self.sampleRate/self.frequency 
     let halfCycleLength = cycleLength/2 

     let amp = self.amplitude, minusAmp = -amp 

     for _ in 0..<nframes { 
      if j < halfCycleLength { 
       ptr?.pointee = amp 
      } else { 
       ptr?.pointee = minusAmp 
      } 
      ptr = ptr?.advanced(by: 1) 
      j += 1.0 
      if (j > cycleLength) { 
       j -= cycleLength 
      } 
     } 

     self.counter = j 
    } 
} 

func main() { 
    //Create an AudioComponentDescription for the input/output unit we want to use. 
#if os(iOS) 
    let kOutputUnitSubType = kAudioUnitSubType_RemoteIO 
#else 
    let kOutputUnitSubType = kAudioUnitSubType_HALOutput 
#endif 

    let ioUnitDesc = AudioComponentDescription(
     componentType: kAudioUnitType_Output, 
     componentSubType: kOutputUnitSubType, 
     componentManufacturer: kAudioUnitManufacturer_Apple, 
     componentFlags: 0, 
     componentFlagsMask: 0) 

    let ioUnit = try! AUAudioUnit(componentDescription: ioUnitDesc, options: AudioComponentInstantiationOptions()) 

    /* 
     Set things up to render at the same sample rate as the hardware, 
     up to 2 channels. Note that the hardware format may not be a standard 
     format, so we make a separate render format with the same sample rate 
     and the desired channel count. 
    */ 
    let hardwareFormat = ioUnit.outputBusses[0].format 
    let renderFormat = AVAudioFormat(standardFormatWithSampleRate: hardwareFormat.sampleRate, channels: min(2,hardwareFormat.channelCount)) 

    try! ioUnit.inputBusses[0].setFormat(renderFormat) 

    // Create square wave generators. 
    let generatorLeft = SquareWaveGenerator(sampleRate: renderFormat.sampleRate, frequency: 440.0, amplitude: 0.1) 
    let generatorRight = SquareWaveGenerator(sampleRate: renderFormat.sampleRate, frequency: 440.0, amplitude: 0.1) 

    // Install a block which will be called to render. 
    ioUnit.outputProvider = { (actionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, timestamp: UnsafePointer<AudioTimeStamp>, frameCount: AUAudioFrameCount, busIndex: Int, rawBufferList: UnsafeMutablePointer<AudioBufferList>) -> AUAudioUnitStatus in 

    let bufferList = UnsafeMutableAudioBufferListPointer(rawBufferList) 
     if bufferList.count > 0 { 
      generatorLeft.render(buffer: bufferList[0]) 
      if bufferList.count > 1 { 
       generatorRight.render(buffer: bufferList[1]) 
      } 
     } 

     return noErr 

    } 

    // Allocate render resources, then start the audio hardware. 
    try! ioUnit.allocateRenderResources() 

    try! ioUnit.startHardware() 

    sleep(3) 
    ioUnit.stopHardware() 
} 

main() 

建設。私が正しく理解していれば、 "T"は私がポインタの位置に保存したい値です。私の場合、それは "amp"でしょう。 "amp"はFloat型です。

私が何をしても、コードを実行することができませんでした。それはちょうど

もう即時エラーを投げていないと正常にコンパイルが、実行している場合、lldbエラーメッセージ

を取得

Cannot convert value of type 'Float' to expected argument type 'T.Type'

または

ptr?.storeBytes(of: amp, as: Float.self) 

を投げ

ptr?.storeBytes(of: amp, as: Float()) 

ようなものを受け入れないだろう

fatal error: storeBytes to misaligned raw pointer

本質的に、私はもう何をしているのか分からず、この文脈で「T.Type」という概念を理解していない。あなたがここに実行していることAudioBuffer.mDataUnsafeMutablePointerにするために使用しながら、それは今スウィフト3で新しく追加されUnsafeMutableRawPointer、ということです

1) How do I solve this issue and get the code running?

2) Where can I learn more about these types of constructions à la Type which will help me understand what they are and what they mean?

+0

「タイプUnsafeMutablePointerの値noを持っていますメンバ 'pointee'" Swift 3では以下のようになっています:https://developer.apple.com/reference/swift/unsafemutablepointer/1641233-pointee Swift 2以前では、それは 'メモリ'と呼ばれていました。 – matt

+0

(Swift 3で) 'AudioBuffer.mData'は' UnsafeMutablePointer'ではなく 'UnsafeMutableRawPointer'の型を持っています。 'UnsafeMutableRawPointer'は' pointee'プロパティを持っていません。 – rmaddy

+0

「UnsafeMutablePointer 」と「UnsafeRawPointer」をインクリメントすることの違いが原因です。型付きポインタは一度に1つのインスタンスだけ移動しますが、生ポインタは一度に1バイトだけ移動し、配置の問題につながります。 –

答えて

3

:だから私は2つの質問があります。

guard let mData = buffer.mData 
    else { return /* or error */ } 
let nframes = Int(buffer.mDataByteSize)/MemoryLayout<Float>.size 
var ptr = mData.bindMemory(to: Float.self, capacity: nframes) 

ptrはあなたが前に使用していたものですUnsafeMutablePointer<Float>、で、以下を行う必要があります。そのデータをあなたが前にいたように動作するように、あなたはこのように、Float型に参照されるメモリをバインドすることができますそのpointeeプロパティに問題なくアクセスできます。

注:は、関数宣言でT.Typeが表示されているときはいつでも、型のインスタンスではなく、型自体を要求しています。この場合、Float.selfのタイプFloatを渡したいとします。一方、Float()を呼び出すと、新しいFloatインスタンスが作成されます。

最後に、代わりにptrを直接操作し続ける、私は少なくともあなたにデバッグモードとよりよいインターフェイスで境界チェックを与えるバッファを作成します。

let buffer = UnsafeMutableBufferPointer<Float>(start: ptr, count: frames) 
// ... 
for i in 0..<nframes { 
    if j < halfCycleLength { 
     buffer[i] = amp 
    } else { 
     buffer[i] = minusAmp 
    } 
    j += 1.0 
    // ... 
} 
関連する問題