Forráskód Böngészése

Added bind addr, drums can use render

Graham Northup 6 éve
szülő
commit
8504e47390
2 módosított fájl, 70 hozzáadás és 2 törlés
  1. 2 1
      client.py
  2. 68 1
      drums.py

+ 2 - 1
client.py

@@ -33,6 +33,7 @@ parser.add_option('-N', '--numpy', dest='numpy', action='store_true', help='Use
 parser.add_option('-G', '--gui', dest='gui', default='', help='set a GUI to use')
 parser.add_option('-c', '--clamp', dest='clamp', action='store_true', help='Clamp over-the-wire amplitudes to 0.0-1.0')
 parser.add_option('-C', '--chorus', dest='chorus', default=0.0, type='float', help='Apply uniform random offsets (in MIDI pitch space)')
+parser.add_option('-B', '--bind', dest='bind_addr', default='', help='Bind to this address')
 parser.add_option('--amp-exp', dest='amp_exp', default=2.0, type='float', help='Raise floating amplitude to this power before computing raw amplitude')
 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')
@@ -640,7 +641,7 @@ if options.test:
     exit()
 
 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-sock.bind(('', PORT))
+sock.bind((options.bind_addr, PORT))
 
 #signal.signal(signal.SIGALRM, sigalrm)
 

+ 68 - 1
drums.py

@@ -7,6 +7,11 @@ import cStringIO as StringIO
 import array
 import time
 import colorsys
+import struct
+import mmap
+import threading
+import os
+import atexit
 
 from packet import Packet, CMD, stoi, OBLIGATE_POLYPHONE
 
@@ -18,6 +23,8 @@ parser.add_option('-r', '--rate', dest='rate', type='int', default=44100, help='
 parser.add_option('-u', '--uid', dest='uid', default='', help='User identifier of this client')
 parser.add_option('-p', '--port', dest='port', default=13677, type='int', help='UDP port to listen on')
 parser.add_option('-c', '--clamp', dest='clamp', action='store_true', help='Clamp over-the-wire amplitudes to 0.0-1.0')
+parser.add_option('-B', '--bind', dest='bind_addr', default='', help='Bind to this address')
+parser.add_option('-G', '--gui', dest='gui', help='Use a GUI')
 parser.add_option('--amp-exp', dest='amp_exp', default=2.0, type='float', help='Raise floating amplitude to this power before computing raw amplitude')
 parser.add_option('--repeat', dest='repeat', action='store_true', help='If a note plays longer than a sample length, keep playing the sample')
 parser.add_option('--cut', dest='cut', action='store_true', help='If a note ends within a sample, stop playing that sample immediately')
@@ -25,6 +32,9 @@ parser.add_option('-n', '--max-voices', dest='max_voices', default=-1, type='int
 parser.add_option('--pg-low-freq', dest='low_freq', type='int', default=40, help='Low frequency for colored background')
 parser.add_option('--pg-high-freq', dest='high_freq', type='int', default=1500, help='High frequency for colored background')
 parser.add_option('--pg-log-base', dest='log_base', type='int', default=2, help='Logarithmic base for coloring (0 to make linear)')
+parser.add_option('--map-file', dest='map_file', default='client_map', help='File mapped by -G mapped (contains u32 frequency, f32 amplitude pairs for each voice)')
+parser.add_option('--map-interval', dest='map_interval', type='float', default=0.02, help='Period in seconds between refreshes of the map')
+parser.add_option('--map-samples', dest='map_samples', type='int', default=4096, help='Number of samples in the map file (MUST agree with renderer)')
 parser.add_option('--counter-modulus', dest='counter_modulus', type='int', default=16, help='Number of packet events in period of the terminal color scroll on the left margin')
 
 options, args = parser.parse_args()
@@ -33,6 +43,11 @@ MAX = 0x7fffffff
 MIN = -0x80000000
 IDENT = 'DRUM'
 
+LAST_SAMPLES = []
+FREQS = [0]
+AMPS = [0]
+STREAMS = 1
+
 if not args:
     print 'Need at least one drumpack (.tar.bz2) as an argument!'
     parser.print_usage()
@@ -49,6 +64,52 @@ def rgb_for_freq_amp(f, a):
     bgcol = colorsys.hls_to_rgb(min((1.0, max((0.0, pitchval)))), 0.5 * (a ** 2), 1.0)
     return [int(i*255) for i in bgcol]
 
+# GUIs
+
+GUIs = {}
+
+def GUI(f):
+    GUIs[f.__name__] = f
+    return f
+
+@GUI
+def mapped():
+    if os.path.exists(options.map_file):
+        raise ValueError('Refusing to map file--already exists!')
+    ms = options.map_samples
+    stm = options.map_interval
+    fixfmt = '>f'
+    fixfmtsz = struct.calcsize(fixfmt)
+    sigfmt = '>' + 'f' * ms
+    sigfmtsz = struct.calcsize(sigfmt)
+    strfmt = '>' + 'Lf' * STREAMS
+    strfmtsz = struct.calcsize(strfmt)
+    sz = sum((fixfmtsz, sigfmtsz, strfmtsz))
+    print 'Reserving', sz, 'in map file'
+    print 'Size triple:', fixfmtsz, sigfmtsz, strfmtsz
+    f = open(options.map_file, 'w+')
+    f.seek(sz - 1)
+    f.write('\0')
+    f.flush()
+    mapping = mmap.mmap(f.fileno(), sz, access=mmap.ACCESS_WRITE)
+    f.close()
+    atexit.register(os.unlink, options.map_file)
+    def unzip2(i):
+        for a, b in i:
+            yield a
+            yield b
+    while True:
+        mapping[:fixfmtsz] = struct.pack(fixfmt, 0.0)
+        mapping[fixfmtsz:fixfmtsz+sigfmtsz] = struct.pack(sigfmt, *(float(LAST_SAMPLES[i])/MAX if i < len(LAST_SAMPLES) else 0.0 for i in xrange(ms)))
+        mapping[fixfmtsz+sigfmtsz:] = struct.pack(strfmt, *unzip2((FREQS[i], AMPS[i]) for i in xrange(STREAMS)))
+        del LAST_SAMPLES[:]
+        time.sleep(stm)
+
+if options.gui:
+    guithread = threading.Thread(target=GUIs[options.gui])
+    guithread.setDaemon(True)
+    guithread.start()
+
 DRUMS = {}
 
 for fname in args:
@@ -131,6 +192,8 @@ def gen_data(data, frames, tm, status):
     for i in range(frames):
         fdata[i] = max(MIN, min(MAX, fdata[i]))
     fdata = array.array('i', fdata)
+    AMPS[0] = (float(sum(abs(i) for i in fdata)) / (len(fdata) * MAX))**0.25
+    LAST_SAMPLES.extend(fdata)
     return (fdata.tostring(), pyaudio.paContinue)
 
 pa = pyaudio.PyAudio()
@@ -141,6 +204,8 @@ if options.test:
         print 'Current playing:', PLAYING
         print 'Playing:', frq
         data = DRUMS[frq]
+        FREQS[0] = frq
+        AMPS[0] = 1.0
         PLAYING.append(SampleReader(data, len(data), options.volume))
         time.sleep(len(data) / (4.0 * options.rate))
     print 'Done'
@@ -148,7 +213,7 @@ if options.test:
 
 
 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-sock.bind(('', options.port))
+sock.bind((options.bind_addr, options.port))
 
 #signal.signal(signal.SIGALRM, sigalrm)
 
@@ -189,6 +254,8 @@ while True:
         amp = options.volume * pkt.as_float(3)
         if options.clamp:
             amp = max(min(amp, 1.0), 0.0)
+        FREQS[0] = frq
+        AMPS[0] = amp
         PLAYING.append(SampleReader(rdata, dframes * 4, amp**options.amp_exp))
         if options.max_voices >= 0:
             while len(PLAYING) > options.max_voices: