I had something written at that time, but it wasn’t calculating the times correctly and i forgot to continue.
Still just a sketch code, as it just reads on/off notes and time related stuff. (no velocities, controllers, key-signatures, etc).
All you need is to have the csv file linked in the Text Editor, and the notes objects (named as xx.000 to xx.127).
import bpy
from collections import defaultdict
# the csv file
cvsfile = bpy.data.texts['pmc.csv']
# the prefix for the objects (from *.000 to *.127)
objectprefix = 'Cube'
#channel to be used
channel = 2
class tempo():
def __init__(self, lst, clk, fps):
self._clk = clk*1e6
self._lst = lst
self._tbl = self._buildtable()
self._fps = fps
def _calc(self, clocknow, clockstart, curtick, timestart):
return (((clocknow-clockstart)*curtick) / (self._clk)) + timestart
def _buildtable(self):
clockstart=0
clockspeed=1e6
timestart=0
timelast=0
table=[]
for tempoevt in self._lst:
if tempoevt[0]>clockstart:
table.append((clockstart, tempoevt[0], clockspeed, timestart))
timestart = self._calc(tempoevt[0], clockstart, clockspeed, timestart)
clockstart = tempoevt[0]
clockspeed = tempoevt[2]
table.append((clockstart, float('inf'), clockspeed, timestart))
return table
def _getslice(self, value):
return [sl for sl in self._tbl if sl[0]<=value<sl[1]][0]
def calc(self, value):
sl = self._getslice(value)
time = self._calc(value, sl[0], sl[2], sl[3])
return int(time * self._fps)
def readtracks(file):
tracks = defaultdict(list)
for line in file.lines:
splits = [x.strip() for x in line.body.split(',')]
if len(splits)>1:
track = eval(splits[0])
evttime = eval(splits[1])
evttype = splits[2]
if evttype.lower() in ['header', 'tempo', 'note_on_c', 'note_off_c']:
args = [eval(s) for s in splits[3:]]
tracks[track].append([evttime, evttype]+args)
return tracks
def processtrack(track):
notes = defaultdict(list)
activenotes = {}
idx = 0
for evt in track:
if evt[1].lower()=='note_on_c':
if evt[3] in activenotes.keys():
notes[evt[3]].append((activenotes.pop(evt[3]), evt[0]))
activenotes[evt[3]]=evt[0]
elif evt[1].lower()=='note_off_c':
if evt[3] in activenotes.keys():
notes[evt[3]].append((activenotes.pop(evt[3]), evt[0]))
return notes
def processtempos(track):
tempos = []
for evt in track:
if evt[1].lower()=='tempo':
tempos.append(evt)
return tempos
def processheader(track):
return track[0][-1]
def parsetracks(trackdict):
clock=0
notes={}
tempos=[]
for trackidx in trackdict.keys():
if trackidx==0:
clock = processheader(trackdict[trackidx])
elif trackidx==1:
tempos = processtempos(trackdict[trackidx])
else:
pnotes = processtrack(trackdict[trackidx])
if len(pnotes):
notes[trackidx]=pnotes
return clock, notes, tempos
# scale times to animation
def scenespeed():
rndr = bpy.context.scene.render
return rndr.fps*rndr.fps_base
def timefy(clock, events, tempos):
scaledevents=defaultdict(list)
tempostat = tempo(tempos, clock, scenespeed())
for note,evts in events.items():
for evt in evts:
sttime = tempostat.calc(evt[0])
entime = tempostat.calc(evt[1])
scaledevents[note].append((sttime, entime))
return scaledevents
#object related stuff
def pressevt(note, start, end):
obj = bpy.data.objects['{:s}.{:03d}'.format(objectprefix, note).format(note)]
obj.rotation_euler.x=-0.20
obj.keyframe_insert("rotation_euler", frame = start)
obj.rotation_mode = "XYZ"
obj.rotation_euler.x=0.00
obj.keyframe_insert("rotation_euler", frame = end)
def resetobjs(insertkf=-1):
for i in range(127):
obj = bpy.data.objects['{:s}.{:03d}'.format(objectprefix, i)]
obj.rotation_euler.x = 0.0
if insertkf>=0:
obj.keyframe_insert("rotation_euler", frame=insertkf)
def setinterpolation():
for i in range(127):
obj = bpy.data.objects['{:s}.{:03d}'.format(objectprefix, i)]
keyframes = obj.animation_data.action.fcurves[0].keyframe_points
for kf in keyframes:
kf.interpolation='CONSTANT'
def transfermotion(notes):
for x,v in notes.items():
for itm in v:
pressevt(x, itm[0], itm[1])
def main():
tracks = readtracks(cvsfile)
clock, notesEvents, tempoEvts = parsetracks(tracks)
scaledtimes=timefy(clock, notesEvents[channel], tempoEvts)
resetobjs(0)
transfermotion(scaledtimes)
setinterpolation()
resetobjs()
main()