diff options
| author | Graham Northup <grissess@nexusg.org> | 2018-09-24 16:08:35 -0400 | 
|---|---|---|
| committer | Graham Northup <grissess@nexusg.org> | 2018-09-24 16:08:35 -0400 | 
| commit | ec177bb81a2a6ab54e05118066364281ebccc318 (patch) | |
| tree | 18c025d023b6fe06bdca8a641619c8bdc8e95518 | |
| parent | 5c205fd148900dc787c99a4ce1898a49abfd901d (diff) | |
oof
| -rw-r--r-- | client.py | 58 | ||||
| -rw-r--r-- | mkiv.py | 10 | 
2 files changed, 52 insertions, 16 deletions
| @@ -32,6 +32,7 @@ parser.add_option('-c', '--clamp', dest='clamp', action='store_true', help='Clam  parser.add_option('-C', '--chorus', dest='chorus', default=0.0, type='float', help='Apply uniform random offsets (in MIDI pitch space)')  parser.add_option('--vibrato', dest='vibrato', default=0.0, type='float', help='Apply periodic perturbances in pitch space by this amplitude (in MIDI pitches)')  parser.add_option('--vibrato-freq', dest='vibrato_freq', default=6.0, type='float', help='Frequency of the vibrato perturbances in Hz') +parser.add_option('--fmul', dest='fmul', default=1.0, type='float', help='Multiply requested frequencies by this amount')  parser.add_option('--pg-fullscreen', dest='fullscreen', action='store_true', help='Use a full-screen video mode')  parser.add_option('--pg-samp-width', dest='samp_width', type='int', help='Set the width of the sample pane (by default display width / 2)')  parser.add_option('--pg-bgr-width', dest='bgr_width', type='int', help='Set the width of the bargraph pane (by default display width / 2)') @@ -72,6 +73,9 @@ DRIFT_FACTOR = 1.0  DRIFT_ERROR = 0.0  LAST_SYN = None +CUR_PERIODS = [0] * STREAMS +CUR_PERIOD = 0.0 +  def lin_interp(frm, to, p):      return p*to + (1-p)*frm @@ -245,23 +249,41 @@ def square_wave(theta):  def noise(theta):      return random.random() * 2 - 1 -@generator('File generator', '(<file>[, <bits=8>[, <signed=True>[, <0=linear interp (default), 1=nearest>[, <swapbytes=False>]]]])') +@generator('File generator', '(<file>[, <bits=8>[, <signed=True>[, <0=linear interp (default), 1=nearest>[, <swapbytes=False>[, <loop=(fraction to loop, 0.0 is all, 1.0 is end, or False to not loop)>[, <loopend=1.0>[, periods=1 (periods in wave file)/freq=None (base frequency)/pitch=None (base MIDI pitch)]]]]]]])')  class file_samp(object):      LINEAR = 0      NEAREST = 1      TYPES = {8: 'B', 16: 'H', 32: 'L'} -    def __init__(self, fname, bits=8, signed=True, samp=LINEAR, swab=False): +    def __init__(self, fname, bits=8, signed=True, samp=LINEAR, swab=False, loop=0.0, loopend=1.0, periods=1.0, freq=None, pitch=None):          tp = self.TYPES[bits]          if signed:              tp = tp.lower()          self.max = float((2 << bits) - 1) +        if signed: +            self.max /= 2.0          self.buffer = array.array(tp)          self.buffer.fromstring(open(fname, 'rb').read())          if swab:              self.buffer.byteswap()          self.samp = samp +        self.loop = loop +        self.loopend = loopend +        self.periods = periods +        if pitch is not None: +            freq = 440.0 * 2 ** ((pitch - 69) / 12.0) +        if freq is not None: +            self.periods = freq * len(self.buffer) / RATE +        print 'file_samp periods:', self.periods, 'freq:', freq, 'pitch:', pitch      def __call__(self, theta): -        norm = theta / (2*math.pi) +        full_norm = CUR_PERIOD / (2*self.periods*math.pi) +        if full_norm > 1.0: +            if self.loop is False: +                return self.buffer[0] +            else: +                norm = (full_norm - 1.0) / (self.loopend - self.loop) % 1.0 * (self.loopend - self.loop) + self.loop +        else: +            norm = full_norm +        norm %= 1.0          if self.samp == self.LINEAR:              v = norm*len(self.buffer)              l = int(math.floor(v)) @@ -411,13 +433,14 @@ if options.numpy:          return numpy.linspace(frm, to, cnt, dtype=numpy.int32)      def samps(freq, amp, phase, cnt): +        global CUR_PERIOD          samps = numpy.ndarray((cnt,), numpy.int32)          pvel = 2 * math.pi * freq / RATE          fac = options.volume * amp / float(STREAMS)          for i in xrange(cnt): -            samps[i] = fac * max(-1, min(1, generator(phase))) -            phase = (phase + pvel) % (2 * math.pi) -        return samps, phase +            samps[i] = fac * max(-1, min(1, generator((phase + i * pvel) % (2*math.pi)))) +            CUR_PERIOD += pvel +        return samps, phase + pvel * cnt      def to_data(samps):          return samps.tobytes() @@ -439,11 +462,13 @@ else:          return samps      def samps(freq, amp, phase, cnt): -        global RATE +        global RATE, CUR_PERIOD          samps = [0]*cnt          for i in xrange(cnt): -            samps[i] = int(2*amp / float(STREAMS) * max(-1, min(1, options.volume*generator((phase + 2 * math.pi * freq * i / RATE) % (2*math.pi))))) -        return samps, (phase + 2 * math.pi * freq * cnt / RATE) % (2*math.pi) +            samps[i] = int(amp / float(STREAMS) * max(-1, min(1, options.volume*generator((phase + 2 * math.pi * freq * i / RATE) % (2*math.pi))))) +            CUR_PERIOD += 2 * math.pi * freq / RATE +        next_phase = (phase + 2 * math.pi * freq * cnt / RATE) +        return samps, next_phase      def to_data(samps):          return struct.pack('i'*len(samps), *samps) @@ -468,7 +493,7 @@ else:          return struct.pack(str(amt)+'i', *out)  def gen_data(data, frames, tm, status): -    global FREQS, PHASE, Z_SAMP, LAST_SAMP, LAST_SAMPLES, QUEUED_PCM, DRIFT_FACTOR, DRIFT_ERROR +    global FREQS, PHASE, Z_SAMP, LAST_SAMP, LAST_SAMPLES, QUEUED_PCM, DRIFT_FACTOR, DRIFT_ERROR, CUR_PERIOD      if len(QUEUED_PCM) >= frames*4:          desired_frames = DRIFT_FACTOR * frames          err_frames = desired_frames - int(desired_frames) @@ -497,6 +522,7 @@ def gen_data(data, frames, tm, status):          AMP = AMPS[i]          EXPIRATION = EXPIRATIONS[i]          PHASE = PHASES[i] +        CUR_PERIOD = CUR_PERIODS[i]          if FREQ != 0:              if time.time() > EXPIRATION:                  FREQ = 0 @@ -507,9 +533,11 @@ def gen_data(data, frames, tm, status):                  fdata = mix(fdata, vdata)                  LAST_SAMPS[i] = vdata[-1]          else: -            vdata, PHASE = samps(FREQ, AMP, PHASE, frames) +            vdata, CUR_PERIOD = samps(FREQ, AMP, CUR_PERIOD, frames) +            PHASE = (PHASE + CUR_PERIOD) % (2 * math.pi)              fdata = mix(fdata, vdata)              PHASES[i] = PHASE +            CUR_PERIODS[i] = CUR_PERIOD              LAST_SAMPS[i] = vdata[-1]      if options.gui:          LAST_SAMPLES.extend(fdata) @@ -526,14 +554,17 @@ if options.gui:  if options.test:      FREQS[0] = 440      EXPIRATIONS[0] = time.time() + 1 +    CUR_PERIODS[0] = 0.0      time.sleep(1)      FREQS[0] = 0      time.sleep(1)      FREQS[0] = 880      EXPIRATIONS[0] = time.time() + 1 +    CUR_PERIODS[0] = 0.0      time.sleep(1)      FREQS[0] = 440      EXPIRATIONS[0] = time.time() + 2 +    CUR_PERIODS[0] = 0.0      time.sleep(2)      exit() @@ -567,12 +598,13 @@ while True:      elif pkt.cmd == CMD.PLAY:          voice = pkt.data[4]          dur = pkt.data[0]+pkt.data[1]/1000000.0 -        freq = pkt.data[2] +        freq = pkt.data[2] * options.fmul          if options.chorus > 0:              midi = 12 * math.log(freq / 440.0, 2) + 69              midi += (random.random() * 2 - 1) * options.chorus              freq = 440.0 * 2 ** ((midi - 69) / 12)          FREQS[voice] = freq +        CUR_PERIODS[voice] = 0.0          amp = pkt.as_float(3)          if options.clamp:              amp = max(min(amp, 1.0), 0.0) @@ -588,7 +620,7 @@ while True:          if pkt.data[5] & PLF.SAMEPHASE:              print '\x1b[1;37mSAMEPHASE',          if pkt.data[0] == 0 and pkt.data[1] == 0: -            print '\x1b[1;35mSTOP!!!' +            print '\x1b[1;31mSTOP!!!'          else:              print '\x1b[1;36mDUR', '%08.6f'%dur          #signal.setitimer(signal.ITIMER_REAL, dur) @@ -27,6 +27,7 @@ parser.add_option('-p', '--program-split', dest='tracks', action='append_const',  parser.add_option('-P', '--percussion', dest='perc', help='Which percussion standard to use to automatically filter to "perc" (GM, GM2, or none)')  parser.add_option('-f', '--fuckit', dest='fuckit', action='store_true', help='Use the Python Error Steamroller when importing MIDIs (useful for extended formats)')  parser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='Be verbose; show important parts about the MIDI scheduling process') +parser.add_option('-q', '--quiet', dest='quiet', action='store_true', help='Be quiet; don\'t log certain high-volume outputs')  parser.add_option('-d', '--debug', dest='debug', action='store_true', help='Debugging output; show excessive output about the MIDI scheduling process (please use less or write to a file)')  parser.add_option('-D', '--deviation', dest='deviation', type='int', help='Amount (in semitones/MIDI pitch units) by which a fully deflected pitchbend modifies the base pitch (0 disables pitchbend processing)')  parser.add_option('-M', '--modwheel-freq-dev', dest='modfdev', type='float', help='Amount (in semitones/MIDI pitch unites) by which a fully-activated modwheel modifies the base pitch') @@ -485,7 +486,8 @@ for fname in args:                  if found:                      break              else: -                print 'WARNING: Did not match %r with any stream deactivation.'%(mev,) +                if not options.quiet: +                    print 'WARNING: Did not match %r with any stream deactivation.'%(mev,)                  if options.verbose:                      print '  Current state:'                      for group in notegroups: @@ -503,7 +505,8 @@ for fname in args:                          stream.Activate(base, base.ev.pitch + options.deviation * (mev.ev.pitch / float(0x2000)), parent=old)                          found = True              if not found: -                print 'WARNING: Did not find any matching active streams for %r'%(mev,) +                if not options.quiet: +                    print 'WARNING: Did not find any matching active streams for %r'%(mev,)                  if options.verbose:                      print '  Current state:'                      for group in notegroups: @@ -521,7 +524,8 @@ for fname in args:                          stream.Activate(base, stream.bentpitch, mev.mw, parent=old)                          found = True              if not found: -                print 'WARNING: Did not find any matching active streams for %r'%(mev,) +                if not options.quiet: +                    print 'WARNING: Did not find any matching active streams for %r'%(mev,)                  if options.verbose:                      print '  Current state:'                      for group in notegroups: | 
