【问题标题】:Translate Objective - C Introduction to AudioUnits into Swift将 Objective - C 对 AudioUnits 的介绍翻译成 Swift
【发布时间】:2016-01-22 15:12:28
【问题描述】:

我已经设法翻译了这段代码,以便调用渲染回调: http://www.cocoawithlove.com/2010/10/ios-tone-generator-introduction-to.html

我确定我的渲染回调方法没有正确实现,因为我要么根本听不到声音,要么耳机发出非常可怕的噪音。 我也看不到 viewDidLoad 中的 audioSession 与其余代码之间的连接。

有没有人可以帮我解决这个问题?

private func performRender(
inRefCon: UnsafeMutablePointer<Void>,
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBufNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus
{

// get object
let vc = unsafeBitCast(inRefCon, ViewController.self)
print("callback")

let thetaIncrement = 2.0 * M_PI * vc.kFrequency / vc.kSampleRate
var theta = vc.theta

//    var sinValues = [Int32]()
let amplitude : Double = 0.25

let abl = UnsafeMutableAudioBufferListPointer(ioData)
    for buffer in abl
    {
        let val : Int32 = Int32((sin(theta) * amplitude))
    //        sinValues.append(val)
        theta += thetaIncrement

        memset(buffer.mData, val, Int(buffer.mDataByteSize))
    }

vc.theta = theta

return noErr
}

class ViewController: UIViewController
{
let kSampleRate : Float64 = 44100
let kFrequency : Double = 440
var theta : Double = 0

private var toneUnit = AudioUnit()
private let kInputBus = AudioUnitElement(1)
private let kOutputBus = AudioUnitElement(0)

@IBAction func tooglePlay(sender: UIButton)
{
    if(toneUnit != nil)
    {
        AudioOutputUnitStop(toneUnit)
        AudioUnitInitialize(toneUnit)
        AudioComponentInstanceDispose(toneUnit)
        toneUnit = nil
    }
    else
    {
        createToneUnit()
        var err = AudioUnitInitialize(toneUnit)
        assert(err == noErr, "error initializing audiounit!")
        err = AudioOutputUnitStart(toneUnit)
        assert(err == noErr, "error starting audiooutput unit!")      
    }
}

func createToneUnit()
{
    var defaultOutputDescription = AudioComponentDescription(
        componentType: kAudioUnitType_Output,
        componentSubType: kAudioUnitSubType_RemoteIO,
        componentManufacturer: kAudioUnitManufacturer_Apple,
        componentFlags: 0,
        componentFlagsMask: 0)

    let defaultOutput = AudioComponentFindNext(nil,&defaultOutputDescription)


    let fourBytesPerFloat : UInt32 = 4
    let eightBitsPerByte : UInt32 = 8

    var err = AudioComponentInstanceNew(defaultOutput, &toneUnit)
    assert(err == noErr, "error setting audio component instance!")
    var input = AURenderCallbackStruct(inputProc: performRender,     inputProcRefCon: UnsafeMutablePointer(unsafeAddressOf(self)))

    err = AudioUnitSetProperty(toneUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, kOutputBus, &input, UInt32(sizeof(AURenderCallbackStruct)))
    assert(err == noErr, "error setting render callback!")

    var streamFormat = AudioStreamBasicDescription(
        mSampleRate: kSampleRate,
        mFormatID: kAudioFormatLinearPCM,
        mFormatFlags: kAudioFormatFlagsNativeFloatPacked,
        mBytesPerPacket: fourBytesPerFloat,
        mFramesPerPacket: 1,
        mBytesPerFrame: fourBytesPerFloat,
        mChannelsPerFrame: 1,
        mBitsPerChannel: fourBytesPerFloat*eightBitsPerByte,
        mReserved: 0)

    err = AudioUnitSetProperty(toneUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &streamFormat, UInt32(sizeof(AudioStreamBasicDescription)))
    assert(err == noErr, "error setting audiounit property!")
}

override func viewDidLoad()
{
    super.viewDidLoad()
    let audioSession = AVAudioSession.sharedInstance()

    do
    {
        try audioSession.setCategory(AVAudioSessionCategoryPlayback)
    }
    catch
    {
        print("Audio session setCategory failed")
    }

    do
    {
        try audioSession.setPreferredSampleRate(kSampleRate)
    }
    catch
    {
        print("Audio session samplerate error")
    }

    do
    {
        try audioSession.setPreferredIOBufferDuration(0.005)
    }
    catch
    {
        print("Audio session bufferduration error")
    }

    do
    {
        try audioSession.setActive(true)
    }
    catch
    {
        print("Audio session activate failure")
    }
}

【问题讨论】:

  • 感谢您提出这个问题,我正在查看相同的代码,它让我自己进行了 Swift 转换:)
  • 是的,我最终使用目标 c 来完成如此低级的任务。我承认 swift 不是一个好的选择。

标签: ios audiounit avaudiosession audiotoolbox


【解决方案1】:
  • vc.theta 没有被递增
  • memset 只占用一个字节的 val
  • AudioUnit 需要 floats,但您存储的是 Int32s
  • 音频数据的范围看起来也很有趣 - 为什么不将其保持在 [-1, 1] 范围内?
  • 也没有必要限制thetasin 可以做到这一点。

你确定这曾经在 Objective-c 中工作过吗?

【讨论】:

  • 是的,32767 不应该在那里。第一点和最后一点也是很好的提示^^。但是 memset 需要一个 Int32,所以我应该为此使用 memset 吗? Objective-c 代码工作正常。我从上面提到的网站下载了 Xcode 项目。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2015-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多