↑ページトップへ
表示調整
閉じる
挿絵表示切替ボタン
▼配色
▼行間
▼文字サイズ
▼メニューバー
×閉じる

ブックマークに追加しました

設定
0/400
設定を保存しました
エラーが発生しました
※文字以内
ブックマークを解除しました。

エラーが発生しました。

エラーの原因がわからない場合はヘルプセンターをご確認ください。

ブックマーク機能を使うにはログインしてください。
PR
49/50

エピ36.2 mp3の仕様を少し(続き)


 ***


 エピ36.2 mp3の仕様を少し(続き)


 ***


 mp3の仕様を調べています。やむを得ないことなのです。


 前エピでは、mp3のフレームの構成を調べて、フレームヘッダの検出を確認しました。


 今エピはサイド情報です。...CRCは無いです。


 ***


 このmp3ファイルの最初のフレームのサイド情報です。


   00 00 02 9F 48 41 81 01 12 E2 55 09 88 30 18 62

   5E 0A 4C 05 12 04 80 00 09 2D 10 62 80 50 89 28


 この32バイトを256ビットに変換すると、


 000000000 000 00000000

 001010011111 010010000 10000011 0000 0 /0100000001000100101110/ 0 0 1

 001010101000 010011000 10000011 0000 0 /0011000011000100101111/ 0 0 0

 001010010011 000000010 10001001 0000 0 /0100100000000000000000/ 0 0 1

 001001011010 001000001 10001010 0000 0 /0010100001000100100101/ 0 0 0


 となります。20bit + 59bit*4 という構成です。なお、モノラルだと 16bit + 59bit*2 = 136bit = 17byte です。


 最初の 20bit はメインデータの各ブロックに共通の情報です。その構成は、


   mainDataBegin :9bit

   privateBits :3bit

   scfsi[ch][band] :1bit *2*4 = 8bit


 です。4つある 59bit は4つあるブロックに対応する情報です。その構成は、


   part23Length :12bit

   bigValues :9bit

   globalGain :8bit

   scalefacCompress :4bit

   windowSwitchingFlag :1bit

   REGION_OR_BLOCK :22bit # union

   preFlag :1bit

   scalefacScale :1bit

   count1TableSelect :1bit


 ここで REGION_OR_BLOCK は、

   windowSwitchingFlag==0 なら REGION で

    tableSelect[reg] :5bit *3 = 15bit

    region0Count :4bit

    region1Count :3bit

   windowSwitchingFlag==1 なら BLOCK で

    blockType :2bit

    mixedBlockFlag :1bit

    tableSelect[reg] :5bit *2 = 10bit # note "*2"

    subblockGain[win] :3bit *3 = 9bit


 です。先の256ビットをこの構成に従って数値に変換すると、


   0 0 00000000

   671 144 131 0 0 {(8 1 2) 5 6} 0 0 1

   680 152 131 0 0 {(6 3 2) 5 7} 0 0 0

   659 __2 137 0 0 {(9 0 0) 0 0} 0 0 1

   602 _65 138 0 0 {(5 1 2) 4 5} 0 0 0


 となります。


 *


 サイド情報は、...とりあえず必要なのは mainDataBegin と part23Length の2つです。

   mainDataBegin : メインデータを切出す際のバイト位置

   part23Length : 各ブロックのビット長


 どちらも重要そうな雰囲気ありますね。


 一方、最後まで必要なさそうなのは privateBits です。誰も参照しないのです。値も0だけ。ボッチです。

 mixedBlockFlag もミックスブロックが無いので値は0のままですが、ミックスブロックを処理するコードは実装されていて、いちおう...、と言うかミックスブロックではないことを判定するために使用されます。そんな寂しいフラグ。


 *


 フレームの通番を f_num とします。フレームは 15298 個あるので 0〜15297 まで変化します。フレームデータとメインデータと共用です。


 ***

 **

 *


 サイド情報の mainDataBegin(9bit)です。


 メインデータは1つ前のフレームのフレームデータから始まることが多いです。その位置を決めるのが mainDataBegin です。


 mainDataBegin は 9bit あるので最大 511 になる可能性があります(...そうなるmp3ファイルを作ることは可能という意味で)。

 フレームデータは 128kbps & 44.1kHzなら、381 or 382バイトですから、2つ前のフレームデータから始まるかも知れないです(...、32kbps & 48kHz なら60or61バイトだから9フレーム前と言うこともあるな)。


 mainDataBegin の最少は0です。最初のフレームは前のフレームはないから当然に0。最初のフレーム以外でも0になることはあるかも。


 *


 とりあえず mainDataBegin をグラフにして見ましょう。カセットテープの音の振幅と比べます。


 上段は mainDataBegin で、下段は音の振幅です。

 横軸は時間で、単位は秒です。mainDataBegin の横軸は f_num を時間に変換しました(t = f_num*(576*2/44100))。

挿絵(By みてみん)

 mainDataBegin の最少は0ですが、最初(f_num=0)以外でも発生していますね。3.1 秒(f_num=122)と 396.1 秒(f_num=15166)の2つです。

 0より大きな値は19で40点あります。1〜18は無いです。


 最大は490です。次は489で1点、485で2点。...以下ボツボツです。381以上ならメインデータは2つ前のフレームデータから始まるのですが割と普通に発生してます。意外です。


 mainDataBegin は音の振幅と関係があります。

 無音とピー音では(音が単調なので?)メインデータの消費バイトが少なくなり、mainDataBegin の値は増加して425〜475程になる。

 データ部分(ギャラギャラ音)になると消費バイトが増えて、mainDataBegin は減少して20〜40程になる。


 mainDataBegin を決めているのは(ボイスレコーダの)エンコーダなのですけど、最少0と最大511の範囲から20程のマージンをとっている気配を感じます。


 他と同じくピー音のはずの 185〜205 秒の区間は何かあるのかな?


 ***

 **

 *


 次は part23Length (12bit * 4)です。


 ブロックの長さはビット単位で可変長です。part23Length でそのビット数が分かります。


 part23Length は 12bit で、4つあるので合計 (2^12)*4 = 16384 ビット(2048バイト)が最大です。フレーム長は一番長いと、320kbps, 32kHz のときに1440バイトになる。なるほど。


 とりあえずグラフにします。


 縦軸は part23Length です(値はブロックのビット長を表します)。横軸は時間で単位は秒です。

挿絵(By みてみん)

 当然のことですけど。mainDataBegin と関係がありますね。


 フレームデータから供給されるバイト数と、4ブロックで消費するバイト数によって増減するバッファ(ビットリザーバー?)の様子をグラフにして見ましょう。


 縦軸は mainDataBegin とバッファ残量で、単位はバイトです。横軸は時間。

挿絵(By みてみん)

 バッファが増減する様子は mainDataBegin の変化と似ているのですが、ズレが発生している箇所が2つあります。それは mainDataBegin が0となるところです。


 拡大して0〜4秒を見ます。

挿絵(By みてみん)

 3.18秒(f_num=122)でバッファに290バイト残っていますが、mainDataBegin が0なのでバッファは捨てて、f_num=122 のフレームデータの先頭からをメインデータとして使います。


 もったいないよ。...、と言うか、ここって秘密のデータを保存するのに利用できるね。普通に再生できるmp3ファイルだけど、小さなデータを密かに配布できる。ヤバくない?

 いや。ちゃんと仕様を公開して。フレーム通番とか経過時間を埋め込むと有益ではないか?


 *


 サイド情報の mainDataBegin と part23Length の動きを把握できましたね。


 ***


 フレームデータからメインデータを取得するには次にようにします。


   tmp = buf[-mainDataBegin:] if mainDataBegin >= 1 else []

   buf = (buf+fd0)[-512:]

   md0 = tmp+fd0


 mainDataBegin が1以上ならバッファ(変数 buf)の後ろから mainDataBegin のバイト数だけ取得して、一時保存(変数 tmp)します。mainDataBegin が0なら tmp = [] です。

 バッファとフレームデータ(変数 fd0)を加算して、後ろから512バイトを取り、バッファを更新します。

 変数 tmp と fd0 を合わせたものがメインデータ(変数 md0)になります。


 *


 メインデータ(変数 md0)のうち、ブロックのデータとして使用するのは part23Length の分だけです。


   p23s = (part23Length[0]+part23Length[1]

       +part23Length[2]+part23Length[3])/8.0


   md1 = md0[:int(p23s+0.999)]


 ブロックで使用するデータは370〜390バイトくらいで、観察した範囲では最小315バイト、最大446バイトでした。平均は382前後。


 使用しなかったデータは、次のフレームのメインデータとして(バッファを参照して)使用されるのです。


 このmp3ファイルでは2回バッファを捨てているのですが一般的な処理なのかは不確かです。


 ***

 **

 *


 ブロックを特定するところまで辿り着きました。


 次はスケールファクタと、...ハフマン符号です! きっと楽しいです(主に自分が!)


 ***


 間違いの指摘とか疑問とか、ご意見・ご感想とかありましたら、どうぞ感想欄に!


 ***

2026.9.14 微推敲

2026.9.15 微加筆


評価をするにはログインしてください。
ブックマークに追加
ブックマーク機能を使うにはログインしてください。
― 新着の感想 ―
このエピソードに感想はまだ書かれていません。
感想一覧
+注意+

特に記載なき場合、掲載されている作品はすべてフィクションであり実在の人物・団体等とは一切関係ありません。
特に記載なき場合、掲載されている作品の著作権は作者にあります(一部作品除く)。
作者以外の方による作品の引用を超える無断転載は禁止しており、行った場合、著作権法の違反となります。