DSFファイル

DSDオーディオファイルのDSFフォーマットについて調べてみた。
まずは、単純にこの構造を構造体で定義してみる。

最終目的は、ID3v2 タグからメタデータを取得する事である。
今回はDSFの4つのチャンクの定義から。
言語はC言語。

。DSD チャンク, fmt チャンク, data チャンク, metadata チャンク。

// 1. DSDチャンク
#define DSD_CHUNK_SIZE 28
struct dsd_chunk_header{
    char name[4];    //'D' 'S' 'D' ' ' の4バイト
    //Size of this chunk
    union {
        unsigned long long int ll;//ただしここの値をそのまま扱えるのはリトルエンディアンのみ
        unsigned char data[8];
    } size;
    //Total file size
    union {
        unsigned long long int ll;
        unsigned char data[8];
    } total_size;
    //Pointer to Metadata chunk
    //metadeta チャンクが無ければ0。あればそこへのポインタ。ID3v2 tag はファイルの末尾に置く必要がある。
    union {
        unsigned long long int ll;
        unsigned char data[8];
    } meta_offset;
};

// 2. fmtチャンク
#define FMT_CHUNK_SIZE 52
struct fmt_chunk_header{
    char name[4];    //'f' 'm' 't' ' ' の4バイト
    //Size of this chunk
    union {
        unsigned long long int ll;
        unsigned char data[8];
    } size;
    //
    //Format version. 1 がセットされている 1以外はUnkownと判断する
    union {
        unsigned long int l;
        unsigned char data[4];
    } format_version;

    //Format ID. 0がセットされている 0以外はUnkownと判断する. 0の意味は DSD raw.
    union {
        unsigned long int l;
        unsigned char data[4];
    } format_id;

    /* Channel Type. 
    1: mono, 2:stereo, 3:3 channels, 4: quad, 5: 4 channels, 6: 5 channels, 7: 5.1 channels
    DSF のインターリーブの形式
    ・2-CHANNELS STEREO
        1 : Front Left 2 : Front Right
    ・3-CHANNELS
        1 : Front Left 2 : Front Right 3 : Center
    ・QUAD
        1 : Front Left 2 : Front Right 3 : Back Left 4 : Back Right
    ・4-CHANNELS
        1 : Front Left 2 : Front Right 3 : Center 4 : Low Frequency
    ・5-CHANNELS
        1 : Front Left 2 : Front Right 3 : Center 4 : Back Left 5 : Back Right
    ・5.1-CHANNELS
        1 : Front Left 2 : Front Right 3 : Center 4 : Low Frequency 5 : Back Left 6 : Back Right
    */
    union {
        unsigned long int l;
        unsigned char data[4];
    } channel_type;

    //Channel num
    //1: mono, 2: stereo,… 6: 6 channels
    union {
        unsigned long int l;
        unsigned char data[4];
    } channel_num;

    //Sampling frequency. (サンプリング周波数)単位はHzで値は、2822400, 5644800, … 
    union {
        unsigned long int l;
        unsigned char data[4];
    } sampling_frequency;

    //Bits per sample. 単位はbitで値は、1 or 8 になる。
    union {
        unsigned long int l;
        unsigned char data[4];
    } bits_per_sample;

    /* Sample count
        サンプル数は1 チャンネルごとのサンプル数となる。
        例) n 秒間のデータの場合、サンプル数は サンプリング周波数* n となる
    */
    union {
        unsigned long long int ll;
        unsigned char data[8];
    } sample_count;
    /*
    Block size per channel. 単位はbyteで4096
    チャンネルごとのブロックサイズは固定である。
    データチャンクの末尾のブロックで、使われなかった領域はゼロ(0x00)で満たす。
    */
    union {
        unsigned long int l;
        unsigned char data[4];
    } block_size;
    //Reserved. Fill Zero(値はすべて0でセット)
    union {
        unsigned long int l;
        unsigned char data[4];
    } reserved;
};

// 3. data チャンク
struct data_chunk{
    char name[4];    //'d' 'a' 't' 'a' の4バイト
    // このチャンク(data)のサイズ。なので、(n + 12) bytes。n はサンプルデータ(DSDデータ)のバイト数
    union {
        unsigned long long int ll;//ただしここの値をそのまま扱えるのはリトルエンディアンのみ
        unsigned char data[8];
    } size;
    /*sample data.
        サンプルビット数=1 のとき、データはLSB(Least Significant Bit)ファースト形式で保存する。
        例えば、実際のDSD ストリームデータ(サンプルビット数=1)が 0x00, 0x01, 0x02, 0x03, 0x04…..
        である場合、DSF のデータチャンク中のデータは次のように書かれる。
        0x00, 0x80, 0x40, 0xC0, 0x20, ….
        (00000000, 10000000, 01000000, 11000000, 00100000, ….)

        サンプルビット数=8 のときは、1sample=1byte なので、バイト列をそのまま記述する。DSD ストリーム
        データ(サンプルビット数=8)が 0x00, 0x01, 0x02, 0x03, 0x04….. である場合、DSF のデータチャ
        ンク中のデータは次のように書かれる。
        0x00, 0x01, 0x02, 0x03, 0x04…..
        (00000000, 00000001, 00000010, 00000011, 00000100, ….)
    */
};

// 4. metadata チャンク (ID3v2)
//    このチャンクがファイルの最後に配置される。

次回はこの構造体を使って、DSDサンプルデータとmetadataチャンクを除いた情報抽出プログラムを掲載します。