How to create valid preloader with jQuery, which can preload mp3 file to browser cache?
Asked Answered
M

2

6

I have a simple drawing spectrum on a website http://alldev.eu/html/mp3/index.phtml, which loads to browser cache a song and plays it after it's fully downloaded.

I've made a pre-loader for my site which displays a message and an image for 7 seconds while the song is being loaded. Unfortunately, it doesn't work in the way I'd like to since 7 seconds might not be enough time to load a song (for instance, a test song with 11 Megabytes)

How can I rebuild my site to pre-load all data? My current script is below:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8"></meta>
        <title>Shiny Toy Guns - Major Tom</title>
        <script type="text/javascript" src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
        <script type="text/javascript">
            (function($) {
                $.fn.extend({
                    jqbar: function(options) {
                        var DefaultSpeedOfAnimation = 7000;
                        var settings = $.extend({
                            SpeedOfAnimation: DefaultSpeedOfAnimation,
                            LengthOfBar: 200,
                            barWidth: 10,
                            barColor: 'red',
                            label: '&nbsp;',
                            value: 100
                        }, options);
                        return this.each(function() {
                            var valueLabelHeight = 0;
                            var ContainerProgress = $(this);
                            ContainerProgress.addClass('jqbar horizontal').append('<div class="bar-label"></div><div class="bar-level-wrapper"><div class="bar-level"></div></div><div class="bar-percent"></div>');
                            var progressLabel = ContainerProgress.find('.bar-label').html(settings.label);
                            var progressBar = ContainerProgress.find('.bar-level').attr('data-value', settings.value);
                            var progressBarWrapper = ContainerProgress.find('.bar-level-wrapper');
                            progressBar.css({
                                height: settings.barWidth,
                                width: 0,
                                backgroundColor: settings.barColor
                            });
                            var valueLabel = ContainerProgress.find('.bar-percent');
                            valueLabel.html('0');
                            animateProgressBar(progressBar);

                            function animateProgressBar(progressBar) {
                                var level = parseInt(progressBar.attr('data-value'));
                                if (level > 100) {
                                    level = 100;
                                    alert('max value cannot exceed 100 percent');
                                }
                                var w = settings.LengthOfBar * level / 100;
                                progressBar.animate({
                                    width: w
                                }, {
                                    duration: DefaultSpeedOfAnimation,
                                    step: function(currentWidth) {
                                        var percent = parseInt(currentWidth / settings.LengthOfBar * 100);
                                        if (isNaN(percent)) percent = 0;
                                        ContainerProgress.find('.bar-percent').html(percent + '%');
                                    }
                                });
                            }
                        });
                    }
                });
            })(jQuery);
        </script>
        <style>
            body {
                text-align: center;
                background-color: black;
                color: white;
            }
            footer {
                float: center;
                bottom: 0;
                position: absolute;
                color: #FFFFFF;
                font: bold 1.2em/2.5 arial;
                width: 99%;
            }
            .jqbar {
                position: relative;
                top: 100px;
            }
            .jqbar.horizontal div {
                display: inline-block;
                margin-left: 5px;
                font-size: 11px;
                font-weight: bold;
            }
            .jqbar.horizontal .bar-percent {
                font-size: 11px;
                font-weight: bold;
                height: 20px;
                margin-bottom: 5px;
            }
            #progressbar {
                width: 400px;
                height: 22px;
                border: 1px solid #000;
                background-color: #292929;
            }
            #progressbar div {
                height: 100%;
                color: #FFF;
                text-align: center;
                line-height: 22px;
                width: 0;
                background-color: #0099FF;
            }
            #preloader {
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                color: #FFF;
                z-index: 99;
                height: 100%;
            }
            #status {
                width: 200px;
                height: 200px;
                position: absolute;
                left: 50%;
                top: 50%;
                background-color: #000;
                background-repeat: no-repeat;
                background-position: center;
                margin: -100px 0 0 -100px;
            }
        </style>
    </head>

    <body onload="hide_preloader();">
        <div id="preloader">
            <div id="status">Wait for MP3 Load...
                <br>
                <br>
                <br>
                <img src="http://alldev.eu/html/images/Loader.gif" />
            </div>
        </div>
        <footer>
            <center>
                <div id="bar-1"></div>
                <canvas id="music" width="1024" height="250" style="display: block;"></canvas>
            </center>
        </footer>
        <script type="text/javascript">
            jQuery(window).load(function() {
                jQuery("#status").delay(5000).fadeOut(2500);
                jQuery("#preloader").delay(5000).fadeOut(2500);
                jQuery("#bar-1").delay(5000).fadeOut(2500);
            });

            $(document).ready(function() {
                $('#bar-1').jqbar({
                    SpeedOfAnimation: 7000,
                    label: 'Loading...',
                    value: 100,
                    barColor: '#FFF',
                    barWidth: 20
                });
            });

            if (!window.AudioContext) {
                if (!window.webkitAudioContext) {
                    alert('AudioContext not found!');
                }
                window.AudioContext = window.webkitAudioContext;
            }
            var context = new AudioContext();
            var audioBuffer;
            var sourceNode;
            var analyser;
            var javascriptNode;
            var ctx = $("#music").get()[0].getContext("2d");
            var gradient = ctx.createLinearGradient(0, 0, 0, 325);

            gradient.addColorStop(1, '#FFFFFF');
            gradient.addColorStop(0.75, '#00FFFF');
            gradient.addColorStop(0.25, '#0000FF');
            gradient.addColorStop(0, '#000000');

            setupAudioNodes();
            loadSound("http://alldev.eu/html/mp3/Shiny%20Toy%20Guns%20-%20Major%20Tom%20(Official%20Live).mp3");

            function setupAudioNodes() {
                javascriptNode = context.createScriptProcessor(2048, 1, 1);
                javascriptNode.connect(context.destination);
                analyser = context.createAnalyser();
                analyser.smoothingTimeConstant = 0.75; //0.5;
                analyser.fftSize = 512;
                sourceNode = context.createBufferSource();
                sourceNode.connect(analyser);
                analyser.connect(javascriptNode);
                sourceNode.connect(context.destination);
            }

            $(document).ready(function() {
                $.ajax({
                    url: "soundfile.mp3",
                    success: function() {
                        $("#play_button").show();
                    }
                });
            });

            function loadSound(url) {
                var request = new XMLHttpRequest();
                request.open('GET', url, true);
                request.responseType = 'arraybuffer';
                request.onload = function() {
                    context.decodeAudioData(request.response, function(buffer) {
                        playSound(buffer);
                    }, onError);
                }
                request.send();
            }

            function playSound(buffer) {
                sourceNode.buffer = buffer;
                sourceNode.start(0);
            }

            function onError(e) {
                console.log(e);
            }

            javascriptNode.onaudioprocess = function() {
                var array = new Uint8Array(analyser.frequencyBinCount);
                analyser.getByteFrequencyData(array);
                ctx.clearRect(0, 0, 1024, 325);
                ctx.fillStyle = gradient;
                drawSpectrum(array);
            }

            function drawSpectrum(array) {
                for (var i = 0; i < (array.length); i++) {
                    var value = array[i];
                    ctx.fillRect(i * 5, 325 - value, 3, 325);
                }
            };
        </script>
    </body>

</html>
Marnamarne answered 19/2, 2014 at 17:26 Comment(4)
You don't know how many time it will take to download file so using a progress bar seems compromised. You should load any other kind of animation and remove it in request.onload or any other callback when your file is completly downloaded. It is just quite hard to figure out which is the more appropriate event to remove animation reading your codeMallis
Preload all data? Can you stream the audio?Ratliff
I don't think you can get that information with javascript : it can tells you if it's downloaded or not. Or maybe look to the audio API ?Kuntz
@gvee: I don't think that I stream the audio, but yes - I want to preload all website data.Marnamarne
B
2

you can give preloadJS a try. http://www.createjs.com/#!/PreloadJS

here's some code from their documentation to get you started:

var queue = new createjs.LoadQueue();
 queue.installPlugin(createjs.Sound);
 queue.on("complete", handleComplete, this);
 queue.loadFile({id:"sound", src:"http://path/to/sound.mp3"});
 queue.loadManifest([
     {id: "myImage", src:"path/to/myImage.jpg"}
 ]);
 function handleComplete() {
     createjs.Sound.play("sound");
     var image = queue.getResult("myImage");
     document.body.appendChild(image);
 }
Beall answered 19/2, 2014 at 17:59 Comment(3)
I think preloadJS will wait for the sound to be loaded, but can't display the progression level of the download ?Kuntz
does it really matter though? you can just use a loading animation and cancel it when the preloading is done. I am not sure how one would display a progression bar of downloaded content without access to the file system.Beall
Seeing his example, I guess he wants to show the progress state ? With preload JS, it can only be 0 or 100%.Kuntz
K
1

Check for JWPlayer API, you can have access to a method getBuffer(), which returns the current buffered state for your audio file : http://www.longtailvideo.com/support/jw-player/28851/javascript-api-reference/

But this requires to use JWplayer to play / handle your audio file, as it's not included in the audio object : http://www.w3schools.com/tags/av_prop_buffered.asp

EDIT :

I took some time to make it work, see the fiddle :) : http://jsfiddle.net/uKZ8N/

Basically, I set an interval of 0,5s which check the getBuffer() value.

Kuntz answered 19/2, 2014 at 18:23 Comment(7)
Hm... I'm trying and trying and don't know, why after use jwplayer().getBuffer() I get nothing...Marnamarne
Did you call jwplayer like that ? <div id="myElement">Loading the player ...</div> <script type="text/javascript"> jwplayer("myElement").setup({ file: "/uploads/example.mp4", height: 360, image: "/uploads/example.jpg", width: 640 }); </script>Kuntz
Yes, I call jwplayer like you wrote and it don't work.Marnamarne
what does console.log(jwplayer('#yourElement').getBuffer()); returns ?Kuntz
I made an edit to my post with a fiddle of a working example :)Kuntz
Your code from fiddle works perfectly, but... It shows jwplayer, what is bad for me. Is it possible to show only numbers from 0 to 100 from getBuffer? Without load all player?Marnamarne
just autoplay your audio file, and put a display: none on the player ? It only hides it, but you need to load jwplayer to use its API (including getBuffer).Kuntz

© 2022 - 2024 — McMap. All rights reserved.