Browse Source

GUI and bind addresses

Grissess 9 years ago
parent
commit
5eb8269872
2 changed files with 89 additions and 2 deletions
  1. 7 1
      broadcast.py
  2. 82 1
      client.py

+ 7 - 1
broadcast.py

@@ -29,8 +29,9 @@ parser.add_option('-f', '--factor', dest='factor', type='float', help='Rescale t
 parser.add_option('-r', '--route', dest='routes', action='append', help='Add a routing directive (see --route-help)')
 parser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='Be verbose; dump events and actual time (can slow down performance!)')
 parser.add_option('-W', '--wait-time', dest='wait_time', type='float', help='How long to wait for clients to initially respond (delays all broadcasts)')
+parser.add_option('-B', '--bind-addr', dest='bind_addr', help='The IP address (or IP:port) to bind to (influences the network to send to)')
 parser.add_option('--help-routes', dest='help_routes', action='store_true', help='Show help about routing directives')
-parser.set_defaults(routes=[], random=0.0, rand_low=80, rand_high=2000, live=None, factor=1.0, duration=1.0, volume=255, wait_time=0.25, play=[], transpose=0, seek=0.0)
+parser.set_defaults(routes=[], random=0.0, rand_low=80, rand_high=2000, live=None, factor=1.0, duration=1.0, volume=255, wait_time=0.25, play=[], transpose=0, seek=0.0, bind_addr='')
 options, args = parser.parse_args()
 
 if options.help_routes:
@@ -56,6 +57,11 @@ print 'Factor:', factor
 
 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
+if options.bind_addr:
+    addr, _, port = options.bind_addr.partition(':')
+    if not port:
+        port = '12074'
+    s.bind((addr, int(port)))
 
 clients = []
 uid_groups = {}

+ 82 - 1
client.py

@@ -11,6 +11,7 @@ import socket
 import optparse
 import array
 import random
+import threading
 
 from packet import Packet, CMD, stoi
 
@@ -22,6 +23,7 @@ parser.add_option('-u', '--uid', dest='uid', default='', help='Set the UID (iden
 parser.add_option('-p', '--port', dest='port', type='int', default=13676, help='Set the port to listen on')
 parser.add_option('-r', '--rate', dest='rate', type='int', default=44100, help='Set the sample rate of the audio device')
 parser.add_option('-V', '--volume', dest='volume', type='float', default=1.0, help='Set the volume factor (>1 distorts, <1 attenuates)')
+parser.add_option('-G', '--gui', dest='gui', default='', help='set a GUI to use')
 
 options, args = parser.parse_args()
 
@@ -31,6 +33,7 @@ IDENT = 'TONE'
 UID = options.uid
 
 LAST_SAMP = 0
+LAST_SAMPLES = []
 FREQ = 0
 PHASE = 0
 RATE = options.rate
@@ -44,6 +47,77 @@ MIN = -0x80000000
 def lin_interp(frm, to, p):
     return p*to + (1-p)*frm
 
+# GUIs
+
+GUIs = {}
+
+def GUI(f):
+    GUIs[f.__name__] = f
+    return f
+
+@GUI
+def pygame_notes():
+    import pygame
+    import pygame.gfxdraw
+    pygame.init()
+
+    SAMP_WIDTH = 512
+    BGR_WIDTH = 512
+    HEIGHT = 1024
+
+    disp = pygame.display.set_mode((SAMP_WIDTH + BGR_WIDTH, HEIGHT))
+
+    WIDTH, HEIGHT = disp.get_size()
+    SAMP_WIDTH = WIDTH / 2
+    BGR_WIDTH = WIDTH - SAMP_WIDTH
+    PFAC = HEIGHT / 128.0
+
+    sampwin = pygame.Surface((SAMP_WIDTH, HEIGHT))
+    lastsy = HEIGHT / 2
+
+    clock = pygame.time.Clock()
+
+    while True:
+        if FREQ > 0:
+            try:
+                pitch = 12 * math.log(FREQ / 440.0, 2) + 69
+            except ValueError:
+                pitch = 0
+        else:
+            pitch = 0
+        col = [int((AMP / MAX) * 255)] * 3
+
+        disp.fill((0, 0, 0), (BGR_WIDTH, 0, SAMP_WIDTH, HEIGHT))
+        disp.scroll(-1, 0)
+        disp.fill(col, (BGR_WIDTH - 1, HEIGHT - pitch * PFAC - PFAC, 1, PFAC))
+
+        sampwin.scroll(-len(LAST_SAMPLES), 0)
+        x = max(0, SAMP_WIDTH - len(LAST_SAMPLES))
+        sampwin.fill((0, 0, 0), (x, 0, SAMP_WIDTH - x, HEIGHT))
+        for i in LAST_SAMPLES:
+            sy = int((float(i) / MAX) * (HEIGHT / 2) + (HEIGHT / 2))
+            pygame.gfxdraw.line(sampwin, x - 1, lastsy, x, sy, (0, 255, 0))
+            x += 1
+            lastsy = sy
+        del LAST_SAMPLES[:]
+        #w, h = SAMP_WIDTH, HEIGHT
+        #pts = [(BGR_WIDTH, HEIGHT / 2), (w + BGR_WIDTH, HEIGHT / 2)]
+        #x = w + BGR_WIDTH
+        #for i in reversed(LAST_SAMPLES):
+        #    pts.insert(1, (x, int((h / 2) + (float(i) / MAX) * (h / 2))))
+        #    x -= 1
+        #    if x < BGR_WIDTH:
+        #        break
+        #if len(pts) > 2:
+        #    pygame.gfxdraw.aapolygon(disp, pts, [0, 255, 0])
+        disp.blit(sampwin, (BGR_WIDTH, 0))
+        pygame.display.flip()
+
+        for i in pygame.event.get():
+            pass  # Todo
+
+        clock.tick(60)
+
 # Generator functions--should be cyclic within [0, 2*math.pi) and return [-1, 1]
 
 GENERATORS = [{'name': 'math.sin', 'args': None, 'desc': 'Sine function'},
@@ -179,7 +253,7 @@ def to_data(samps):
     return struct.pack('i'*len(samps), *samps)
 
 def gen_data(data, frames, time, status):
-    global FREQ, PHASE, Z_SAMP, LAST_SAMP
+    global FREQ, PHASE, Z_SAMP, LAST_SAMP, LAST_SAMPLES
     if FREQ == 0:
         PHASE = 0
         if LAST_SAMP == 0:
@@ -188,12 +262,19 @@ def gen_data(data, frames, time, status):
         LAST_SAMP = fdata[-1]
         return (to_data(fdata), pyaudio.paContinue)
     fdata, PHASE = samps(FREQ, PHASE, frames)
+    if options.gui:
+        LAST_SAMPLES.extend(fdata)
     LAST_SAMP = fdata[-1]
     return (to_data(fdata), pyaudio.paContinue)
 
 pa = pyaudio.PyAudio()
 stream = pa.open(rate=RATE, channels=1, format=pyaudio.paInt32, output=True, frames_per_buffer=FPB, stream_callback=gen_data)
 
+if options.gui:
+    guithread = threading.Thread(target=GUIs[options.gui])
+    guithread.setDaemon(True)
+    guithread.start()
+
 if options.test:
     FREQ = 440
     time.sleep(1)