comparison tim_grid_mapper/grid_mapper.py @ 3:7bd1f07044ab

Added grid_mapper to map from Kinect data to Joe's synth and Ableton. Added OSC.py which is a library file. You need it to run grid_mapper.py but please don't change it.
author Tim MB <tim.murraybrowne@eecs.qmul.ac.uk>
date Tue, 15 Feb 2011 17:31:11 +0000
parents
children 5f9ad838d417
comparison
equal deleted inserted replaced
2:b111b478075d 3:7bd1f07044ab
1 '''
2 grid_mapper.py - maintained by Tim.
3
4 This module implements a mapping from person positions (id,x,y,z) to generate
5 pitch, velocities and channels for Joe's synthesiser and controller data for
6 Ableton.
7
8 '''
9
10 from OSC import ThreadingOSCServer, OSCClient, OSCMessage, OSCClientError
11
12 #### PUBLIC OPTIONS ####
13 num_instruments = 3 # number of output channels
14
15 #### OSC OPTIONS - THESE NEED TO BE SET MANUALLY ####
16 my_port = 2001 # to receive OSC messages
17 joe = ('localhost', " PUT JOE's PORT NUMBER IN HERE")
18 ableton = ('localhost', " PUT ABLETON'S PORT NUMBER IN HERE ")
19
20 ### Constants for grid mapping:
21 # The range of values that the input coordinates and output values may take:
22 # (ranges are inclusive)
23 MIN = {
24 'x' : 0.,
25 'y' : 0.,
26 'z' : 0.,
27 'pitch' : 0,
28 'cc1' : 0,
29 'cc2' : 0,
30 }
31 MAX = {
32 'x' : 1.,
33 'y' : 1.,
34 'z' : 1.,
35 'pitch' : 15,
36 'cc1' : 127,
37 'cc2' : 127,
38 }
39
40
41
42 #### PRIVATE VARIABLES ####
43 person_positions = {} # mapping from personId to x,y,z
44 last_update_times = {} # mapping from personId to time of last update
45
46 # OSC OBJECTS
47 server = ThreadingOSCServer(('localhost'), my_port)
48 client = OSCClient()
49
50
51 def send_to_joe(data, address='/test'):
52 '''Sends `data` to Joe directly as an OSC message.
53 '''
54 message = OSCMesssage(address)
55 message.extend(data)
56 client.sendto(message, joe)
57
58
59
60 def person_handler(address, tags, data, client_address):
61 ''' Handles OSC input matching the 'person' tag.
62
63 `data` is [person_id, x, y, z]
64 '''
65 pitch, velocity, channel, cc1, cc2 = grid_map(data)
66
67 ## Format data for Joe - done using Specification.txt on 2011-02-15
68
69 # constrain and round off pitch and velocity
70 pitch = max(min(round(pitch), MAX['pitch']), MIN['pitch'])
71 velocity = max(min(round(pitch), MAX['velocity']), MIN['velocity'])
72
73 # turn integer pitch into a single 1 in a boolean array of 0s
74 boolean_note_array = [0] * (MAX['pitch'] - MIN['pitch'] + 1)
75 boolean_note_array[pitch] = 1
76
77 # seperate boolean for note-on and note-off
78 note_on = velocity > 0
79 # Never send velocity == 0
80 if velocity==0:
81 velocity = 127
82 THIS NEEDS FINISHING.
83
84
85
86
87 def grid_map(person_id, x, y, z):
88 '''This function maps from a person's location to MIDI data
89 returning a tuple (pitch, velocity, channel, cc1, cc2).
90
91 The current mapping creates higher pitch values as the person moves
92 closer to the Kinect (i.e. z decreases). x and y values are mapped to cc1
93 and cc2 (to be sent straight to Ableton and determined by a particular
94 synth)
95
96 NB. channel == person_id and velocity==0 when note is off.
97 Midi-Velocity is currently unimplemented but will use Person-velocity data
98 when that becomes available.
99 This function does not guarantee that the output will be in range if the
100 input goes out of range.
101 '''
102 pitch = round(interpolate(z,
103 MIN['z'], MAX['z'],
104 MIN['pitch'], MAX['pitch'])
105 )
106 cc1 = round(interpolate(x,
107 MIN['x'], MAX['x'],
108 MIN['cc1'], MAX['cc1'])
109 )
110 cc2 = round(interpolate(x,
111 MIN['y'], MAX['y'],
112 MIN['cc2'], MAX['cc2'])
113 )
114 velocity = 127
115 return (pitch, velocity, person_id, cc1, cc2)
116
117
118
119
120 def interpolate(x, a, b, A, B):
121 ''' Interpolates x from the range [a, b] to the range [A, B].
122
123
124 Interpolation is linear. From [a,b] to [A,B] this would be:
125 (B-A)*(x-a)/(b-a) + A
126 '''
127 return (B-A)*(x-a)/(b-a) + A