| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- from xml.etree import ElementTree as ET
- import optparse, random, math, sys
- def store_tup(opt, optstr, val, parser, nm, idx, filt=float):
- tup = getattr(parser.values, nm)
- setattr(parser.values, nm, tup[:idx] + (filt(val),) + tup[(idx+1):])
- fund = 440.0
- def to_freq(p):
- return fund * 2.0**((p - 69) / 12.0)
- def to_pitch(f):
- try:
- return 12 * math.log(f / fund, 2) + 69
- except ValueError:
- print 'bad frequency', f
- raise
- def store_target(opt, optstr, val, parser):
- print 'opt', opt, 'optstr', optstr, 'val', val, 'parser', parser
- if val.startswith('@'):
- val = int(val[1:])
- else:
- val = int(to_freq(float(val)))
- parser.values.targets.append((
- parser.values.voices,
- val,
- parser.values.fadeint,
- parser.values.inita,
- parser.values.randt,
- parser.values.randf,
- parser.values.fstep,
- parser.values.fina,
- parser.values.sweept,
- parser.values.fadeoutt
- ))
- parser = optparse.OptionParser()
- parser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='Be verbose')
- parser.add_option('-V', '--voices', dest='voices', type='int', help='Subsequent -t will have this many voices directed toward it')
- 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')
- 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')
- 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')
- 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')
- parser.add_option('--randtlow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('randt', 0), help='Low random time for subsequent -t')
- parser.add_option('--randthigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('randf', 1), help='High random time for subsequent -t')
- parser.add_option('--randflow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('randf', 0), help='Low random freq for subsequent -t')
- parser.add_option('--randfhigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('randt', 1), help='High random freq for subsequent -t')
- parser.add_option('--fstep', dest='fstep', type='float', help='Frequency to wander by in random phase')
- 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')
- 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')
- parser.add_option('--sweeplow', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('sweept', 0), help='Low sweep time for subsequent -t')
- parser.add_option('--sweephigh', action='callback', nargs=1, type='float', callback=store_tup, callback_args=('sweept', 1), help='High sweep time for subsequent -t')
- 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')
- 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')
- parser.add_option('-t', '--target', action='callback', type='str', callback=store_target, nargs=1, help='Have some voices target this MIDI pitch or @frequency')
- parser.add_option('-C', '--clear-targets', action='store_const', const=[], dest='targets', help='Clear all targets (including built in ones) prior')
- parser.add_option('-r', '--resolution', dest='resolution', type='float', help='Period of generated samples')
- parser.add_option('-c', '--chorus', dest='chorus', type='float', help='Random variation of frequency (factor)')
- parser.add_option('--smooth', dest='smooth', type='int', help='Number of random uniform samples to perform to smooth')
- parser.add_option('-D', '--duration', dest='duration', type='float', help='Length of the note')
- parser.add_option('--slack', dest='slack', type='float', help='Slack added to duration to overcommit clients')
- parser.add_option('--fundamental', dest='fundamental', type='float', help='Frequency of the A above middle C (traditionally 440 Hz)')
- fadeint = (4.0, 6.0)
- inita = (0.1, 0.2)
- randt = (8.5, 9.0)
- fina = (0.95, 1.0)
- sweept = (17.5, 19.0)
- fadeoutt = (1.5, 3.5)
- randf = (200, 400)
- fstep = 5
- parser.set_defaults(
- resolution = 0.05,
- chorus = 0.02,
- smooth = 5,
- duration = 30.0,
- slack = 0.02,
- fundamental = 430.0,
- voices = 1,
- fadeint = fadeint,
- inita = inita,
- randt = randt,
- fina = fina,
- sweept = sweept,
- fadeoutt = fadeoutt,
- randf = randf,
- fstep = fstep,
- targets = [
- (2, to_freq(26), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (2, to_freq(38), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (3, to_freq(45), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (3, to_freq(50), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (3, to_freq(57), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (3, to_freq(62), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (3, to_freq(69), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (3, to_freq(74), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (3, to_freq(81), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (3, to_freq(86), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- (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
- # Below this is the "shit note"
- #(2, to_freq(34), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(2, to_freq(35), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(2, to_freq(36), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(2, to_freq(42), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(47), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(48), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(54), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(59), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(60), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(66), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(72), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(77), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(83), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(84), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(85), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- #(3, to_freq(90), fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt),
- ],
- )
- options, args = parser.parse_args()
- fund = options.fundamental
- smooth_rand_buf = [random.random() for i in range(options.smooth)]
- def smooth_rand():
- global smooth_rand_buf
- rv = sum(smooth_rand_buf) / options.smooth
- smooth_rand_buf = [random.random()] + smooth_rand_buf[:-1]
- return rv
- def smooth_uniform(a, b):
- return a + (b-a) * smooth_rand()
- def clamp(u, l, h):
- return min((h, max((l, u))))
- iv = ET.Element('iv')
- ivmeta = ET.SubElement(iv, 'meta')
- ivstreams = ET.SubElement(iv, 'streams')
- for nvoice, freq, fadeint, inita, randt, randf, fstep, fina, sweept, fadeoutt in options.targets:
- for vn in range(nvoice):
- ivstream = ET.SubElement(ivstreams, 'stream', type='ns')
- vfadeint = random.uniform(*fadeint)
- vinita = random.uniform(*inita)
- vrandt = random.uniform(*randt)
- vfina = random.uniform(*fina)
- vsweept = random.uniform(*sweept)
- vfadeoutt = random.uniform(*fadeoutt)
- lastf = smooth_uniform(*randf)
- if options.verbose:
- print '-- setup:', freq, vn, 'fadeint', vfadeint, 'inita', vinita, 'randt', vrandt, 'fina', vfina, 'sweept', vsweept, 'fadeoutt', vfadeoutt, 'lastf', lastf
- cntr = 0
- for ts in range(int(options.duration / options.resolution)):
- tm = ts * options.resolution
- if tm < vfadeint:
- a = vinita * (tm / vfadeint)
- ap = 'fadein'
- elif tm < vrandt:
- a = vinita
- ap = 'inita'
- elif tm < vsweept:
- u = (clamp((tm - vfadeint - vrandt) / (vsweept - vfadeint - vrandt), 0.0, 1.0)) ** 2
- a = u * vfina + (1 - u) * vinita
- ap = 'sweep'
- else:
- a = vfina
- ap = 'fina'
- if tm > options.duration - vfadeoutt:
- a = vfina * max((((options.duration - tm) / vfadeoutt), 0))
- ap = 'fadeout'
- if tm < vfadeint + vrandt:
- lastf = clamp(lastf + smooth_uniform(-fstep, fstep), randf[0], randf[1])
- f = lastf
- fp = 'rand'
- elif tm < vsweept:
- u = clamp((tm - vfadeint - vrandt) / (vsweept - vfadeint - vrandt), 0.0, 1.0)
- f = u * freq + (1 - u) * lastf
- fp = 'sweep'
- else:
- f = freq * (1.0 + smooth_uniform(-options.chorus, options.chorus))
- fp = 'finf'
- if options.verbose:
- print freq, vn, tm, fp, f, ap, a
- ivnote = ET.SubElement(ivstream, 'note',
- id = str(cntr),
- pitch = str(to_pitch(f)),
- ampl = str(a),
- time = str(tm),
- dur = str(options.resolution + options.slack),
- )
- cntr += 1
- if cntr > 0:
- ivnote.set('par', '0')
- sys.stdout.write(ET.tostring(iv, 'UTF-8'))
|