utils/pianoroll-client.py
changeset 93 79ae42ad97d4
parent 85 eff9460bd4f2
equal deleted inserted replaced
87:9611905b58fe 93:79ae42ad97d4
     5 This example is in the public domain.
     5 This example is in the public domain.
     6 """
     6 """
     7 
     7 
     8 import argparse
     8 import argparse
     9 import csv
     9 import csv
       
    10 import signal
    10 import time
    11 import time
    11 
    12 
    12 import ntplib
    13 import ntplib
    13 from twisted.internet import reactor
    14 from twisted.internet import reactor
    14 from txosc import osc
    15 from txosc import osc
    17 
    18 
    18 class UDPSenderApplication(object):
    19 class UDPSenderApplication(object):
    19     """
    20     """
    20     Example that sends UDP messages.
    21     Example that sends UDP messages.
    21     """
    22     """
    22     def __init__(self, port, host, address, rows, shift):
    23     def __init__(self, port, host, address, rows, shift, token):
    23         self.port = port
    24         self.port = port
    24         self.host = host
    25         self.host = host
    25         self.client = async.DatagramClientProtocol()
    26         self.client = async.DatagramClientProtocol()
    26         self._client_port = reactor.listenUDP(0, self.client)
    27         self._client_port = reactor.listenUDP(0, self.client)
    27         self.rows = rows
    28         self.rows = rows
    28         self.address = address
    29         self.address = address
    29         self.shift = shift
    30         self.shift = shift
       
    31         self.token = token
    30         reactor.callLater(0, self.send_messages)
    32         reactor.callLater(0, self.send_messages)
    31 
    33 
    32     def _send(self, element):
    34     def _send(self, element):
    33         # This method is defined only to simplify the example
    35         # This method is defined only to simplify the example
    34         self.client.send(element, (self.host, self.port))
    36         self.client.send(element, (self.host, self.port))
    35         print("Sent %s to %s:%d" % (element, self.host, self.port))
    37         print("Sent %s to %s:%d" % (element, self.host, self.port))
    36 
    38 
    37     def send_messages(self):
    39     def send_messages(self):
    38         t0 = time.time()
    40         t0 = time.time()
       
    41         #tc = 0
    39         for row in self.rows:
    42         for row in self.rows:
       
    43             if not self.token.running:
       
    44                 break
    40             if self.shift:
    45             if self.shift:
    41                 row[0] = ntplib.system_to_ntp_time(t0 + float(row[1])/10**3)
    46                 row[0] = ntplib.system_to_ntp_time(t0 + float(row[1])/1000.0)
    42             row_conv = [ osc.TimeTagArgument(float(row[0]))] + [osc.IntArgument(int(a)) for a in row[1:]]
    47             row_conv = [ osc.TimeTagArgument(float(row[0]))] + [osc.IntArgument(int(a)) for a in row[1:]]
    43             #time.sleep((row_conv[1].value-tc)/10**3)
    48             #time.sleep((row_conv[1].value-tc)/1000.0)
    44             time.sleep(0.1)
    49             sleep_time = t0+float(row[1])/1000.0-time.time()
    45             #tc = row_conv[1].value
    50             if sleep_time > 0:
       
    51                 time.sleep(sleep_time)
       
    52             #time.sleep(0.1)
       
    53             tc = row_conv[1].value
    46             self._send(osc.Message(self.address,*row_conv))
    54             self._send(osc.Message(self.address,*row_conv))
    47         print("Goodbye.")
    55         print("Goodbye.")
    48         reactor.callLater(0.1, reactor.stop)
    56         reactor.callLater(0.1, reactor.stop)
    49 
    57 
       
    58 class Token(object):
       
    59     def __init__(self):
       
    60         self.running = True
       
    61 
    50 if __name__ == "__main__":
    62 if __name__ == "__main__":
       
    63 
       
    64     token = Token()
    51 
    65 
    52     parser = argparse.ArgumentParser(description='Simulate an (osc) pianoroll client.')
    66     parser = argparse.ArgumentParser(description='Simulate an (osc) pianoroll client.')
    53     parser.add_argument('datafile', metavar='DATAFILE', help='The file containing the pianoroll data (CSV).')
    67     parser.add_argument('datafile', metavar='DATAFILE', help='The file containing the pianoroll data (CSV).')
    54     parser.add_argument('-e', '--event', dest='event', metavar='EVENT', required=True, help='the event code.')
    68     parser.add_argument('-e', '--event', dest='event', metavar='EVENT', required=True, help='the event code.')
    55     parser.add_argument('-s', '--shift', dest='shift', action='store_true', required=False, help='Shift the data.', default=False)
    69     parser.add_argument('-s', '--shift', dest='shift', action='store_true', required=False, help='Shift the data.', default=False)
    56 
    70 
    57     args = parser.parse_args()
    71     args = parser.parse_args()
    58 
    72 
       
    73     def customHandler(signum, _):
       
    74         print("Got signal: %s" % signum)
       
    75         token.running = False
       
    76         if reactor.running:
       
    77             reactor.callFromThread(reactor.stop) # to stop twisted code when in the reactor loop
       
    78     signal.signal(signal.SIGINT, customHandler)
       
    79 
       
    80 
    59     with open(args.datafile, 'rU') as datafile:
    81     with open(args.datafile, 'rU') as datafile:
    60         reader = csv.reader(datafile, delimiter=' ')
    82         reader = csv.reader(datafile, delimiter=' ')
    61         app = UDPSenderApplication(9090, "127.0.0.1", "/pianoroll/%s/" % args.event, list(reader), args.shift)
    83         app = UDPSenderApplication(9090, "127.0.0.1", "/pianoroll/%s/" % args.event, list(reader), args.shift, token)
    62 
    84 
    63     reactor.run()
    85     reactor.run()