Date Tags ADPCM

ADPCMのデコードはほぼできた。次はエンコード。

いろんなソース見とるが、予測時に分岐しまくるのやばくね?とおもってたらそのとおりで、ffmpeg実装は乗算を使ってる:

static inline int16_t adpcm_ima_expand_nibble(ADPCMChannelStatus *c, int8_t nibble, int shift)
{
    int step_index;
    int predictor;
    int sign, delta, diff, step;

    step = ff_adpcm_step_table[c->step_index];
    step_index = c->step_index + ff_adpcm_index_table[(unsigned)nibble];
    step_index = av_clip(step_index, 0, 88);

    sign = nibble & 8;
    delta = nibble & 7;
    /* perform direct multiplication instead of series of jumps proposed by
     * the reference ADPCM implementation since modern CPUs can do the mults
     * quickly enough */
    diff = ((2 * delta + 1) * step) >> shift;
    predictor = c->predictor;
    if (sign) predictor -= diff;
    else predictor += diff;

    c->predictor = av_clip_int16(predictor);
    c->step_index = step_index;

    return (int16_t)c->predictor;
}

static inline uint8_t adpcm_ima_compress_sample(ADPCMChannelStatus *c,
                                                int16_t sample)
{
    int delta  = sample - c->prev_sample;
    int nibble = FFMIN(7, abs(delta) * 4 /
                       ff_adpcm_step_table[c->step_index]) + (delta < 0) * 8;
    c->prev_sample += ((ff_adpcm_step_table[c->step_index] *
                        ff_adpcm_yamaha_difflookup[nibble]) / 8);
    c->prev_sample = av_clip_int16(c->prev_sample);
    c->step_index  = av_clip(c->step_index + ff_adpcm_index_table[nibble], 0, 88);
    return nibble;
}

nibbleってなんだよ・・・って思って調べたら1/2バイト(4bit)のことだった。

デコーダ作って安定させてたら、AudacityとffmpegのADPCM(IMA)のデコード結果が違うことに気付く。 原因は、Audacityを始めとした多くのコーデックでは分岐が多い近似実装になっているからだった。 こいつ が原因か。 一方、ffmpegは近頃のCPUは十分乗算が早いからと言う理由で厳密計算している。ということで自分も厳密計算を選ぶ。

もう一点、AudacityにADPCM(IMA)を突っ込むと末尾が伸びてしまう。これは末尾のブロックも同一サンプル数でデコードしているから…。 あきらかな不具合。PR送るか、送らざるべきか…。

Audacityは内部でlibsndfileを使ってるから、 こっち にPRを送るべき。