Any significant overhead from creating AudioSamples, PDSynths, and SequenceTracks on the fly?

As I've mentioned in previous threads, I'm working on a tracker module player, and one of the effects in it I need to implement is "sample offset", which allows playing a sample starting at a particular offset, as well as "retrigger" for replaying a sample several times quickly.

Since the Playdate API doesn't on its own have a feature for playing a sample starting at a particular offset, I'm implementing this by creating new instances of AudioSample using newSampleFromData (so no allocating or copying memory necessary, just using existing audio data) and swapping out the AudioSample assigned to an existing PDSynth. Retrigger I'm implementing by creating a SequenceTrack on the fly. But this is as music is playing, and eventually while game logic is computing at the same time. I'd also need to add and remove signals to these various PDSynth instances.

So I'm wondering, what kind of overhead there is with creating and modifying these entities at runtime, rather than creating them all ahead of time when loading the music in the first place? Would it be better for me to structure my code so that I'm trying to create and setup as much of these as possible at load time?

the parameter youre looking for is:

playdate.sound.sampleplayer:setPlayRange(start, end)

you can also specify these in negative values which would add silence at the start of the loop, or drop frames from the end of the loop.

i think its this in C:

void playdate->sound->sampleplayer->setPlayRange(SamplePlayer* player, int start, int end)

though I'm a Lua kid and the description of the negative value behaviour doesnt match my expectation.

I had missed that SamplePlayer has an option for specifying the start point in a sample. Interesting!

Unfortunately I don't think I can use it for my purposes since I'm making heavy use of frequency modulation, which is a feature of PDSynth and not SamplerPlayer. Though if the Playdate devs would like to add a similar feature for the sample start time to PDSynth, that would certainly make what I'm implementing a lot simpler! (Though I've already finished implementing it using the technique I described in my first post.)

1 Like

I think I can now answer my own question. I just did a test of six PDSynths all simultaneously playing about eight notes a second, and every time a note was triggered it would create a new AudioSample based on a different position in the audio data, assign it to one of the PDSynths, free the old AudioSample instance, and then play the note. That took around 31% of my Playdate's CPU.

I then repeated the same test, but this time it just played a note using the PDSynths without creating or freeing any AudioSamples. That took around 30.5% of the Playdate's CPU.

So I think it's safe to say that that there's no significant overhead to creating AudioSamples and assigning them to PDSynths on the fly, if you're doing it around fifty times a second.

2 Likes