downsamp.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. from xml.etree import ElementTree as ET
  2. import optparse
  3. import os
  4. parser = optparse.OptionParser()
  5. parser.add_option('-f', '--frequency', dest='frequency', type='float', help='How often to switch between active streams')
  6. parser.set_defaults(frequency=0.016)
  7. options, args = parser.parse_args()
  8. class Note(object):
  9. def __init__(self, time, dur, pitch, ampl):
  10. self.time = time
  11. self.dur = dur
  12. self.pitch = pitch
  13. self.ampl = ampl
  14. for fname in args:
  15. try:
  16. iv = ET.parse(fname).getroot()
  17. except IOError:
  18. import traceback
  19. traceback.print_exc()
  20. print fname, ': Bad file'
  21. continue
  22. print '----', fname, '----'
  23. notestreams = iv.findall("./streams/stream[@type='ns']")
  24. print len(notestreams), 'notestreams'
  25. print 'Loading all events...'
  26. evs = []
  27. dur = 0.0
  28. for ns in notestreams:
  29. for note in ns.findall('note'):
  30. n = Note(
  31. float(note.get('time')),
  32. float(note.get('dur')),
  33. float(note.get('pitch')),
  34. float(note.get('ampl', float(note.get('vel', 127.0)) / 127.0)),
  35. )
  36. evs.append(n)
  37. if n.time + n.dur > dur:
  38. dur = n.time + n.dur
  39. print len(evs), 'events'
  40. print dur, 'duration'
  41. print 'Scheduling events...'
  42. sched = {}
  43. t = 0.0
  44. i = 0
  45. while t <= dur:
  46. nextt = t + options.frequency
  47. #print '-t', t, 'nextt', nextt
  48. evs_now = [n for n in evs if n.time <= t and t < n.time + n.dur]
  49. if evs_now:
  50. holding = False
  51. count = 0
  52. while count < len(evs_now):
  53. selidx = (count + i) % len(evs_now)
  54. sel = evs_now[selidx]
  55. sched[t] = (sel.pitch, sel.ampl)
  56. if sel.time + sel.dur >= nextt:
  57. holding = True
  58. break
  59. t = sel.time + sel.dur
  60. count += 1
  61. if not holding:
  62. sched[t] = (0, 0)
  63. else:
  64. sched[t] = (0, 0)
  65. t = nextt
  66. i += 1
  67. print len(sched), 'events scheduled'
  68. print 'Writing out schedule...'
  69. newiv = ET.Element('iv')
  70. newiv.append(iv.find('meta'))
  71. newivstreams = ET.SubElement(newiv, 'streams')
  72. newivstream = ET.SubElement(newivstreams, 'stream', type='ns')
  73. prevt = None
  74. prevev = None
  75. for t, ev in sorted(sched.items(), key=lambda pair: pair[0]):
  76. if prevt is not None:
  77. if prevev[0] != 0:
  78. ET.SubElement(newivstream, 'note',
  79. pitch = str(prevev[0]),
  80. ampl = str(prevev[1]),
  81. time = str(prevt),
  82. dur = str(t - prevt),
  83. )
  84. prevev = ev
  85. prevt = t
  86. t = dur
  87. if prevev[0] != 0:
  88. ET.SubElement(newivstream, 'note',
  89. pitch = str(prevev[0]),
  90. ampl = str(prevev[1]),
  91. time = str(prevt),
  92. dur = str(t - prevt),
  93. )
  94. print 'Done.'
  95. txt = ET.tostring(newiv, 'UTF-8')
  96. open(os.path.splitext(os.path.basename(fname))[0]+'.downsampled.iv', 'wb').write(txt)