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

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

ただいまの
回答率

88.37%

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,980

tetsutail

score 76

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

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

該当のソースコード

//音声データURLを取得
let sineURL = NSBundle.mainBundle().URLForResource("memorize", 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]()
            var sampleCount = 0
//音声データの読み込み、配列への格納           
            while assetReader.status == AVAssetReaderStatus.Reading {
                if let sampleBufferRef = trackOutput.copyNextSampleBuffer() {
                    //読み込んだ音声データの形式を表示
                    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)
                 //ここで16834個分のデータを格納。ここで本来は44100個にしたいが、16384個目を超えたところでデータ値はすべて0になってしまう。           
                        for i in 0..<32768/2{
                            arraySamples.append(samples.advancedBy(i).memory)
                            print(i,arraySamples[i])
                        }
                        countSample += 1
                    }
                }
            }
        }

試したこと

最初の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/ツール等のバージョンなど)

より詳細な情報

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/10 12:27

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

    キャンセル

  • 2016/06/10 12:57

    >考えれば良いのでしょうか?

    そうです。

    左右の順番です。

    キャンセル

  • 2016/06/10 12:59

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

    キャンセル

0

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

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

 仕切り直し

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

ログに、

numSamples = 8192

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/10 16:11

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

    キャンセル

  • 2016/06/10 16:20 編集

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

    キャンセル

  • 2016/06/11 03:17

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

    キャンセル

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

  • ただいまの回答率 88.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る