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

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

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

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

Q&A

解決済

2回答

2841閲覧

【Swift】44100hzの音声から毎秒16834個のデータしか取得できない

tetsutail

総合スコア81

Swift 2

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

0グッド

0クリップ

投稿2016/06/09 15:22

###発生している問題・エラーメッセージ

AVAssetReaderを使って44100hzの音声データを取得し、1秒間に44100個の音声データを取得したいのですが、なぜか16384個のデータしか取得できません。と書きましたが、おそらく音声データ自体は読み込めていると思われるのですが、それをうまく取り出す方法がわかっていないという状態です。
最後の方でarraySamples.append(samples.advancedBy(i).memory)というふうに格納しているのですが、これではまずいのでしょうか?

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

Swift

1//音声データURLを取得 2let sineURL = NSBundle.mainBundle().URLForResource("memorize", withExtension: "mp3")! 3 let asset = AVAsset(URL: sineURL) 4 var assetReader:AVAssetReader 5 6 do{ 7 assetReader = try AVAssetReader(asset: asset) 8 }catch{ 9 fatalError("Unable to read Asset: \(error) : \(#function).") 10 } 11//取得する音声データ形式を設定 12 let track = asset.tracksWithMediaType(AVMediaTypeAudio).first 13 let outputSettings: [String:Int] = 14 [ AVFormatIDKey: Int(kAudioFormatLinearPCM), 15 AVLinearPCMIsBigEndianKey: 0, 16 AVLinearPCMIsFloatKey: 0, 17 AVLinearPCMBitDepthKey: 16, 18 AVLinearPCMIsNonInterleaved: 0] 19 20 21 let trackOutput = AVAssetReaderTrackOutput(track: track!, outputSettings: outputSettings) 22 23 assetReader.addOutput(trackOutput) 24 25 assetReader.startReading() 26 27 let sampleData = NSMutableData() 28 29 //サンプリングしたデータを取り出した後、格納する配列 30 var arraySamples = [Int16]() 31 var sampleCount = 0 32//音声データの読み込み、配列への格納 33 while assetReader.status == AVAssetReaderStatus.Reading { 34 if let sampleBufferRef = trackOutput.copyNextSampleBuffer() { 35 //読み込んだ音声データの形式を表示 36 print(sampleBufferRef) 37 38 if let blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef) { 39 40 let bufferLength = CMBlockBufferGetDataLength(blockBufferRef) 41 let data = NSMutableData(length: bufferLength) 42 CMBlockBufferCopyDataBytes(blockBufferRef, 0, bufferLength, data!.mutableBytes) 43 let samples = UnsafeMutablePointer<Int16>(data!.mutableBytes) 44 sampleData.appendBytes(samples, length: bufferLength) 45 CMSampleBufferInvalidate(sampleBufferRef) 46 //ここで16834個分のデータを格納。ここで本来は44100個にしたいが、16384個目を超えたところでデータ値はすべて0になってしまう。 47 for i in 0..<32768/2{ 48 arraySamples.append(samples.advancedBy(i).memory) 49 print(i,arraySamples[i]) 50 } 51 countSample += 1 52 } 53 } 54 } 55 } 56

###試したこと
最初の1秒分の出力結果は以下の通りです。
CMSampleBuffer 0x7fbbbb7247f0 retainCount: 6 allocator: 0x10ed90a40
invalid = NO
dataReady = YES
makeDataReadyCallback = 0x0
makeDataReadyRefcon = 0x0
formatDescription = <CMAudioFormatDescription 0x7fbbbb6124d0 [0x10ed90a40]> {
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 = 0x7fbbbb7047f0

0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
・・・
省略(上で値が0になっているのは、まだ曲が始まってすぐだから?)
・・・
16356 6
16357 -37
16358 -13
16359 -37
16360 26
16361 -6
16362 2
16363 -22
16364 21
16365 -27
16366 -6
16367 -17
16368 16
16369 -13
16370 -7
16371 26
16372 -19
16373 21
16374 -16
16375 1
16376 16
16377 22
16378 -23
16379 -21
16380 5
16381 -9
16382 8
16383 -38

###補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報

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

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

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

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

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

guest

回答2

0

ベストアンサー

ログにnumSamples = 8192 とありますので、一回のcopyNextSampleBuffer()で読み込まれるのが8192サンプルなのでしょう。
CMSampleBufferGetNumSamplesを呼び出して、sampleBufferRefに何サンプル入っているかを見て(bufferLengthから計算するよりも確実です。)、
その値に応じた処理をすれば良いと思います。
whileのループで8192サンプル分読み込みファイル全てが読みおったら終了するので
それを理解しましょう。
ここで8192サンプルは8192/44100=0.18秒分のデータを意味します。

投稿2016/06/10 01:26

編集2016/06/10 03:56
pebble8888

総合スコア390

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

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

tetsutail

2016/06/10 03:27

回答ありがとうございます。numSamplesはそういう意味だったのですね。この場合、while文一周期で8192個ずつ取り出され、それを5周期分強取り出した44100分を1秒分だと考えれば良いのでしょうか? また、この場合、一周期でステレオなので16384個取り出されるのですが、左右の並びはどのようになっているのでしょうか?左・右、左・右でしょうか?
pebble8888

2016/06/10 03:57

>考えれば良いのでしょうか? そうです。 左右の順番です。
tetsutail

2016/06/10 03:59

よく見ると以前回答いただいた方と同じ方なのですね。総サンプル数の計算をしていただいたことを思い出し、もう一度計算してみたところ、while1周期で8192個サンプルを取り出す場合、総サンプル数10682368 = 44100hz*242sと考えられ、44100*242個サンプルが8192個ずつ取り出されていたということが確認できました。 何度もありがとうございます。ようやくAVAssetReaderのサンプル読み込み形式がわかってきました。
guest

0

全然調べてないんですけど、mp3だから(というか圧縮されているから)データが少ない、
ということではないのでしょうか?

例えば、wavファイル(44KHz/16bit/Stereo)でも同じような結果になるでしょうか?

仕切り直し

copyNextSampleBufferが「1秒間」のデータを取ってくると思っているようですが、その根拠は何でしょうか?

ログに、

numSamples = 8192

とありますので、8192サンプルしか読み込んでいないような気がします。

投稿2016/06/10 01:01

編集2016/06/10 01:40
fuzzball

総合スコア16731

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

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

fuzzball

2016/06/10 01:08

あー、変換してるんですね。今から真面目に調べますw
fuzzball

2016/06/10 01:41 編集

回答に追記しました‥が、pebble8888さんと丸かぶりでしたw
tetsutail

2016/06/10 03:26

回答ありがとうございます。numSamplesはそういう意味だったのですね。この場合、while文一周期で8192個ずつ取り出され、それを5周期分強取り出した44100分を1秒分だと考えれば良いのでしょうか? また、この場合、一周期でステレオなので16384個取り出されるのですが、左右の並びはどのようになっているのでしょうか?左・右、左・右でしょうか?
tetsutail

2016/06/10 04:02

回答ありがとうございました。お二人の回答のおかげでAVAssetReaderの音声よみ出し形式がようやくわかってきました。
fuzzball

2016/06/10 04:18

kAudioFormatLinearPCMは、チャンネルの割り当てを定義していない(と思う)ので、元のmp3側のチャンネル割り当てを調べないといけません。mp3側がチャンネル0=左、チャンネル1=右なのであれば、変換後のリニアPCMも左、右の順に並んでいることになります。
tetsutail

2016/06/10 07:11

ご指摘ありがとうございます。何度も申しわけありませんが、元のmp3のチャンネル割り当てを調べる方法を教えていだだけないでしょうか・・・
fuzzball

2016/06/10 07:20 編集

いや、あの、まぁ左、右でいいと思いますw というか、左、右を特定しないと困るのでしょうか?
tetsutail

2016/06/10 18:17

確かに左、右を特定する必要はありませんでした。 音声解析ツールなども使って調べられるようなので、必要ならばそれと照らし合わせてみようと思います。 お手数かけましてすみません。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問