aiff_file_source

ビッグエンディアンの検証用にAIFFファイルのデバイスを作ってみました。
仕様は適当にググって見つけたページを参考にしました。
http://nagasm.suac.net/ASL/sound05/#aiff-1
数値がビッグエンディアンで格納されることを除けばフォーマット自体はWAVEファイルによく似ているので(実際は逆にRIFFがIFFをマネしたものらしい)、コードはほとんどコピペで書けました。
一点、「今のところ使わない」と言っていた80ビット浮動小数点数が使われていて困りました。
とりあえず、64ビット整数で保持できる範囲でデコードしています。

inline boost::uint_least64_t decode_extended(const char* s)
{
    boost::int_least16_t exp = decode_int<big,2>(s);    // 手抜きにつき、入力が負でないことを仮定
    boost::uint_least64_t mant = decode_uint<big,8>(s+2);

    if ((exp == 0) && (mant == 0))
        return 0;
    else
        return mant >> (63-(exp-16383));
}

inline void encode_extended(char* s, boost::uint_least64_t n)
{
    if (n == 0)
    {
        std::memset(s, 0, 10);
        return;
    }

    boost::int_least16_t exp = 16383+63;
    boost::uint_least64_t mant = n;
    while ((mant & 0x8000000000000000) == 0)
    {
        --exp;
        mant <<= 1;
    }
    encode_int<big,2>(s, exp);
    encode_uint<big,8>(s+2, mant);
}

いつもの演奏プログラムはこうなります。

audio::aiff_file_source file("doremi.aiff");

audio::pcm_format fmt = file.format();
// pcm_sinkで使用できる形式に変換
if (fmt.type == audio::int8)
    fmt.type = audio::uint8;
else
    fmt.type = audio::int_le16;

io::copy(
    audio::widen<float>(file),
    audio::widen<float>(audio::pcm_sink(fmt))
);

今のところ、pcm_sinkはリトルエンディアンしか扱えないので、AIFF側と別のフォーマットを指定してオープンする必要があります。
また、フォーマットが違うので一旦ワイド文字を経由してコンバートを行う必要があります。
SourceとSinkで扱えるフォーマットが違う場合、適切なフォーマットを判定する手段が欲しいですね。