Copying a sample-based synth produces distorted sound

Since upgrading to SDK 2.1.x I started hearing distorted sound (both in the simulator and on device) coming from some sample-based synths I was using, that were working before, unchanged. I narrowed this down to tracks in MIDI sequences with polyphony, and realized this only happened when I was making copies of an existing synth to add multiple voices to a track instrument.

I made a small repro case with a workaround:

-- Set of repro steps for synth:copy() bug

local seq = playdate.sound.sequence.new("test.mid")
local inst = playdate.sound.instrument.new()
local sample = playdate.sound.sample.new("guitar-c4-bridge.wav")
local synth = playdate.sound.synth.new(sample)
inst:addVoice(synth)

for trackIdx=2,seq:getTrackCount() do
    local track = seq:getTrackAtIndex(trackIdx)
    for _ = 2, track:getPolyphony() do
        -- Comment out the following line for workaround
        inst:addVoice(synth:copy())
        -- Uncomment the following line for workaround
        -- inst:addVoice(playdate.sound.synth.new(sample))
    end
    track:setInstrument(inst)
    seq:setTrackAtIndex(trackIdx, track)
end

seq:play()

function playdate.update()
end

I have a test MIDI file and PCM WAV sample to go with this, that I'm not allowed to upload to this thread, but it shouldn't matter what MIDI file or sample are being used, as long as there is polyphony in the sequence; the polyphonic parts should play distorted if the synth copy takes place.

Commenting out the line inst:addVoice(synth:copy()) and uncommenting instead the following line inst:addVoice(playdate.sound.synth.new(sample)) makes this work as expected again, as a new synth is created from scratch with the same sample data instead of using a synth obtained with synth:copy().

While this workaround does solve my immediate issue, it also means that any new synths thus created would need to get all properties of the original re-assigned as they wouldn't be coming over via copy(), so as long as this is an allowed usage of copy() (which used to work!) it seems the original solution may still be preferable.

As far as I can tell, this usage of synth:copy() also seems related to this OS crash I filed a few months back E0 crash with Lua game on SDK 2.0, as the above workaround appears to avoid it.

1 Like

oof. I built a mechanism so that a synth can make a unique copy of its internals when you do synth:copy(), and then I completely forgot to use it. :man_facepalming: At least it's a simple fix. I'll get this into the 2.4 release. Thanks for your patience, and for all your help with this!

No problem, thanks for taking care of it. Looking forward to 2.4!