Предложения по преодолению проблемы производительности вспышки - PullRequest
1 голос
/ 13 июля 2010

Мой вопрос является своего рода продолжением этого вопроса ниже, но я подумал, что было бы лучше начать новый вопрос.

, помогите преобразовать этот код as3 в код пиксель-бендера

Итак, у меня есть реализация рисования формы волны во флэш-памяти, которая извлекает данные pcm из mp3 и рисует форму волны с несколькими уровнями масштабирования.Он работает хорошо, пока вы не начнете работать с треками дольше, чем пару минут, а затем просто слишком медленно.Так что я выбрал более быстрое решение.

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

Так что теперь я думаю, что в качестве альтернативы был бы лучший кошелек для авеню.

Позволит ли написание моего кода для расчета формы сигнала на языке c и использование алхимии ощутимое улучшение скорости и производительности?По сути, он все еще работает как as3?

Будет ли лучше использовать какой-нибудь серверный скрипт?Может быть, передача данных PCM в качестве байтового массива в сценарий php и получение сценария для возврата данных печати?

Можете ли вы вспомнить какие-либо другие методы, которые я мог бы попытаться изучить?

РЕДАКТИРОВАТЬ: >>

В as3 я пытаюсь сделать следующее:

Извлечь аудиоданные в формате MP3 в байтовый массив. Определить виртуальное количество пикселей для построения при максимальном увеличении.уровень (например, 800 пикселей = 10 секунд дорожки при 2-кратном увеличении)

Так что, если мое число выборок = 33315840, а максимальное количество виртуальных пикселей = 1600 (требуется прокрутка, поскольку область просмотра составляет 800 пикселей в ширину)тогда размер моего куска = 33315840/1600 = 20822

Таким образом, для каждых 20822 выборок в байтовом массиве я нахожу максимальное значение и использую это значение в качестве значения для моего графика

РЕДАКТИРОВАТЬ 2

@ backtodos

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

Я сделал следующий кодкоторый я думаю represо чем вы говорили.Одна проблема заключается в том, что если я изменяю свое разрешение на значение, превышающее 800, я получаю очень высокую линию и очень короткие линии, которые выглядят очень странно.На 800 это очень хороший сигнал!

Если мое разрешение превышает 1600, я получаю ошибки, когда пытаюсь нарисовать прямоугольник, говоря, что параметр недействителен.

Я думаю, что я немногозапутался в вашей стратегии масштабирования.Вы говорите: «Если вы увеличиваете масштаб, вы перерисовываете форму волны с двойным разрешением».Я действительно не понимаю, что вы имеете в виду, что это?Я знаю, что буду рисовать только 800 пикселей за раз.Допустим, я делаю 2-кратное увеличение, будет ли это означать, что я удваиваю количество операций чтения по источнику выборки и получаю 1600 точек построения, но рисую только 800 из них за раз, основываясь на позиции прокрутки?

        private function calculatePlottingData():void
        {

            this._container=new UIComponent()
            drawon=new MovieClip()
            _container.addChild(drawon)
            addChild(_container)

            var spriteSize:Number;
            spriteSize=800; // my resolution

            //ba is a bytearray filled with my extracted audio data
            //blocksize helps me determine where in the bytearray 
            //to read a sample value from for plotting
            blocksize=Math.floor(ba.length / spriteSize);

            var tstart:Number=getTimer()
            var l:Number
            var r:Number
            var la:Number
            var ra:Number
            var readpoint:int=0;
            var val:Number;

            for (var i:int=0; i < spriteSize; i++)
            {
                readpoint=i * blocksize


                ba.position=readpoint;

                //read teh left and right sample
                la=ba.readFloat();
                ra=ba.readFloat();

                val=(la + ra) / 2;

                plottingvalues[i]=val

                drawon.graphics.beginFill(0xff0000)

            }
            var tend:Number=getTimer() - tstart;
            trace("time taken=" + tend / 1000)

            draw()
        }

        private function draw():void
        {
            var val:Number
            for (var i:int=0; i < _viewportwidth; i++)
            {
                drawon.graphics.beginFill(0xffffff)
                val=plottingvalues[i];
                drawon.graphics.drawRect(i, 50, 1, val * 50)
            }
        }

РЕДАКТИРОВАТЬ 3> Усовершенствованный код, основанный на получении только когда-либо получающих 800 точек печати, этот код выглядит достаточно быстрым для моих целей.Это экономит большую часть обработки благодаря предложению @ backtodos придерживаться разрешения.

    package drawing
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;
    import flash.media.Sound;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;

    import mx.core.Application;

    public class WaveformView extends MovieClip
    {
        private var _sound:Sound
        private var _resolution:Number
        private var _quality:int=1;
        private var _buffersize:int;
        private var _ba:ByteArray=new ByteArray()
        private var _step:Number
        private var _zoomby:int=1;
        private var _zoomfactor:int=2;
        private var _blocksize:int;
        private var _scrollbar:Bitmap
        private var _scrollthumb:MovieClip


        private var _relativeThumbPosition:Number=0
        private var _sliderRange:int
        private var _sliderCenterMinLeft:int
        private var _sliderCenterMax_Right:int;
        public var _slider_rel_pos:Number=0;
        private var _sliderCenter:Number=0;

        public function WaveformView(snd:Sound, res:Number=800, quality:int=2, buffersize:int=2048)
        {
            super();
            this._sound=snd;
            this._resolution=res;
            this._quality=quality; // not implemented yet
            this._buffersize=buffersize;
            initScrollBar();
            getPCM()
            drawwaveform()

        }

        private function initScrollBar():void
        {
            var sbbmd:BitmapData=new BitmapData(_resolution, 20, false, 0xcccccc)
            _scrollbar=new Bitmap(sbbmd)
            _scrollbar.y=120
            addChild(_scrollbar)

            sbbmd=new BitmapData(_resolution, 16, false, 0xeeeeee)
            _scrollthumb=new MovieClip()
            _scrollthumb.graphics.beginFill(0xff0000)
            _scrollthumb.graphics.drawRect(0, 0, _resolution, 10)
            _scrollthumb.graphics.endFill()
            _scrollthumb.y=125
            addChild(_scrollthumb)
            _scrollthumb.buttonMode=true
            _scrollthumb.addEventListener(MouseEvent.MOUSE_DOWN, beginthumbdrag)

        }

        private function beginthumbdrag(e:MouseEvent):void
        {
            _scrollthumb.startDrag(false, new Rectangle(_scrollbar.x, _scrollbar.y + 5, _scrollbar.width - (_scrollthumb.width), 0))
            _scrollthumb.addEventListener(MouseEvent.MOUSE_MOVE, shuttleMoving, false, 0, true);
            _scrollthumb.addEventListener(MouseEvent.MOUSE_UP, endthumbdrag, false, 0, true);
        }

        private function endthumbdrag(e:MouseEvent):void
        {
            _scrollthumb.stopDrag();
            e.updateAfterEvent();
            _scrollthumb.removeEventListener(MouseEvent.MOUSE_MOVE, shuttleMoving);
        }

        private function shuttleMoving(e:MouseEvent):void
        {
            calculateShuttleRelativePosition();
            drawwaveform()
            e.updateAfterEvent()
        }

        private function calculateShuttleRelativePosition():void
        {

            var _x:Number=_scrollthumb.x
            _sliderCenter=_x + (_scrollthumb.width / 2)
            _sliderRange=_scrollbar.width - _scrollthumb.width;
            _slider_rel_pos=(_sliderCenter - _sliderCenterMinLeft) / _sliderRange

        }

        public function getPCM():void
        {
            var len:int=_sound.length * 44.1
            _sound.extract(_ba, len)
            this._blocksize=_ba.length / (_resolution * _zoomby)
            shaveblocksize()
        }

        public function zoomin():void
        {
            if (this._zoomby < 16)
            {
                this._zoomby*=2
                resizeThumb()
                drawwaveform()
            }
        }

        public function zoomout():void
        {
            if (_zoomby >= 2)
            {
                this._zoomby/=2
                resizeThumb()

                drawwaveform()
            }
        }

        private function resizeThumb():void
        {
            _scrollthumb.width=_scrollbar.width / _zoomby
            if (_scrollthumb.width == _resolution)
            {
                _slider_rel_pos=0
            }
            _sliderCenterMinLeft=_scrollthumb.width / 2;
            _sliderCenterMax_Right=_scrollbar.width - (_scrollthumb.width / 2);
            _sliderRange=_scrollbar.width - _scrollthumb.width;
            _sliderRange=_scrollbar.width - _scrollthumb.width;
            _scrollthumb.x=(_slider_rel_pos * _sliderRange)
        }


        public function drawwaveform():void
        {
            var starttime:Number=getTimer()

            var readposition:int
            var l:Number
            var r:Number
            var p:Number

            this._blocksize=_ba.length / (_resolution * _zoomby)
            shaveblocksize()
            this.graphics.clear()

            this.graphics.beginFill(0xc5c5c5, 0.5)
            this.graphics.drawRect(0, 50, _resolution, 1)

            var max:int=_ba.length - (_blocksize * _resolution)
            var pos:int=Formulas.interpolate(_slider_rel_pos, 0, max)
            _ba.position=pos
            for (var i:int=0; i < _resolution; i++)
            {
                l=Math.abs(_ba.readFloat());
                r=Math.abs(_ba.readFloat());

                l*=50
                r*=50
                p=(l + r)/2

                try
                {
                    this.graphics.drawRect(i, 50, 1, p)
                    this.graphics.drawRect(i, 50, 1, -p)

                }
                catch (e:Error)
                {


                }
                _ba.position+=_blocksize
            }


        }

        private function shaveblocksize():void
        {
            do
            {
                _blocksize--
            } while (_blocksize % 4);
        }

    }
}

Решение Спасибо backtodos за его помощь.Это может быть чертовски много оптимизации, но это хорошая отправная точка для кого-то.

package drawing
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;
    import flash.media.Sound;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;

    public class WaveformView extends MovieClip
    {
        private var _sound:Sound
        private var _resolution:Number
        private var _quality:int=1;
        private var _buffersize:int;
        private var _ba:ByteArray=new ByteArray()
        private var _zoomby:int=1;
        private var _zoomXFactor:int=2;
        private var _maximumSecondsPerViewPort:int=10;
        ;
        private var _blocksize:int;
        private var _scrollbar:Bitmap
        private var _scrollthumb:MovieClip


        private var _relativeThumbPosition:Number=0
        private var _sliderRange:int
        private var _sliderCenterMinLeft:int
        private var _sliderCenterMax_Right:int;
        public var _slider_rel_pos:Number=0;
        private var _sliderCenter:Number=0;
        private var _resolutions:Array

        private var _zoomsInSecondsArray:Array=new Array();
        private var _numberOfZoomLevels:int;

        public function WaveformView(snd:Sound, res:Number=800, quality:int=2, buffersize:int=2048, height:int=100)
        {
            super();
            this._sound=snd;
            this._resolution=res;
            this._quality=quality; // not implemented yet
            this._buffersize=buffersize;

            //  addChild(viewportBitmap)
            _resolutions=new Array()

            initScrollBar();
            getPCM()
            calculateZoomLevelData()
            drawwaveform()

        }

        public function calculateZoomLevelData():void
        {
            _zoomsInSecondsArray=[]
            var amt:int=Math.round(_sound.length / 1000);
            _zoomsInSecondsArray.push(amt);

            while (amt >= _maximumSecondsPerViewPort)
            {
                amt=amt / _zoomXFactor;
                if (amt >= _maximumSecondsPerViewPort)
                {
                    _zoomsInSecondsArray.push(amt);
                }
            }

            _numberOfZoomLevels=_zoomsInSecondsArray.length;


            var checkSize:int=_resolution;
            var r:ResolutionCache
            r=new ResolutionCache(checkSize)

            _resolutions.push(r)



            for (var c:int=1; c < _numberOfZoomLevels + 1; c++)
            {
                checkSize=checkSize * _zoomXFactor;
                r=new ResolutionCache(checkSize)
                _resolutions.push(r)
            }
            _resolutions.pop()

        }

        private function initScrollBar():void
        {
            var sbbmd:BitmapData=new BitmapData(_resolution, 20, false, 0xcccccc)
            _scrollbar=new Bitmap(sbbmd)
            _scrollbar.y=120
            addChild(_scrollbar)

            sbbmd=new BitmapData(_resolution, 16, false, 0xeeeeee)
            _scrollthumb=new MovieClip()
            _scrollthumb.graphics.beginFill(0xff0000)
            _scrollthumb.graphics.drawRect(0, 0, _resolution, 10)
            _scrollthumb.graphics.endFill()
            _scrollthumb.y=125
            addChild(_scrollthumb)
            _scrollthumb.buttonMode=true
            _scrollthumb.addEventListener(MouseEvent.MOUSE_DOWN, beginthumbdrag)

        }

        private function beginthumbdrag(e:MouseEvent):void
        {
            _scrollthumb.startDrag(false, new Rectangle(_scrollbar.x, _scrollbar.y + 5, _scrollbar.width - (_scrollthumb.width), 0))
            _scrollthumb.addEventListener(MouseEvent.MOUSE_MOVE, shuttleMoving, false, 0, true);
            _scrollthumb.addEventListener(MouseEvent.MOUSE_UP, endthumbdrag, false, 0, true);
        }

        private function endthumbdrag(e:MouseEvent):void
        {
            _scrollthumb.stopDrag();
            e.updateAfterEvent();
            _scrollthumb.removeEventListener(MouseEvent.MOUSE_MOVE, shuttleMoving);
        }

        private function shuttleMoving(e:MouseEvent):void
        {
            calculateShuttleRelativePosition();
            drawwaveform()
            //e.updateAfterEvent()
        }

        private function calculateShuttleRelativePosition():void
        {

            var _x:Number=_scrollthumb.x
            _sliderCenter=_x + (_scrollthumb.width / 2)
            _sliderRange=_scrollbar.width - _scrollthumb.width;
            _slider_rel_pos=(_sliderCenter - _sliderCenterMinLeft) / _sliderRange

        }

        public function getPCM():void
        {
            var len:int=_sound.length * 44.1
            _sound.extract(_ba, len)
            this._blocksize=_ba.length / (_resolution * _zoomby)
            shaveblocksize()
        }

        public function zoomin():void
        {
            if (this._zoomby < 16)
            {
                this._zoomby*=2
                resizeThumb()
                drawwaveform()
            }
        }

        public function zoomout():void
        {
            if (_zoomby >= 2)
            {
                this._zoomby/=2
                resizeThumb()

                drawwaveform()
            }
        }

        private function resizeThumb():void
        {
            _scrollthumb.width=_scrollbar.width / _zoomby
            if (_scrollthumb.width == _resolution)
            {
                _slider_rel_pos=0
            }
            _sliderCenterMinLeft=_scrollthumb.width / 2;
            _sliderCenterMax_Right=_scrollbar.width - (_scrollthumb.width / 2);
            _sliderRange=_scrollbar.width - _scrollthumb.width;
            _sliderRange=_scrollbar.width - _scrollthumb.width;
            _scrollthumb.x=(_slider_rel_pos * _sliderRange)
        }

        private function getResolutionCache(vww:int):ResolutionCache
        {
            var r:ResolutionCache
            for (var i:int=0; i < _resolutions.length; ++i)
            {
                if (_resolutions[i].name == vww)
                {
                    r=_resolutions[i];
                    break;
                }
            }
            return r;

        }

        public function drawwaveform():void
        {
            var starttime:Number=getTimer()
            var readposition:int
            var viewPortWidth:int=_resolution;
            var virtualWindowWidth:int=_resolution * _zoomby;
            var l:Number
            var r:Number
            var p:Number

            var rc:ResolutionCache=getResolutionCache(virtualWindowWidth)

            this._blocksize=_ba.length / virtualWindowWidth
            shaveblocksize()
            this.graphics.clear()

            this.graphics.beginFill(0xc5c5c5, 0.5)
            this.graphics.drawRect(0, 50, _resolution, 1)

            var pixel:int=(_slider_rel_pos * (virtualWindowWidth - viewPortWidth - 1));
            var readpoint:int=pixel * _blocksize;
            var rect:Rectangle
            _ba.position=readpoint;

            this.graphics.clear()
            this.graphics.beginFill(0xffffff)

            for (var i:int=0; i < _resolution; i++)
            {

                if (rc.points[pixel] == -1)
                {
                    _ba.position=pixel * _blocksize
                    l=_ba.readFloat() * 100;
                    r=_ba.readFloat() * 100;

                    p=(l + r) / 2

                    rc.addPoint(pixel, i, height / 2, p)
                    rect=rc.points[pixel]
                    //this.graphics.drawRect(rect.x,rect.y,rect.width,rect.height)
                    this.graphics.drawRect(i, 50, 1, p)
                    this.graphics.drawRect(i, 50, 1, -p)


                }
                else
                {

                    //viewportBitmapdata.fillRect(rc.points[pixel], 0xffffff)
                    rect=rc.points[pixel]
                    this.graphics.drawRect(i, 50, 1, rect.height)
                    this.graphics.drawRect(i, 50, 1, -rect.height)
                        //this.graphics.drawRect(i,height/2,rect.width,rect.height)


                }

                pixel++

            }

        }

        private function shaveblocksize():void
        {
            do
            {
                _blocksize--
            } while (_blocksize % 4);
        }

    }
}

1 Ответ

1 голос
/ 13 июля 2010

Почему именно вы пытаетесь найти максимум за несколько кусков?

Кроме того, что этот код должен делать:

            if (_pcmData.bytesAvailable)
            {
                var la:Number=_pcmData.readFloat();
                var ra:Number=_pcmData.readFloat();
                var l:Number=la > 0.0 ? la : -la;
                var r:Number=ra > 0.0 ? ra : -ra;

                ++_divCount;
                var ml:Number=0;
                var mr:Number=0;
                var a_ml:Number=ml > 0.0 ? ml : -ml;
                var a_mr:Number=mr > 0.0 ? mr : -mr;

                ml=a_ml > (l) ? ml : l;
                mr=a_mr > (r) ? mr : r;
            }

ml и mr всегда равны 0, так какой смысл это проверять? а что такое divCount?

Если бы это было для рисования формы волны, я бы нарисовал ее с определенным разрешением. Если я хочу нарисовать форму волны в области шириной 500 пикселей, то в основном будет работать 500 выборок. Если вы хотите, чтобы он немного усреднялся, то вполне хватит набора сэмплов на пиксель. Таким образом, из временного интервала, представленного пикселем, вы выбираете 4 выборки (равноудаленных или случайных) и рассчитывает среднее Если отклонение превышает определенный порог, вы можете попытаться получить более надежное значение, получив больше выборок. В общем, сигналы являются непрерывными и плавными. Время рисования графика должно линейно масштабироваться с размером графика, а не с количеством задействованных выборок.

Greetz
back2dos

...