Статьи

Рендеринг аудио-спектра MP3 во Flash с помощью computeSpectrum ()

В этом уроке я научу вас создавать визуальное представление звукового спектра звукового файла с помощью метода Flash SoundMixer.computeSpectrum . Для этого эффекта мы будем использовать четыре класса: Sound , SoundChannel , SoundMixer и ByteArray . Я объясню каждый класс, как мы их используем.


Давайте посмотрим на конечный результат, к которому мы будем стремиться:


Нажмите, чтобы посмотреть демо

Запустите Flash Pro и создайте новый документ Flash. Установите размер сцены 500x300px, цвет фона # 000000 и частоту кадров 24 кадра в секунду.

Этап настройки

В вашей временной шкале выберите существующий слой и переименуйте его в «Кнопки». Затем нажмите « Окно»> «Общие библиотеки»> «Кнопки» .

Выберите ваш любимый набор кнопок, затем перетащите кнопки «Play» и «Stop» в правый нижний угол сцены.

Библиотека-кнопка

Установите имена экземпляров этих кнопок равными play_btn и stop_btn соответственно.

Создайте новый файл AS и сохраните его как Main.as. Добавьте этот код (читайте комментарии для более подробной информации):

Этот код должен быть помещен в наш новый класс:

01
02
03
04
05
06
07
08
09
10
11
12
13
package {
    import flash.display.Sprite;
    import flash.media.Sound;
    import flash.net.URLRequest;
     
    public class Main extends Sprite {
        private var sound:Sound;
        public function Main() {
            sound = new Sound(new URLRequest(«sound.mp3»));
            sound.play();
        }
    }
}

Вам нужно будет поместить файл MP3 с именем sound.mp3 в тот же каталог, что и выходной каталог вашего FLA. Подойдет любой MP3; включен в исходную загрузку учебника.


Добавьте имя класса в поле «Класс» в разделе «Публикация» на панели «Свойства», чтобы связать FLA с классом основного документа.

Если вы не знакомы с концепцией класса документа, ознакомьтесь с этим кратким советом, прежде чем читать дальше.

Раздел публикации

Затем нажмите Ctrl + Enter, чтобы протестировать ваше приложение.


Давайте добавим экземпляр нового класса: SoundChannel . Этот класс используется для хранения разных звуков в отдельных аудиоканалах; каждый канал создается экземпляром SoundChannel , и мы используем эти экземпляры для управления звуками.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package {
    import flash.display.Sprite;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.net.URLRequest;
    import flash.events.MouseEvent;
    public class Main extends Sprite {
        private var sound:Sound;
        private var channel:SoundChannel;
         
        public function Main() {
            sound = new Sound(new URLRequest(«sound.mp3»));
            play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
            stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
        }
         
        private function onPlayHandler(event:MouseEvent):void{
            channel = sound.play();
        }
         
        private function onStopHandler(event:MouseEvent):void{
            channel.stop();
        }
    }
}

Как видите, при нажатии кнопки «Воспроизведение» мы не просто воспроизводим MP3, мы также назначаем его для SoundChannel. Затем мы можем управлять воспроизведением через этот экземпляр SoundChannel позже — в этом случае, остановив его.


Теперь давайте создадим простую анимацию для этого звука, снова используя класс SoundChannel.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package {
    import flash.display.Sprite;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.net.URLRequest;
    import flash.events.MouseEvent;
    import flash.events.Event;
     
    public class Main extends Sprite {
         
        private var sound:Sound;
        private var channel:SoundChannel;
         
        public function Main() {
            sound = new Sound(new URLRequest(«sound.mp3»));
            play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
            stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
        }
         
        private function onPlayHandler(event:MouseEvent):void{
            channel = sound.play();//assign sound to channel class
            addEventListener(Event.ENTER_FRAME,animateBars);
        }
         
        private function onStopHandler(event:MouseEvent):void{
            channel.stop();
            graphics.clear();
            removeEventListener(Event.ENTER_FRAME,animateBars);//stop rendering the animation
        }
         
        private function animateBars(event:Event):void{
             
            graphics.clear();
             
            graphics.beginFill(0xAB300C,1);
            //Draw a rectangle whose height corresponds to channel.leftPeak
            graphics.drawRect(190,300,50,-channel.leftPeak * 160 );
            graphics.endFill();
             
            graphics.beginFill(0xAB300C,1);
            //Draw a rectangle whose height corresponds to channel.rightPeak
            graphics.drawRect(250,300,50,-channel.rightPeak * 160 );
            graphics.endFill();
        }
    }
}

leftPeak и rightPeak экземпляра SoundChannel соответствуют текущей амплитуде звука через левый и правый каналы. Подумайте об этом так: если у вас есть стереодинамики, то leftPeak — это громкость звука, выходящего из левого динамика, а rightPeak — это громкость звука, выходящего из правого динамика.

Вы можете нажать Ctrl + Enter, чтобы протестировать ваше приложение:

Звуковая панель Анимация

Класс SoundMixer контролирует все встроенные и потоковые звуки в приложении для всех SoundChannels одновременно.

Он имеет три метода: areSoundsInaccessible() , который определяет, являются ли какие-либо звуки недоступными по соображениям безопасности; stopAll() , который останавливает воспроизведение всех звуков; и computeSpectrum() , который нас интересует в этом уроке. Последний метод берет «снимок» текущего звука и помещает его в объект ByteArray.


Класс ByteArray предоставляет методы и свойства для оптимизации чтения, записи и работы с двоичными данными. Он хранит данные в виде массива байтов, отсюда и его имя. Узнайте больше с этим введением в ByteArray .


Итак, теперь давайте создадим более сложную анимацию, используя метод SoundMixer.computeSpectrum() . Снова, прочитайте комментарии в коде, чтобы полностью понять поведение:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package {
    import flash.display.Sprite;
    import flash.media.Sound;
    import flash.utils.ByteArray;
    import flash.events.Event;
    import flash.media.SoundMixer;
    import flash.filters.GlowFilter;
    import flash.net.URLRequest;
    import flash.events.MouseEvent;
    import flash.media.SoundChannel;
 
    public class Main extends Sprite{
        private var sound:Sound;
        private var channel:SoundChannel;
        private var byteArr:ByteArray = new ByteArray();
        private var glow:GlowFilter = new GlowFilter();
        private var filterArr:Array;
        private var line:Sprite = new Sprite();
 
        public function Main(){
            // create a «glow» effect for the animation we will render
            glow.color = 0x009900;
            glow.alpha = 1;
            glow.blurX = 10;
            glow.blurY = 10;
             
            // load your MP3 in to the Sound object
            sound = new Sound(new URLRequest(«sound.mp3»));
            // apply the glow effect
            filterArr = new Array(glow);
            line.filters = filterArr;
            addChild(line);
             
            play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
            stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
        }
         
        private function onPlayHandler(event:MouseEvent):void{
            channel = sound.play(0,1000);
            addEventListener(Event.ENTER_FRAME,spectrumHandler);
        }
         
        private function onStopHandler(event:MouseEvent):void{
            channel.stop();
            line.graphics.clear();
            removeEventListener(Event.ENTER_FRAME,spectrumHandler);
        }
 
        private function spectrumHandler(event:Event):void{
            line.graphics.clear();
            line.graphics.lineStyle(1,Math.random() * 0xFFFFFF);
            line.graphics.moveTo(-1,150);
            // push the spectrum’s bytes into the ByteArray
            SoundMixer.computeSpectrum(byteArr);
 
            for (var i:uint=0; i<256; i++){
                // read bytes and translate to a number between 0 and +300
                var num:Number = byteArr.readFloat() * 150 + 150;
                //use this number to draw a line
                line.graphics.lineTo(i*2,num);
            }
        }
    }
}

Наиболее важными частями этого кода являются строки 53 и 57. Здесь вся звуковая волна преобразуется в ByteArray, который затем читается, побайтно, и транслируется в набор чисел.

ByteArray будет длиной 512 операций с плавающей запятой; в цикле for мы читаем только первые 256 значений с плавающей точкой, которые соответствуют всей звуковой волне левого канала (звук, проходящий через левый динамик)

Нажмите Ctrl + Enter, чтобы протестировать ваше приложение.

Анимация звуковой линии

Мы можем заполнить область под линией, чтобы получить другой эффект:

Комплексная анимация рисования

Все, что нам нужно сделать, это нарисовать прямоугольник и заполнить его, используя graphics методы. Код для этого выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package {
    import flash.display.Sprite;
    import flash.media.Sound;
    import flash.utils.ByteArray;
    import flash.events.Event;
    import flash.media.SoundMixer;
    import flash.filters.GlowFilter;
    import flash.net.URLRequest;
    import flash.events.MouseEvent;
    import flash.media.SoundChannel;
 
    public class Main extends Sprite{
        private var sound:Sound;
        private var channel:SoundChannel;
        private var byteArr:ByteArray = new ByteArray();
        private var glow:GlowFilter = new GlowFilter();
        private var filterArr:Array;
        private var line:Sprite = new Sprite();
 
        public function Main(){
            glow.color = 0xFF0000;
            glow.alpha = 1;
            glow.blurX = 10;
            glow.blurY = 10;
             
            sound = new Sound(new URLRequest(«sound.mp3»));
             
            filterArr = new Array(glow);
            line.filters = filterArr;
            addChild(line);
            addChild(play_btn);
            addChild(stop_btn);
             
            play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
            stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
        }
         
        private function onPlayHandler(event:MouseEvent):void{
            channel = sound.play(0,1000);
            addEventListener(Event.ENTER_FRAME,spectrumHandler);
        }
         
        private function onStopHandler(event:MouseEvent):void{
            channel.stop();
            line.graphics.clear();
            removeEventListener(Event.ENTER_FRAME,spectrumHandler);
        }
 
        private function spectrumHandler(event:Event):void{
            // draw one edge of the box, and specify a fill
            line.graphics.clear();
            line.graphics.beginFill(0xFF0000,1);
            line.graphics.lineStyle(1,0xFF0000);
            line.graphics.moveTo(-1,150);
            SoundMixer.computeSpectrum(byteArr);
 
            for (var i:uint=0; i<256; i++){
                var num:Number = byteArr.readFloat() * 200 + 150;
                line.graphics.lineTo(i*2,num);
            }
 
            //draw the rest of the box
            line.graphics.lineTo(512,300);
            line.graphics.lineTo(0,300);
            line.graphics.lineTo(-1,150);
        }
    }
}

Мы можем развить эту идею, добавив еще более интересные и сложные эффекты:

Комплексная анимация рисования

В этом случае мы нарисуем два спектра друг над другом, один для левого канала и один для правого. Чтобы достичь этого, мы будем использовать два цикла for , каждый из которых читает 256 операций с плавающей запятой, один за другим.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package {
    import flash.display.Sprite;
    import flash.media.Sound;
    import flash.utils.ByteArray;
    import flash.events.Event;
    import flash.media.SoundMixer;
    import flash.filters.GlowFilter;
    import flash.net.URLRequest;
    import flash.events.MouseEvent;
    import flash.media.SoundChannel;
 
    public class Main extends Sprite{
        private var sound:Sound;
        private var channel:SoundChannel;
        private var byteArr:ByteArray = new ByteArray();
        private var glow:GlowFilter = new GlowFilter();
        private var filterArr:Array;
        private var line:Sprite = new Sprite();
        private var num:Number;
        public const GRAFT_HEIGHT:int = 150;
        public const CHANNEL_SIZE:int = 256;
 
        public function Main(){
            glow.color = 0x009900;
            glow.alpha = 1;
            glow.blurX = 10;
            glow.blurY = 10;
             
            sound = new Sound(new URLRequest(«sound.mp3»));
             
            filterArr = new Array(glow);
            line.filters = filterArr;
            addChild(line);
             
            play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
            stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
        }
         
        private function onPlayHandler(event:MouseEvent):void{
            channel = sound.play(0,1000);
            addEventListener(Event.ENTER_FRAME,spectrumHandler);
        }
         
        private function onStopHandler(event:MouseEvent):void{
            channel.stop();
            line.graphics.clear();
            removeEventListener(Event.ENTER_FRAME,spectrumHandler);
        }
 
        private function spectrumHandler(event:Event):void{
            num = 0;
             
            line.graphics.clear();
            line.graphics.lineStyle(0, 0x00FF00);
            line.graphics.beginFill(0x00FF00,0.5);
            line.graphics.moveTo(0,GRAFT_HEIGHT);
             
            SoundMixer.computeSpectrum(byteArr);// add bytes to Sound mixer
             
            for (var i:int = 0; i < CHANNEL_SIZE; i++) {
                        num = (byteArr.readFloat() * GRAFT_HEIGHT);
                        line.graphics.lineTo(i * 2, GRAFT_HEIGHT — num);
                    }
             
            line.graphics.lineTo(CHANNEL_SIZE * 2, GRAFT_HEIGHT);
            line.graphics.endFill();
              
            line.graphics.lineStyle(0, 0xFF0000);
            line.graphics.beginFill(0xFF0000, 0.5);
            line.graphics.moveTo(CHANNEL_SIZE * 2,GRAFT_HEIGHT);
              
            for (i = CHANNEL_SIZE; i > 0; i—) {
                num = (byteArr.readFloat() * GRAFT_HEIGHT);
                line.graphics.lineTo(i * 2, GRAFT_HEIGHT — num);
            }
             
            line.graphics.lineTo(0, GRAFT_HEIGHT);
            line.graphics.endFill();
        }
    }
}

Итак, мы узнали, как использовать различные классы Sound и как создавать красивые анимации рисования звука с помощью SoundMixer .

Спасибо, что нашли время, чтобы прочитать эту статью, потому что это мой первый урок. Если у вас есть какие-либо вопросы, пожалуйста, оставьте их в комментарии.