Mercurial > hg > movesynth
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 |