Advance ways to avoid memory leak ? audio related

hello

i’m not a coder. i’m a musician/visual artist.
with the help of this wonderful community here, and also with chatgpt, i put together this code that shuffles and endlessly plays a sequence of audio clips (and also enables / indicates objects within the project for each clip). this code works perfect on my rather strong macbook, but on older devices with little RAM and on my rather new iphone, my project crashes relatively fast.

maybe my aim is a bit crazy, i want to have a ton of audio clips in my project (i’ve set all of them to not pre-loaded) and then have a relatively stable playback of them on devices with only 2, 3 or 4GB of RAM …

with the code below, do the clips stay in the cache / memory after they been loaded and played?
i’m wondering if its is somehow possible that the code is somehow cleaning up after itself… so that its really almost like streaming audio, that each mp3 clip is loaded and then memory is freed again?
how to find out what makes most memory used ? i have the feeling that maybe after 10-20 minutes maybe 5-6 times a clip of 3mb has been loaded and it accumulates too much memory use throughout and then crashes… what in my code is not efficient in that regard?

thanks so much for any help in advance, really really appreciate this!

here is my code:

var ClipPlayer = pc.createScript('clipPlayer');
var _currentIndex = 0;

ClipPlayer.attributes.add('clips', {
    type: 'asset',
    assetType: 'audio',
    array: true
});

ClipPlayer.attributes.add('indicators', {
    type: 'entity',
    array: true
});

// initialize code called once per entity
ClipPlayer.prototype.initialize = function () {
    this.index = Array(this.clips.length).fill(null).map((_, i) => i);
    this.index = shuffle(this.index);
    _currentIndex = 0;
    this.playSound(_currentIndex);

    this.entity.sound.on('end', function () {
        //let lastidx = this.index[_currentIndex -1];
        //this.clips[lastidx].unload();
        this.clearIndicators();
        this.playSound(_currentIndex);
    }, this);
};

ClipPlayer.prototype.playSound = function (clipIndex) {
    if (clipIndex >= this.clips.length || clipIndex < 0) {
        console.log('Shuffling');
        _currentIndex = clipIndex = 0;
        this.index = shuffle(this.index);
    }
    console.log(this.index);
    let idx = this.index[clipIndex];
    console.log(`Playing clip ${this.clips[idx].name}`);
    
    this.setIndicatorActive(idx, true);

    //console.log(this.clips[idx].loaded);
    //if(!this.clips[idx].loaded ) {
       // this.app.assets.load(this.clips[idx]);
    //}
    
    this.entity.sound.slot('Slot').asset = this.clips[idx];
    this.entity.sound.play('Slot');

    _currentIndex += 1;
};

ClipPlayer.prototype.setIndicatorActive = function (indicatorIndex, active) {
    if (indicatorIndex >= this.indicators.length || indicatorIndex < 0) {
        return;
    }

    if (active) {
        this.indicators[indicatorIndex].element.color = new pc.Color(0.);
    } else {
        this.indicators[indicatorIndex].element.color = new pc.Color(0,0,0,0,);
    }
};

ClipPlayer.prototype.clearIndicators = function () {
    for (const i in this.indicators) {
        this.setIndicatorActive(i, false);
    }
};

function shuffle(array) {
  let currentIndex = array.length,  randomIndex;

  // While there remain elements to shuffle.
  while (currentIndex != 0) {

    // Pick a remaining element.
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex--;

    // And swap it with the current element.
    [array[currentIndex], array[randomIndex]] = [
      array[randomIndex], array[currentIndex]];
  }

  return array;
}

Hi @asnras,

Have you tried unloading the sound assets that aren’t currently in use?

I see that you have commented out the call to asset.unload().

thanks for pointing the unload thing out! maybe i should try again. but is it in the correct place in the code? so that it would unload mp3s after they’ve been played (sorry i can’t code at all)

Hi @asnras,

Your code is a bit long to review/debug out of context, but you are right that you should be calling unload as soon as your sounds are stop playing.

If you’d like at any point to use them again, then you need to make sure to reload them:

mySoundAsset.ready( () => {
   // this will fire as soon as the sound is loaded and available for playback
});

this.app.assets.load(mySoundAsset);

thank you! i dont really get what to put after the brackets ? thanks