忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

時間逆転音

逆再生動画ではスリッパのペタペタ音とでも形容すべき奇妙な音が目立ちます。これは普通の再生動画では決して耳にすることのない音です(スリッパをペタペタさせている時を除き!)。いったいどうしてこんな音がするのでしょう?


スリッパのペタペタ音

まずこのペタペタ音というのがどういう音なのかを聞いていただきましょう。これは私が検索したとき一番上に出てきた逆再生動画です:

バックミュージックのせいで逆再生音がよく聞こえないこともありますが、割れた風船を復元しているときなどヒュッとかシュッという音が聞こえます。突然音がぶつ切りになって終わるのです。ここでは便宜上スリッパのペタペタ音と呼ぶことにします。

このペタペタ音というやつは一体どのようにしてできるのでしょうか?

減衰の逆

通常、音は、音叉を叩いたときのように最初が一番大きく、じょじょに小さくなっていきます。(ただ実際は、音叉を叩いた瞬間の波形は90°折れ曲がるのではなくもう少しなめらかなはずです)

ところが時間を逆転させると、かすかな音が次第に大きくなっていきある時いきなり消えるのです。これは非常に「不自然」です。

ともかく、この波形はとてもペタペタ音っぽいです。クライマックスへ向けて次第に高まり、ある時突然あるべき場所へすべてが収まり静かになる感じがよく出ています。

逆転音プログラム

本当にこれがペタペタ音の出るメカニズムなのでしょうか?音を出すプログラムを書いて検証してみましょう。

using System;
using OpenAL = OpenTK.Audio.OpenAL;

class HitSound
{
    public double StartTime = 0;
    public double Frequency = 440;

    public double GetValue(double time)
    {
        if (time < StartTime) { return 0; }

        return Math.Sin(2 * Math.PI * Frequency * time) * Math.Exp(-20 * (time - StartTime));
    }
}

class Program
{
    const int bufferFrequency = 44100;
    const int bufferSeconds = 4;
    const bool reverseTime = true;

    static void Main(string[] args)
    {
        //初期化
        var device = OpenAL.Alc.OpenDevice(null);
        var context = OpenAL.Alc.CreateContext(device, (int[])null);
        OpenAL.Alc.MakeContextCurrent(context);

        //音源を作成
        var source = OpenAL.AL.GenSource();
        int buffer = createBuffer();
        OpenAL.AL.BindBufferToSource(source, buffer);

        //再生
        OpenAL.AL.SourcePlay(source);
        System.Threading.Thread.Sleep(bufferSeconds * 1000 + 1000);

        //使わなくなったデータをクリーンアップ
        OpenAL.AL.DeleteSource(source);
        OpenAL.AL.DeleteBuffer(buffer);
        OpenAL.Alc.MakeContextCurrent(OpenTK.ContextHandle.Zero);
        OpenAL.Alc.DestroyContext(context);
        OpenAL.Alc.CloseDevice(device);
    }
    
    private static int createBuffer()
    {
        var buffer = OpenAL.AL.GenBuffer();
        byte[] bufferData = createBufferData();

        OpenAL.AL.BufferData(
            buffer,
            OpenAL.ALFormat.Mono8,
            bufferData,
            bufferData.Length,
            bufferFrequency
            );
        return buffer;
    }

    private static byte[] createBufferData()
    {
        var bufferData = new byte[bufferFrequency * bufferSeconds];

        var @do = new HitSound();
        @do.StartTime = 0;
        @do.Frequency = 261.63;
        var mi = new HitSound();
        mi.StartTime = 1;
        mi.Frequency = 329.63;
        var so = new HitSound();
        so.StartTime = 2;
        so.Frequency = 392.00;
        var higherDo = new HitSound();
        higherDo.StartTime = 3;
        higherDo.Frequency = 523.23;

        for (var i = 0; i < bufferData.Length; i++)
        {
            var time = (double)i / bufferFrequency;
            var reversedTime = (double)(bufferData.Length - i) / bufferFrequency;
            var soundTime = reverseTime ? reversedTime : time;
            var data = (
                @do.GetValue(soundTime)
                + mi.GetValue(soundTime)
                + so.GetValue(soundTime)
                + higherDo.GetValue(soundTime)
                );
            bufferData[i] = (byte)Math.Floor(
                byte.MaxValue * (data + 1) / 2
                );
        }

        return bufferData;
    }
}

結果

上のプログラムは通常と逆転、2種類の音を出します

通常の音

逆転音

おお!ペタペタ感が出せている気がします!いい感じです!!やはりペタペタ音の正体は増加と突然の停止のようです。

拍手[0回]

PR