質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

2457閲覧

AudioUnitで、音程がブレるのは何故?

taro_nii_chan

総合スコア207

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2017/05/28 11:34

編集2017/05/28 11:55

何らかのデバイス(PC, iPhone, ...)から任意の波形を作り音を鳴らすための勉強しています。

Xcode 8.3.2でiOSアプリを今作っています。

「swiftでCoreAudioを使ってみる。(swift3 update 2017-02)」のサンプルコードをほぼそのまま頂いて、ViewController.swiftからplay()を呼び出す形にしてあります。

変更したのは、クラス名をMyAudioPlayerからAudioPlayerに変えたのと、M_PI.piに変えた点です。

編集したものが下のコードです。

swift

1import Foundation 2import AudioUnit 3import AudioToolbox 4import AVFoundation 5 6class AudioPlayer 7{ 8 var _audiounit: AudioUnit? = nil 9 var _x: Float = 0 10 let _sampleRate:Double = 44100 11 init() { 12 #if os(iOS) 13 let subtype = kAudioUnitSubType_RemoteIO 14 #else 15 let subtype = kAudioUnitSubType_HALOutput 16 #endif 17 var acd = AudioComponentDescription(componentType: kAudioUnitType_Output, 18 componentSubType:subtype, 19 componentManufacturer: kAudioUnitManufacturer_Apple, 20 componentFlags: 0, 21 componentFlagsMask: 0) 22 23 let ac = AudioComponentFindNext(nil, &acd) 24 AudioComponentInstanceNew(ac!, &_audiounit) 25 AudioUnitInitialize(_audiounit!); 26 // オーディオデータ供給を44100,ステレオ,標準フォーマット(Float32, Non-Interleave)に設定 27 let audioformat:AVAudioFormat = AVAudioFormat(standardFormatWithSampleRate: _sampleRate, channels: 2) 28 var asbd:AudioStreamBasicDescription = audioformat.streamDescription.pointee 29 AudioUnitSetProperty(_audiounit!, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &asbd, UInt32(MemoryLayout.size(ofValue: asbd))) 30 } 31 let callback: AURenderCallback = { 32 (inRefCon: UnsafeMutableRawPointer, 33 ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, 34 inTimeStamp: UnsafePointer<AudioTimeStamp>, 35 inBusNumber: UInt32, 36 inNumberFrames: UInt32, 37 ioData: UnsafeMutablePointer<AudioBufferList>?) 38 in 39 // ポインタからAudioPlayerインスタンスに変換 40 let AudioPlayer:AudioPlayer = Unmanaged<AudioPlayer>.fromOpaque(inRefCon).takeUnretainedValue() 41 AudioPlayer.render(inNumberFrames, ioData:ioData) 42 return noErr 43 } 44 func render(_ inNumberFrames: UInt32, ioData: UnsafeMutablePointer<AudioBufferList>?) { 45 let delta:Float = Float(443 * 2 * .pi / _sampleRate) 46 guard let abl = UnsafeMutableAudioBufferListPointer(ioData) else { 47 return 48 } 49 var x:Float = 0 50 for buffer:AudioBuffer in abl { 51 x = _x 52 let cap = Int(buffer.mDataByteSize)/MemoryLayout<Float>.size 53 assert(cap == Int(inNumberFrames)) 54 if let buf:UnsafeMutablePointer<Float> = buffer.mData?.bindMemory(to: Float.self, capacity: cap) { 55 for i:Int in 0 ..< Int(inNumberFrames) { 56 buf[i] = sin(x) 57 x += delta 58 } 59 } 60 } 61 if abl.count > 0 { 62 _x = x 63 } 64 } 65 func play() { 66 // AudioPlayerインスタンスをポインタに変換 67 let ref: UnsafeMutableRawPointer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) 68 var callbackstruct:AURenderCallbackStruct = AURenderCallbackStruct(inputProc: callback, inputProcRefCon: ref) 69 AudioUnitSetProperty(_audiounit!, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callbackstruct, UInt32(MemoryLayout.size(ofValue: callbackstruct))) 70 71 AudioOutputUnitStart(_audiounit!) 72 } 73 func stop() { 74 AudioOutputUnitStop(_audiounit!) 75 } 76} 77

ほぼ問題なく起動と同時にラ(443Hz)の音が出るのですが、音程が一定しません。微妙にブレるのです。

原因は分かりますでしょうか?
対策はありますか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こちらで実験してみたわけではないので想像となりますが、render内で常に一定のサイン波を生成しているのが原因の一端かもしれません。実際の再生時には様々な要因でデータ供給や再生処理の遅れが生じると予想されますので(特に今回の場合、リアルタイムで波を生成しようとしているのですよね)、経過時間に応じてdeltaを微調整する必要があるのではないでしょうか。
callbackに渡されるinTimeStampを見て補正すると多少は改善できるかもしれません。

参考:AudioUnit細かいことまとめ

投稿2017/05/29 04:12

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taro_nii_chan

2017/05/29 13:07

ご回答ありがとうございます。 様々な要因で再生処理の遅れが生じると予想されること、経過時間に応じてdeltaを調整する必要がありそうであること、なるほどです。 スキル不足でそれをどうやったら実際のコードに反映すればいいのかまだ分かっていませんので、質問を締め切るまでもうしばらくお時間を下さい。
taro_nii_chan

2017/05/31 13:20

お待たせしておりましたが、 簡単には実現できなさそうなので この質問は締め切らせていただきたいと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問