python-midi
python-midi copied to clipboard
Best way to deepcopy a track
I'm trying to get a deep copy of a track via:
copy.deepcopy(track)
but I'm getting this error:
File "/Users/tleyden/Development/climate_music/src/transformer.py", line 52, in transform
track_copy = copy.deepcopy(track)
File "/Users/tleyden/DevLibraries/anaconda/lib/python2.7/copy.py", line 190, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "/Users/tleyden/DevLibraries/anaconda/lib/python2.7/copy.py", line 351, in _reconstruct
item = deepcopy(item, memo)
File "/Users/tleyden/DevLibraries/anaconda/lib/python2.7/copy.py", line 190, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "/Users/tleyden/DevLibraries/anaconda/lib/python2.7/copy.py", line 346, in _reconstruct
setattr(y, key, value)
File "/Users/tleyden/DevLibraries/anaconda/lib/python2.7/site-packages/midi/events.py", line 125, in set_velocity
self.data[1] = val
AttributeError: data
As an alternative, I'm writing my own kludge and just propagating the events I care about:
def copy_track(track):
"""
copy.deepcopy() didn't work, so I hand rolled this as a workaround
"""
track_copy = midi.Track()
for event in track:
if isinstance(event, midi.NoteOnEvent):
on = midi.NoteOnEvent(tick=event.tick, velocity=event.velocity, pitch=event.pitch)
track_copy.append(on)
if isinstance(event, midi.NoteOffEvent):
off = midi.NoteOffEvent(tick=event.tick, velocity=event.velocity, pitch=event.pitch)
track_copy.append(off)
return track_copy
If it's not feasible to make copy.deepcopy()
work, is there a more elegant way of rolling my own?
I never really looked into this fully. From the discussion last time (#40), it seems I had tracked it to a known interaction between deepcopy
using property
/custom getters/setters, but I also seem to recall something about how __slots__
worked affecting it. Hrm...
So I think fixing it is feasible, but no one ever got around to figuring it out.
In the meantime, I know you can simply provide custom functions for __copy__
/__deepcopy__
which will be used by them automatically. Here's an SO thread on it.
I also tried to deepcopy, because I was removing single notes (note on & off) from a track and so I had to update the next note's tick to produce a suitable gap between both (the last and the next remaining note). Because I accessed the same source track multiple times (to split several drum components like bass drum or snare in one session without reloading), I used the event's constructor to recreate the event when appending to the new track (so to say: manually deep copy it). So it looked like this:
kwargs = {
"tick": event.tick,
"velocity": event.velocity,
"pitch": event.pitch,
"channel": event.channel
}
target.append(type(event)(**kwargs))
But I'm not sure whether I fetched all necessary ctor-args .. but it seems to work for me ^^ Doing this on your own isn't perfect but maybe a suitable temporary solution to you :-)