theremin/theremin/leap.py

134 lines
3.7 KiB
Python

import math
import Leap
def list_leap_motions():
controller = Leap.Controller()
has_devices = False
for device in controller.devices:
has_devices = True
print('{}'.format(str(device)))
if not has_devices:
print('No Leap Motion devices found')
class LeapMotion(Leap.Listener):
def __init__(self, dsp, track=0, amplitude=.5, min_frequency=55, max_frequency=10000):
super().__init__()
self.dsp = dsp
self.track = track
self.amplitude = amplitude
self.min_frequency = min_frequency
self.max_frequency = max_frequency
self.controller = Leap.Controller()
self.controller.add_listener(self)
def on_init(self, controller):
print('Leap initialized')
def on_connect(self, controller):
print('Leap connected')
def on_disconnect(self, controller):
print('Leap disconnected')
def on_exit(self, controller):
print('Leap exited')
@staticmethod
def _get_hands(frame):
(left, right) = (None, None)
if len(frame.hands) > 0:
if len(frame.hands) == 1:
left = frame.hands[0]
right = None
else:
if frame.hands[0].palm_position[0] < frame.hands[1].palm_position[0]:
left = frame.hands[0]
right = frame.hands[1]
else:
left = frame.hands[1]
right = frame.hands[0]
return left, right
def on_frame(self, controller):
frame = controller.frame()
left, right = self._get_hands(frame)
if not left and not right:
if self.dsp.is_playing(self.track):
self.dsp.stop(self.track)
return
y_left = left.palm_position[1]
frequency = self.y_to_freq(y_left)
if right:
y_right = right.palm_position[1]
self.amplitude = self.y_to_amplitude(y_right)
self.dsp.set_frequency(self.track, frequency)
self.dsp.set_volume(self.track, self.amplitude)
if not self.dsp.is_playing(self.track):
self.dsp.play(self.track)
print('Hand height: {:.8f}, Frequency: {:1f}, MIDI: {}, Amplitude: {:4f}'.format(
y_left, frequency, self.freq_to_midi_note(frequency), self.amplitude))
@staticmethod
def midi_note_to_str(midi):
notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
base_c = 24
i = (midi - base_c) % len(notes)
octave = int((midi - base_c) / 12)
return '{note}{octave}'.format(note=notes[i], octave=octave)
@classmethod
def freq_to_midi_note(cls, freq):
return cls.midi_note_to_str(int(math.log2(freq / 440.0) * 12) + 69)
def y_to_freq(self, y):
y_min_height = 70
y_max_height = 500
min_freq = self.min_frequency
max_freq = self.max_frequency
y -= y_min_height
y_max_height -= y_min_height
# max_freq -= min_freq
frequency = min_freq + ((max_freq*y) / y_max_height)
if frequency < min_freq:
return min_freq
if frequency > max_freq:
return max_freq
return frequency
@staticmethod
def y_to_amplitude(y):
y_min_height = 70
y_max_height = 500
min_amplitude = 0
max_amplitude = 1.5
y -= y_min_height
y_max_height -= y_min_height
max_amplitude -= min_amplitude
amplitude = min_amplitude + ((max_amplitude*y) / y_max_height)
if amplitude < min_amplitude:
return min_amplitude
if amplitude > max_amplitude:
return max_amplitude
return amplitude
def stop(self):
self.controller.remove_listener(self)