goldfire / howler.js

Javascript audio library for the modern web.
https://howlerjs.com
MIT License
24.04k stars 2.24k forks source link

Preloading locally? Why does it take so long? #519

Closed Jones-S closed 8 years ago

Jones-S commented 8 years ago

Hi there

I have a local setup for a gesture controlled radio and I use howler to play some music. Now the thing is, that I thought it might be a good idea to save the songs as .wav files to make it easier for the computer, as it does not have to decompress the audio files (with mp3 they do). But now I realize that even with preload: true (howler v1: buffer) it takes a long time to start a song. Can't I just access the file directly from the harddisk? Is it saved somewhere in a temporary storage, or why does it take so long? I would be glad if you could share some insight so that I get to know how I can optimize and how the whole system works.

Thanks in advance. Cheers

Jones-S commented 8 years ago

Or, is there some function built in, which allows me to execute a callback function, as soon as all sounds are loaded? And does anyone know, if there is a limit? I still believe that the song is probably stored temporarily. Thanks for shedding any light on this.

goldfire commented 8 years ago

What filetype are you playing and in what browser?

Jones-S commented 8 years ago

Dammit, I totally missed your comment. Well I wanted to use wav files, due to the fact that a computer would not need to decompress the file. This means a music file is about 30MB. And with around 10 tracks, I get 300MB of preloading ... 😲 I am using this in Chrome or Safari, both at the newest version. I now switched back to mp3 (Filesize ~ 3-4MB) because I experience much shorter preloading periods – which only makes sense.

But I was asking myself, if I could play the music directly from my disk instead of loading it into some storage, which I guess it does at the moment.

Or at least have some clue, how far the preloading has progressed...

Thanks for your help in advance.

goldfire commented 8 years ago

If you are loading files that large you'll want to use html5: true on 2.0 and buffer: true on 1.x (wasn't sure by your first post if you were saying you were using that or not). Assuming there isn't an issue with the file where it doesn't have a duration (which can be an issue with OGG), using HTML5 Audio instead of Web Audio should get it playing quite quickly. Otherwise, it has to wait for the full file to download.

Jones-S commented 8 years ago

Ok, so setting the html5 to true should do it? (And no, I just wanted to make a complete question, so if someone using version 1.0 could also understand what I am asking. for the record: I am using v2.0). Alright. Thanks, I will check and get back here with feedback if it worked or not. Thank you very much.

Jones-S commented 8 years ago

Funny thing is, that with html5: true the song does not play at all. If I take this option out, it does take its time, but it plays eventually... The wav file is 65MB big... do you know if there could be any other issue with the wav file itself?

goldfire commented 8 years ago

Can you provide sample code?

Jones-S commented 8 years ago

Yes sure. Here you go. I took the radio fragment out of my code, but I think it should contain all the necessary things.

(function() {

    function completeFilePath(directory, files) {
        var tracks = [];

        // looping reversly. File order will be in reverse
        for (var i = files.length - 1; i >= 0; i--) {
            var file = directory + files[i];
            tracks.push(file);
        }
        return tracks;
    }

    APP.Radio = function() {

        this.files = [
            'dire_sultan.wav',
            'rhcp_cabron.wav',
            'uh_lady.wav',
            'racon_steady.wav'
        ];

        this.folder = "audio/tracks/classics/";
        this.files = completeFilePath(this.folder, this.files);
        console.log("this.files: ", this.files);

        this.current_track          = 0;
        this.current_playback_id    = undefined;
        this.howler_bank            = [];
        this.current_volume         = 0.5   ; // from 0.01 to 1.0
        var uber                    = this;

        // build up howler_bank:
        this.files.forEach(function(current, i) {
            uber.howler_bank.push(new Howl({
                src: [uber.files[i]],
                onend: uber.onEnd.bind(uber),
                preload: true,
                // html5: true,
                volume: uber.current_volume
            }));
        });

    };

    APP.Radio.prototype.play = function() {

        var uber = this;
        var song = uber.howler_bank[uber.current_track];
        if (!song.playing()){
            // set the volume before playing
            song.volume(uber.current_volume);
            song.play();
        }

    };

}());

I currently commented the html5 out. Also in my setup I have more songs. About 12. Some of the tracks are more than 60MB (wav). It should create the howls on load, but only after I give the command to play. If it's html5, it does not start at all, if it's Web Audio it does not play if I give the play command immediately after page load. But if I wait for around 10s, it will play (I have to repeat the command ...).

goldfire commented 8 years ago

I modified your code sample so that it was testable and I can't get it to not work. What is different from this from what you have?

https://jsfiddle.net/wc4m7jq2/

Jones-S commented 8 years ago

First thanks for the effort!! It looks pretty much the same. I realized that your first song is only 15MB, but still, if I load your jsfiddle and click on to the button immediately after the visual components are on the screen, it does not start playing the song. If I just wait it won't play either. So the play command just got lost. If I press again afterwards it plays, but first it does not. (Safari this time). I guess it is because the song is not ready at the moment I press Play 0.

-- Edit: No I was wrong. It will eventually start playing but it takes about 20 seconds. Then it will start. Maybe in my case with a file four times bigger than yours, I never waited for a minute or longer. But the problem remains. I either need a preloader telling the user that something is happening behind, or even better: I need to play it locally, which I suppose is much faster, if that is even possible...

goldfire commented 8 years ago

If play is called before the sound is ready, it will get queued and will fire on load. When html5: true is set, it will wait until canplaythrough has been fired by the browser before it starts playing.

Jones-S commented 8 years ago

Ok. But that means there is no way to have it ready more quickly or at least display a loader telling the user how long the system needs until it is ready?

goldfire commented 8 years ago

You can listen to the progress event on the sound's _node for load progress. This may be something we'll add into the library directly, but at this point it would have to be post-2.0.