deep_note.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. from xml.etree import ElementTree as ET
  2. import optparse, random, math, sys
  3. def store_tup(opt, optstr, val, parser, nm, idx, filt=float):
  4. tup = getattr(parser.values, nm)
  5. setattr(parser.values, nm, tup[:idx] + (filt(val),) + tup[(idx+1):])
  6. fund = 440.0
  7. def to_freq(p):
  8. return fund * 2.0**((p - 69) / 12.0)
  9. def to_pitch(f):
  10. try:
  11. return 12 * math.log(f / fund, 2) + 69
  12. except ValueError:
  13. print 'bad frequency', f
  14. raise
  15. def store_target(opt, optstr, val, parser):
  16. print 'opt', opt, 'optstr', optstr, 'val', val, 'parser', parser
  17. if val.startswith('@'):
  18. val = int(val[1:])
  19. else:
  20. val = int(to_freq(float(val)))
  21. parser.values.targets.append((
  22. parser.values.voices,
  23. val,
  24. parser.values.fadeint,
  25. parser.values.inita,
  26. parser.values.randt,
  27. parser.values.randf,
  28. parser.values.fstep,
  29. parser.values.fina,
  30. parser.values.sweept,
  31. parser.values.fadeoutt
  32. ))
  33. parser = optparse.OptionParser()
  34. parser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='Be verbose')
  35. parser.add_option('-V', '--voices', dest='voices', type='int', help='Subsequent -t will have this many voices directed toward it')
  36. parser.add_option('--fadeinlow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('fadeint', 0), help='Low fade-in time for subsequent -t')
  37. parser.add_option('--fadeinhigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('fadeint', 1), help='High fade-in time for subsequent -t')
  38. parser.add_option('--initalow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('inita', 0), help='Low init amplitude time for subsequent -t')
  39. parser.add_option('--initahigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('inita', 1), help='High init amplitude time for subsequent -t')
  40. parser.add_option('--randtlow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('randt', 0), help='Low random time for subsequent -t')
  41. parser.add_option('--randthigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('randf', 1), help='High random time for subsequent -t')
  42. parser.add_option('--randflow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('randf', 0), help='Low random freq for subsequent -t')
  43. parser.add_option('--randfhigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('randt', 1), help='High random freq for subsequent -t')
  44. parser.add_option('--fstep', dest='fstep', type='float', help='Frequency to wander by in random phase')
  45. parser.add_option('--finalow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('fina', 0), help='Low init amplitude time for subsequent -t')
  46. parser.add_option('--finahigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('fina', 1), help='High init amplitude time for subsequent -t')
  47. parser.add_option('--sweeplow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('sweept', 0), help='Low sweep time for subsequent -t')
  48. parser.add_option('--sweephigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('sweept', 1), help='High sweep time for subsequent -t')
  49. parser.add_option('--fadeoutlow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('fadeoutt', 0), help='Low fade-out time for subsequent -t')
  50. parser.add_option('--fadeouthigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('fadeoutt', 1), help='High fade-out time for subsequent -t')
  51. parser.add_option('-t', '--target', action='callback', type='str', callback=store_target, nargs=1, help='Have some voices target this MIDI pitch or @frequency')
  52. parser.add_option('-C', '--clear-targets', action='store_const', const=[], dest='targets', help='Clear all targets (including built in ones) prior')
  53. parser.add_option('-r', '--resolution', dest='resolution', type='float', help='Period of generated samples')
  54. parser.add_option('-c', '--chorus', dest='chorus', type='float', help='Random variation of frequency (factor)')
  55. parser.add_option('--smooth', dest='smooth', type='int', help='Number of random uniform samples to perform to smooth')
  56. parser.add_option('-D', '--duration', dest='duration', type='float', help='Length of the note')
  57. parser.add_option('--slack', dest='slack', type='float', help='Slack added to duration to overcommit clients')
  58. parser.add_option('--fundamental', dest='fundamental', type='float', help='Frequency of the A above middle C (traditionally 440 Hz)')
  59. fadeint = (4.0, 6.0)
  60. inita = (0.1, 0.2)
  61. randt = (8.5, 9.0)
  62. fina = (0.95, 1.0)
  63. sweept = (17.5, 19.0)
  64. fadeoutt = (1.5, 3.5)
  65. randf = (200, 400)
  66. fstep = 5
  67. parser.set_defaults(
  68. resolution = 0.05,
  69. chorus = 0.02,
  70. smooth = 5,
  71. duration = 30.0,
  72. slack = 0.02,
  73. fundamental = 430.0,
  74. voices = 1,
  75. fadeint = fadeint,
  76. inita = inita,
  77. randt = randt,
  78. fina = fina,
  79. sweept = sweept,
  80. fadeoutt = fadeoutt,
  81. randf = randf,
  82. fstep = fstep,
  83. targets = [
  84. (2, to_freq(26), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  85. (2, to_freq(38), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  86. (3, to_freq(45), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  87. (3, to_freq(50), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  88. (3, to_freq(57), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  89. (3, to_freq(62), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  90. (3, to_freq(69), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  91. (3, to_freq(74), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  92. (3, to_freq(81), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  93. (3, to_freq(86), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  94. (3, to_freq(90), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt), # Moorer claims this is here, but I'm not sure I believe him
  95. # Below this is the "shit note"
  96. #(2, to_freq(34), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  97. #(2, to_freq(35), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  98. #(2, to_freq(36), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  99. #(2, to_freq(42), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  100. #(3, to_freq(47), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  101. #(3, to_freq(48), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  102. #(3, to_freq(54), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  103. #(3, to_freq(59), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  104. #(3, to_freq(60), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  105. #(3, to_freq(66), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  106. #(3, to_freq(72), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  107. #(3, to_freq(77), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  108. #(3, to_freq(83), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  109. #(3, to_freq(84), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  110. #(3, to_freq(85), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  111. #(3, to_freq(90), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
  112. ],
  113. )
  114. options, args = parser.parse_args()
  115. fund = options.fundamental
  116. smooth_rand_buf = [random.random() for i in range(options.smooth)]
  117. def smooth_rand():
  118. global smooth_rand_buf
  119. rv = sum(smooth_rand_buf) / options.smooth
  120. smooth_rand_buf = [random.random()] + smooth_rand_buf[:-1]
  121. return rv
  122. def smooth_uniform(a, b):
  123. return a + (b-a) * smooth_rand()
  124. def clamp(u, l, h):
  125. return min((h, max((l, u))))
  126. iv = ET.Element('iv')
  127. ivmeta = ET.SubElement(iv, 'meta')
  128. ivstreams = ET.SubElement(iv, 'streams')
  129. for nvoice, freq, fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt in options.targets:
  130. for vn in range(nvoice):
  131. ivstream = ET.SubElement(ivstreams, 'stream', type='ns')
  132. vfadeint = random.uniform(*fadeint)
  133. vinita = random.uniform(*inita)
  134. vrandt = random.uniform(*randt)
  135. vfina = random.uniform(*fina)
  136. vsweept = random.uniform(*sweept)
  137. vfadeoutt = random.uniform(*fadeoutt)
  138. lastf = smooth_uniform(*randf)
  139. if options.verbose:
  140. print '-- setup:', freq, vn, 'fadeint', vfadeint, 'inita', vinita, 'randt', vrandt, 'fina', vfina, 'sweept', vsweept, 'fadeoutt', vfadeoutt, 'lastf', lastf
  141. cntr = 0
  142. for ts in range(int(options.duration / options.resolution)):
  143. tm = ts * options.resolution
  144. if tm < vfadeint:
  145. a = vinita * (tm / vfadeint)
  146. ap = 'fadein'
  147. elif tm < vrandt:
  148. a = vinita
  149. ap = 'inita'
  150. elif tm < vsweept:
  151. u = (clamp((tm - vfadeint - vrandt) / (vsweept - vfadeint - vrandt), 0.0, 1.0)) ** 2
  152. a = u * vfina + (1 - u) * vinita
  153. ap = 'sweep'
  154. else:
  155. a = vfina
  156. ap = 'fina'
  157. if tm > options.duration - vfadeoutt:
  158. a = vfina * max((((options.duration - tm) / vfadeoutt), 0))
  159. ap = 'fadeout'
  160. if tm < vfadeint + vrandt:
  161. lastf = clamp(lastf + smooth_uniform(-fstep, fstep), randf[0], randf[1])
  162. f = lastf
  163. fp = 'rand'
  164. elif tm < vsweept:
  165. u = clamp((tm - vfadeint - vrandt) / (vsweept - vfadeint - vrandt), 0.0, 1.0)
  166. f = u * freq + (1 - u) * lastf
  167. fp = 'sweep'
  168. else:
  169. f = freq * (1.0 + smooth_uniform(-options.chorus, options.chorus))
  170. fp = 'finf'
  171. if options.verbose:
  172. print freq, vn, tm, fp, f, ap, a
  173. ivnote = ET.SubElement(ivstream, 'note',
  174. id = str(cntr),
  175. pitch = str(to_pitch(f)),
  176. ampl = str(a),
  177. time = str(tm),
  178. dur = str(options.resolution + options.slack),
  179. )
  180. cntr += 1
  181. if cntr > 0:
  182. ivnote.set('par', '0')
  183. sys.stdout.write(ET.tostring(iv, 'UTF-8'))