最近のトラックバック

スポンサード リンク


  • Google
    Web sketch.txt-nifty.com

リンク

« 『ぼんくら』(宮部みゆき) | トップページ | 『トランスフォーマー』 »

ActionScript日記 - サウンドのリアルタイム生成(2)

 第1回|第2回|第3回第4回第5回

 完全にプログラマ向けのエントリです。

 また物凄く間が空いてしまいましたが、前回の続き。
 まだまだ使い物になるレベルじゃないんですが、一応音楽らしきものが鳴らせるようになったので公開してみたいと思います。5%ルールってとこですか。

  トルコ行進曲(2小節)

 一応プログラム中でメロディを記述することは出来るんですが、このままじゃアレなんで、次はMMLに対応してみたいと思います。
 プチノイズも何とかしたいし、対応してない機能もどうにかしたいですねぇ。

 ソースは続きをどうぞ。
 ソースの貼り付けにはas2htmlを利用させていただきました。

PlayMML.as
package {
    import flash.display.Sprite;
    import nu.mine.flashnet.sound.core.*;
    import flash.events.Event;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    
    public class PlayMML extends Sprite {
        private var engine:PlaybackEngine;
        private var tracks:Array;
        
        public function PlayMML() {
            var playbackBufferSize:int = 2048;
            var dataProvider:MMixer = new MMixer(); //create a data source
            tracks = new Array();
            tracks[0] = new MTrack(dataProvider.getFmt(), playbackBufferSize);
            tracks[0].addNote(74, 48);
            tracks[0].addNote(76, 48);
            tracks[0].addNote(78, 96);
            tracks[0].addNote(74, 48);
            tracks[0].addNote(76, 48);
            tracks[0].addNote(78, 48);
            tracks[0].addNote(76, 48);
            tracks[0].addNote(74, 48);
            tracks[0].addNote(73, 48);
            tracks[0].addNote(71, 48);
            tracks[0].addNote(73, 48);
            tracks[0].addNote(74, 48);
            tracks[0].addNote(76, 48);
            tracks[0].addNote(73, 48);
            tracks[0].addNote(69, 48);
            dataProvider.connect(tracks[0]);
            tracks[1] = new MTrack(dataProvider.getFmt(), playbackBufferSize);
            tracks[1].addRest(96);
            tracks[1].addNote(62, 192);
            tracks[1].addNote(62, 192);
            tracks[1].addNote(55, 192);
            tracks[1].addNote(61, 192);
            dataProvider.connect(tracks[1]);
            engine = new PlaybackEngine(dataProvider, playbackBufferSize); //hand the data source to the playback engine, and the buffersize for the engine
            engine.addEventListener(PlaybackEngine.READY, engineReady, false, 0, true); //listen for when the engine is ready

        }

        private function engineReady(event:Event):void {
            engine.start(); //commence playback
        }
    }
}


MMixer.as
package {
    import nu.mine.flashnet.sound.core.*;

    public class MMixer extends AudioDataProvider {
        private var phase:Number;
        private var phaseFactor:Number;
        private var trackArr:Array;
        private var fmt:PCMSoundFormat;

        public function MMixer() {
            fmt  = new PCMSoundFormat(44100, 16, 1);
            super(fmt);
            phase = 0.0;
            phaseFactor = 1000;
            trackArr = new Array();
        }

        public function getFmt():PCMSoundFormat {
            return fmt;
        }

        public function connect(track:MTrack):void {
            trackArr.push(track);
        }

        protected override function fillBuffer(numSamples:int):void {
            for(var i:int = 0;i < numSamples; ++i) {
                var s:Number = 0;
                for each (var track:MTrack in trackArr) {
                        s += track.getNextSample();
                }
                buffer.writeMonoSample(s);
            }
        }
    }
}


MTrack.as
package {
    import nu.mine.flashnet.sound.core.*;

    public class MTrack {
        private var m_ch:MChannel;            // channel (instrument)
        private var m_fmt:PCMSoundFormat;     // 
        private var m_playbackBufferSize:int//
        private var m_needle:int;             // global time
        private var m_bpm:Number;             // beat per minute
        private var m_vol:int;                // default volume    (max:127)
        private var m_vel:int;                // default velocity  (max:127)
        private var m_len:int;                // default length
        private var m_gate:Number;            // default gate time (max:1.0)
        private var m_events:Array;           //
        private var m_spt:Number;             // samples per tick
        private var m_pointer:int;            // current event no.
        private var m_delta:int;
        
        public function MTrack(fmt:PCMSoundFormat, playbackBufferSize:int) {
            m_ch                 = new MChannel(fmt);
            m_fmt                = fmt;
            m_playbackBufferSize = playbackBufferSize;
            m_needle             = -4096; // initialize time
            m_bpm                = 120;
            m_vol                = 100;
            m_vel                = 100;
            m_len                = 96;   // quater note
            m_gate               = 0.8;
            m_events             = new Array();
            var tps:Number = m_bpm * 96 / 60; // ticks per second (quater note = 96ticks)
            m_spt = 44100 / tps;     // samples per tick
            m_pointer = 0;
            m_delta = 0;
        }

        public function getNextSample():Number {
            if (m_pointer < m_events.length) {
                var e:MEvent = m_events[m_pointer];
                var delta:Number = m_events[m_pointer].getDelta() * m_spt;
                if (m_needle >= delta) {
                    switch(e.getStatus()) {
                    case MStatus.NOTE_ON:
                        m_ch.noteOn(MEvent.getFrequency(e.getNoteNo()));
                        break;
                    case MStatus.NOTE_OFF:
                        m_ch.noteOff();
                        break;
                    case MStatus.EOT:
                        m_ch.noteOff();
                        break;
                    default:
                        break;
                    }
                    trace(m_pointer+": "+e.getStatus()+": "+e.getNoteNo()+": "+m_needle+", "+delta);
                    m_needle = 0;
                    m_pointer++;
                }
            }
            m_needle += 1.0;
            return m_ch.getNextSample();
        }

        public function seek(delta:int):void {
            m_delta = delta;
        }

        public function addNote(noteNo:int, len:int = -1, vel:int = -1):void {
            if (len < 0) len = m_len;
            if (vel < 0) vel = m_vel;
            var e0:MEvent = new MEvent();
            e0.setNoteOn(noteNo, vel);
            e0.setDelta(m_delta);
            m_events.push(e0);
            var e1:MEvent = new MEvent();
            var gate:int = len * m_gate;
            seek(gate);
            e1.setNoteOff(noteNo, vel);
            e1.setDelta(m_delta);
            m_events.push(e1);
            seek(len - gate);
        }

        public function addRest(len:int = -1):void {
            if (len < 0) len = m_len;
            seek(len);
        }

        public function setVolume(vol:int):void {
            var e:MEvent = new MEvent();
            e.setVolume(vol);
            m_events.push(e);
        }

        public function setTempo(tempo:Number):void {
            var e:MEvent = new MEvent();
            e.setTempo(tempo);
            m_events.push(e);
        }
}
}


MChannel.as
package {
    import nu.mine.flashnet.sound.core.*;
    import nu.mine.flashnet.sound.synthesis.*;
    import nu.mine.flashnet.sound.synthesis.tones.*;

    public class MChannel {
        private var envelope:ADSREnvelope;
        private var tone:ToneGenerator;
        private var vel:Number;

        public function MChannel(soundFormat:PCMSoundFormat, type:String = "sine") {
            envelope = new ADSREnvelope(0, 0.4, 0.2, 0, soundFormat);
            tone = new SineToneGenerator(soundFormat, 440.0);
            vel = 0.5;
        }
        public function setVel(v:Number):void {
            vel = v;
        }
        public function noteOn(frequency:Number):void {
            tone.setPitch(frequency);
            envelope.triggerEnvelope();
        }
        public function noteOff():void {
            envelope.releaseEnvelope();
        }
        public function getNextSample():Number {
            return tone.getNextSample() * envelope.getNextAmplitude() * vel;
        }
    }
}


MEvent.as
package {
    public class MEvent {
        private var m_delta:int;
        private var m_status:int;
        private var m_data0:int;
        private var m_data1:int;
        
        public function MEvent() {
            set(MStatus.NOP, 0, 0);
        }
        public function set(status:int, data0:int, data1:int):void {
            m_status = status;
            m_data0  = data0;
            m_data1  = data1;
        }
        public function setEOT():void                         { set(MStatus.EOT, 0, 0); }
        public function setNoteOn(noteNo:int, vel:int):void   { set(MStatus.NOTE_ON, noteNo, vel); }
        public function setNoteOff(noteNo:int, vel:int):void  { set(MStatus.NOTE_OFF, noteNo, vel); }
        public function setTempo(tempo:int):void              { set(MStatus.TEMPO, tempo, 0); }
        public function setVolume(vol:int):void               { set(MStatus.VOLUME, vol, 0); }
        public function setDelta(delta:int):void              { m_delta = delta; }
        public function getStatus():int     { return m_status; }
        public function getDelta():int      { return m_delta; }
        public function getNoteNo():int     { return m_data0; }
        public function getVelocity():int   { return m_data1; }
        public function getTempo():int      { return m_data0; }
        public function getVolume():int     { return m_data0; }

        public static function getFrequency(noteNo:int):Number {
            return frequencyMap[noteNo];
        }
        
        private static const frequencyMap:Array = new Array(
            // octave -2
            8.18,    // C    0
            8.66,    // C#    1
            9.18,    // D    2
            9.73,    // D#    3
            10.30,    // E    4
            10.92,    // F    5
            11.56,    // F#    6
            12.25,    // G    7
            12.98,    // G#    8
            13.75,    // A    9
            14.57,    // A#    10
            15.44,    // B    11
            // octave -1
            16.35,    // C    12
            17.32,    // C#    13
            18.35,    // D    14
            19.45,    // D#    15
            20.60,    // E    16
            21.83,    // F    17
            23.12,    // F#    18
            24.50,    // G    19
            25.96,    // G#    20
            27.50,    // A    21
            29.14,    // A#    22
            30.87,    // B    23
            // octave 0
            32.70,    // C    24
            34.65,    // C#    25
            36.71,    // D    26
            38.89,    // D#    27
            41.20,    // E    28
            43.65,    // F    29
            46.25,    // F#    30
            49.00,    // G    31
            51.91,    // G#    32
            55.00,    // A    33
            58.27,    // A#    34
            61.74,    // B    35
            // octave 1
            65.41,    // C    36
            69.30,    // C#    37
            73.42,    // D    38
            77.78,    // D#    39
            82.41,    // E    40
            87.41,    // F    41
            92.50,    // F#    42
            98.00,    // G    43
            103.83,    // G#    44
            110.00,    // A    45
            116.54,    // A#    46
            123.47,    // B    47
            // octave 2
            130.81,    // C    48
            138.59,    // C#    49
            146.83,    // D    50
            155.56,    // D#    51
            164.81,    // E    52
            174.61,    // F    53
            185.00,    // F#    54
            196.00,    // G    55
            207.65,    // G#    56
            220.00,    // A    57
            233.08,    // A#    58
            246.94,    // B    59
            // octave 3
            261.63,    // C    60
            277.18,    // C#    61
            293.66,    // D    62
            311.13,    // D#    63
            329.63,    // E    64
            349.23,    // F    65
            369.99,    // F#    66
            392.00,    // G    67
            415.30,    // G#    68
            440.00,    // A    69
            466.16,    // A#    70
            493.88,    // B    71
            // octave 4
            523.25,    // C    72
            554.37,    // C#    73
            587.33,    // D    74
            622.25,    // D#    75
            659.26,    // E    76
            698.46,    // F    77
            739.99,    // F#    78
            783.99,    // G    79
            830.61,    // G#    80
            880.00,    // A    81
            932.33,    // A#    82
            987.77,    // B    83
            // octave 5
            1046.50,    // C    84
            1108.73,    // C#    85
            1174.66,    // D    86
            1244.51,    // D#    87
            1318.51,    // E    88
            1396.91,    // F    89
            1479.98,    // F#    90
            1567.98,    // G    91
            1661.22,    // G#    92
            1760.00,    // A    93
            1864.66,    // A#    94
            1975.53,    // B    95
            // octave 6
            2093.00,    // C    96
            2217.46,    // C#
            2349.32,    // D
            2489.02,    // D#
            2637.02,    // E
            2793.83,    // F
            2959.96,    // F#
            3135.96,    // G
            3322.44,    // G#
            3520.00,    // A
            3729.31,    // A#
            3951.07,    // B
            // octave 7
            4186.01,    // C    108
            4434.92,    // C#    109
            4698.64,    // D    110
            4678.03,    // D#    111
            5274.04,    // E    112
            5587.65,    // F    113
            5919.91,    // F#    114
            6271.93,    // G    115
            6644.88,    // G#    116
            7040.00,    // A    117
            7458.62,    // A#    118
            7902.13,    // B    119
            // octave 8
            8372.02,    // C    120
            8869.84,    // C#    121
            9397.27,    // D    122
            9956.06,    // D#    123
            10548.08,    // E    124
            11175.30,    // F    125
            11839.82,    // F#    126
            12543.85,    // G    127
            13289.75,    // G#    128
            14080.00,    // A    129
            14917.24,    // A#    130
            15804.27    // B    131
                                                                  );
    }
}


MStatus.as
package {
    public final class MStatus {
        public static const EOT:int      = 0;
        public static const NOP:int      = 1;
        public static const NOTE_ON:int  = 2;
        public static const NOTE_OFF:int = 3;
        public static const TEMPO:int    = 4;
        public static const VOLUME:int   = 5;
    }
}

« 『ぼんくら』(宮部みゆき) | トップページ | 『トランスフォーマー』 »

ActionScript 3.0」カテゴリの記事

FlMML」カテゴリの記事

コメント

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: ActionScript日記 - サウンドのリアルタイム生成(2):

« 『ぼんくら』(宮部みゆき) | トップページ | 『トランスフォーマー』 »

ブログパーツ



2021年7月
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
無料ブログはココログ