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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

Q&A

解決済

1回答

3164閲覧

CMSampleBufferクラスで44100hzの音声データを取り込んでも5hzほどでしかとれない

tetsutail

総合スコア81

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

0グッド

0クリップ

投稿2016/05/04 11:56

###前提・実現したいこと
CMSampleBufferクラスで44100hzの音声データを取り込んでも5hzほどでしかとれない

###発生している問題・エラーメッセージ
swiftで音楽データを取り込んでみようと思い、CMSampleBufferクラスを使ってデータサンプルをとってみたのですが、本来の音声データ(mp3)のサンプリング周波数が44100hzに対して、取り込んだ音声データは5hzほどしかないという状況です。海外のサイトも閲覧しましたが、わかりませんでした。詳しい方、ご教授お願いします。

エラーメッセージ

###該当のソースコード
swift

//mp3データを取得
let sineURL = NSBundle.mainBundle().URLForResource("SUPER", withExtension: "mp3")!
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() let sampleData = NSMutableData() //サンプリングしたデータを格納する配列 var arraySamples = [Int16]() //読み込むデータが無くなるまで、つまり終端のデータまで読み込みつづける。 while assetReader.status == AVAssetReaderStatus.Reading {

//copyNextSampleBuffer:次のサンプルに進む?
if let sampleBufferRef = trackOutput.copyNextSampleBuffer() {
//samplebufferRefのprint結果については後述。
print(sampleBufferRef)

if let blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef) { let bufferLength = CMBlockBufferGetDataLength(blockBufferRef) let data = NSMutableData(length: bufferLength) CMBlockBufferCopyDataBytes(blockBufferRef, 0, bufferLength, data!.mutableBytes) let samples = UnsafeMutablePointer<Int16>(data!.mutableBytes) sampleData.appendBytes(samples, length: bufferLength) CMSampleBufferInvalidate(sampleBufferRef) if(samples.memory < -32766 || samples.memory > 32766){ arraySamples.append(32767) } else{ arraySamples.append(samples.memory) } } } }

###試したこと
arraySamples.append(samples.memory)の回数を計算すると、240秒のデータ量でだいたい1200個のsamplesが得られました。これではたったの5hzしかサンプリングできていないのです。
###補足情報(言語/FW/ツール等のバージョンなど)
print(sampleBufferRef)の結果です。

CMSampleBuffer 0x7fcbe3e215f0 retainCount: 6 allocator: 0x10dbeca40
invalid = NO
dataReady = YES
makeDataReadyCallback = 0x0
makeDataReadyRefcon = 0x0
formatDescription = <CMAudioFormatDescription 0x7fcbe3e4b290 [0x10dbeca40]> {
mediaType:'soun'
mediaSubType:'lpcm'
mediaSpecific: {
ASBD: {
mSampleRate: 44100.000000
mFormatID: 'lpcm'
mFormatFlags: 0xc
mBytesPerPacket: 4
mFramesPerPacket: 1
mBytesPerFrame: 4
mChannelsPerFrame: 2
mBitsPerChannel: 16 }
cookie: {(null)}
ACL: {(null)}
}
extensions: {(null)}
}
sbufToTrackReadiness = 0x0
numSamples = 8192
sampleTimingArray[1] = {
{PTS = {0/44100 = 0.000}, DTS = {INVALID}, duration = {1/44100 = 0.000}},
}
sampleSizeArray[1] = {
sampleSize = 4,
}
dataBuffer = 0x7fcbe3e55020

この下から8行目のnumSamples = 8912の分がまとめて一つのデータとして入っているのではないかと考えられるのですが、この値を変える方法がわかりません。

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

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

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

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

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

guest

回答1

0

ベストアンサー

sampleDataには正しい読み出しデータが入っているように見えます。

Simulatorで試したところ、32768バイトづつ読み込まれるようなので、
240sec * 44100 * sizeof(Int16) * 2(チャンネル) = 42336000 bytes
42336000 / 32768 = 1292 回のループ
1200と言っているのはループ回数でしょう。
samples.memoryは最初のInt16を表しますので、arraySamplesに意味があるデータが入るとは思えません。

回答のピントがずれていたら、質問を変えてみてください。

投稿2016/05/04 14:42

編集2016/05/04 14:48
pebble8888

総合スコア390

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

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

tetsutail

2016/05/04 15:55 編集

回答ありがとうございます。 ループ回数についても理解できたのでとても助かりました。 また、samples.memoryやarraySampleに関してですが、何回か実行しても、arraySamplesに同じデータが入ったため、意味のあるデータなのかと思っていました。ループごとにsamplesが更新されているはずなのですが、やはりsamples.memoryはかわらないのでしょうか? そして、質問の意図がわかりづらく申し訳ありません。 sampleDataから44100hzのサンプリング周波数でサンプリングした音声データを配列に入れたいのですが、どうすればよいでしょうか?(とりあえず、メモリの問題は考えないとします)
pebble8888

2016/05/04 16:07 編集

sampleDataにはすでに44100Hzの周波数でサンプリングした音声データが入っています。NSMutableDataなのでバイトデータ列ですが。Int16の配列にしたいということでしょうか? samples = UnsafeMutablePointer<Int16> はいわゆるC言語でいうポインタですからInt16の型が32768/2個並んだメモリの先頭アドレスを指しており、samples.memoryでは32768/2個分の最初の1個のInt16での値を表しています。残りの(32768/2)-1個のデータを見るには、samples.advancedBy(1).memory、samples.advancedBy(2).memoryのように見ていき全て(32768/2)個分appendしていけば期待するものは得られると思います。 あと、データはmp3ファイルから取り出したものなので、-32766,32766でclipする意味はありません。
tetsutail

2016/05/04 17:46 編集

お早い回答本当にありがとうございます。 既存のコードから見よう見まねで作ったプログラムだったため、NSMutableData型をよくわかっておらず、またなぜUnsafeMutablePointer、つまりポインタを使うべきなのかもよくわかっていませんでしたが、ポインタの先頭から準に複数データがまとまって入ると考えれば納得ですね。確かにそう考えれば、おっしゃる通りの方法でポインタの中の値を利用できそうです。 が、これではsampleDataが絡んでおらず、sampleDataの意味がないような気がしてきました。という認識であっているのでしょうか?そうすると、sampleDataは必要ないのでしょうか? お気づきでしょうが、なぜかsampleDataにappendByteしたデータを使っていませんでした。そこで、このバイトデータ列を利用する場合はどのように扱えば良いのでしょうか?もし、質問者様の言われるようにInt16に変換できるのであれば、その方法もご教授願いたいです。ちなみに、print文を使ってsampleDataの中身を見たところ、バイトデータ列は具体的には16進数8桁の列(例:e4e4e0e2 )となっていました。 また、最後の[ -32766, 32766 ]でclipするのは意味がないというのはどういう意味でしょうか?mp3ではなく、waveファイルなどであれば変わるのでしょうか? 質問が多く申し訳ないですが、お時間があれば回答よろしくお願いします。
pebble8888

2016/05/05 01:04

>質問者様の言われるようにInt16に変換できるのであれば、その方法もご教授願いたいです。 その方法を回答したつもりです。 繰り返しになりますが、UnsafeMutablePointerのadvancedByを使いましょう。 >最後の[ -32766, 32766 ]でclipするのは意味がないというのはどういう意味でしょうか? waveでも同じです。 元々音データですから、音として有効なデータであるはずだからです。 それにInt16型ですから-32768〜32767の範囲の値しかとることはできません。
tetsutail

2016/05/05 02:50

わかりました。一度得たデータを音声ファイルとして書き出しして確かめてみたいと思います。何度もご返答いただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問