From ea698a54a82ff5c20236ff09e592354dfe25798a Mon Sep 17 00:00:00 2001 From: Niklas Halle Date: Mon, 5 Apr 2021 14:34:56 +0200 Subject: start cleanup --- .gitignore | 19 ++--- CMakeLists.txt | 10 +++ Contents.m | 18 ----- HarmoniousHarps_DemoMA01.mp3 | Bin 1193837 -> 0 bytes HarmoniousHarps_DemoMA01.wav | Bin 10509764 -> 0 bytes README.md | 119 ------------------------------ build.m | 22 ------ build_matleap | 10 +++ matleap.cpp | 113 ++++++++++++++++++++--------- matleap.h | 96 ------------------------ matleap.hpp | 60 +++++++++++++++ matleap.o | Bin 35992 -> 35904 bytes startup | 11 +++ test_matleap.m | 57 --------------- theremin.m | 162 +++++++++++++++++++++++++++++++++++++++++ theremin_ui.mlapp | Bin 0 -> 149110 bytes theremin_ui_alt.mlapp | Bin 0 -> 149110 bytes theremine | 6 -- theremine.m | 169 ------------------------------------------- 19 files changed, 343 insertions(+), 529 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 Contents.m delete mode 100644 HarmoniousHarps_DemoMA01.mp3 delete mode 100644 HarmoniousHarps_DemoMA01.wav delete mode 100644 README.md delete mode 100644 build.m create mode 100755 build_matleap mode change 100755 => 100644 matleap.cpp delete mode 100755 matleap.h create mode 100644 matleap.hpp create mode 100755 startup delete mode 100755 test_matleap.m create mode 100644 theremin.m create mode 100644 theremin_ui.mlapp create mode 100644 theremin_ui_alt.mlapp delete mode 100644 theremine delete mode 100644 theremine.m diff --git a/.gitignore b/.gitignore index 5a2072a..b95946c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,12 @@ -LeapSDK -matleap.mexa64 -.vs/ +# sdk +LeapSDK/ LeapSDKv4/ -MatLeapC.sln -MatLeapC.vcxproj -MatLeapC.vcxproj.filters -MatLeapC.vcxproj.user -x64/ +# binary +matleap.mexa64 *.mexw64 -LeapC.dll +# other out +x64/ +cmake-*/ +# ide +.vs/ +.idea/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5ef30fd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.20) +project(matleap) + +set(CMAKE_CXX_STANDARD 14) + +include_directories(.) + +add_executable(matleap + matleap.cpp + matleap.hpp) diff --git a/Contents.m b/Contents.m deleted file mode 100644 index a8c0533..0000000 --- a/Contents.m +++ /dev/null @@ -1,18 +0,0 @@ -% matleap Leap Motion Controller Interface -% ---------------------------------------- -% -% Copyright (C) 2013 Jeff Perry -% -% FUNCTIONS -% --------- -% v=matleap_version Get the version number -% f=matleap_frame Get a frame from the leap motion controller -% -% HISTORY -% ------- -% jsp Wed Nov 20 10:36:45 CST 2013 Created -% -% SEE ALSO -% -------- -% https://www.leapmotion.com/ -% https://developer.leapmotion.com/ diff --git a/HarmoniousHarps_DemoMA01.mp3 b/HarmoniousHarps_DemoMA01.mp3 deleted file mode 100644 index 20d9f61..0000000 Binary files a/HarmoniousHarps_DemoMA01.mp3 and /dev/null differ diff --git a/HarmoniousHarps_DemoMA01.wav b/HarmoniousHarps_DemoMA01.wav deleted file mode 100644 index cf3bbb3..0000000 Binary files a/HarmoniousHarps_DemoMA01.wav and /dev/null differ diff --git a/README.md b/README.md deleted file mode 100644 index 6589cf5..0000000 --- a/README.md +++ /dev/null @@ -1,119 +0,0 @@ -# Matleap: MATLAB Interface to the Leap Motion Controller - -This MATLAB mex-file will allow you to get data from a Leap Motion -Controller device. - -In order to build the mex-file, you need to have a C++ compiler -installed, and you need to setup Matlab for building mex-files. - -For more information on setting up Matlab for building mex-files, see -[the Matlab documentation](http://www.mathworks.com/help/matlab/ref/mex.html). - -## Building - -* Install the Leap SDK -* Give the matleap build module access the Leap SDK: - * If you are running **Windows**, copy the LeapSDK directory to the - directory that contains the matleap code. - * If you are running **OS/X** or **Linux**, you can either copy the - directory, or better still, create a symbolic link to the LeapSDK - directory and place it in the same directory as the matleap code, - for example: - -``` - $ ln -s ~/Software/Leap_Developer_Kit/LeapSDK/ ~/matleap/LeapSDK -``` - -* Build the mex file from within MATLAB - -``` - >> build -``` - -## Testing - -``` - >> test_matleap -``` - -## Examples -``` - >> matleap_version - ans = - 0 4 - >> f=matleap_frame - f = - id: 263725 - timestamp: 8.1430e+09 - pointables: [1x5 struct] - >> f.pointables(1).position - ans = - 8.9769 220.3197 -5.8013 - >> f.pointables(1).velocity - ans = - -6.7446 -4.2978 -13.0157 - >> f.pointables(1).direction - ans = - 0.2089 0.3257 -0.9221 - - >> test_matleap - matleap version 0.4 - frame id 309984 - frame timestamp 8767122812 - frame pointables 5 - pointable 1 - id 6 - position -18.529303 279.245270 -9.088086 - velocity -19.887272 -16.154881 -2.646765 - direction 0.098189 0.300899 -0.948588 - pointable 2 - id 7 - ... - pointable 5 - id 10 - position 34.367825 264.370300 41.408348 - velocity -3.097427 13.046532 9.727820 - direction 0.558435 0.059477 -0.827414 - 89 frames - 1.000254 seconds - 88.977400 fps -``` - -## Troubleshooting - -### General - -* Frames are returned with invalid frame data: **This happens when the - motion controller driver is not installed.** - -* Motion controller has slow framerate: **The driver will go into standby - mode if no movement is detected for a long period of time.** - -### OS/X - -* "libLeap.dylib can't load": **The Leap dynamic link library must be made - available to the mex-file executable either by changing your path, - creating a symbolic link to the library, or by copying the library to the - same directory as the mex-file.** For example: - -``` - $ cp '/Applications/Leap Motion.app/Contents/MacOS/libLeap.dylib' path_to_matleap -``` - -### Windows - -* "Invalid MEX-file '...\matleap.mexw64/32': The specified module could not - be found.": **Leap.dll must be made available to the mex-file executeable, - either by adding it to your path or copying it to the same directory as - the mex-file. The leap DLL is located in the LeapSDK\lib\x86 directory on - 32 bit systems and in the LeapSDK\lib\x64 directory on 64 bit systems.** - -### Linux - -* "Invalid MEX-file ... libLeap.so: cannot open shared object file: No such - file or directory": **The leap shared library must be made available to the - mex-file executable.** For example: - -``` - # ln -s /usr/lib/Leap/libLeap.so /usr/lib/ -``` diff --git a/build.m b/build.m deleted file mode 100644 index f5ef2a1..0000000 --- a/build.m +++ /dev/null @@ -1,22 +0,0 @@ -% @file build.m -% @brief build the matleap mex module -% @author Jeff Perry -% @version 1.0 -% @date 2013-09-12 - -libdir_switch='-L/usr/lib/Leap/'; - -% create the mex command line -fn='matleap.cpp'; -fprintf('Compiling %s\n',fn); -cmd=['mex',... - ' -I/usr/include ',... - libdir_switch,... - ' -lLeap ',... - fn]; -fprintf('Evaluating "%s"\n',cmd) - -% run mex -eval(cmd) - -fprintf('Done\n') diff --git a/build_matleap b/build_matleap new file mode 100755 index 0000000..218c357 --- /dev/null +++ b/build_matleap @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +nc_print() { + echo -e "\e[35m${*}\e[0m" +} + +nc_print "Building mex library..." +mex -lLeap matleap.cpp +#mex -c -lLeap matleap.cpp +nc_print "Done." diff --git a/matleap.cpp b/matleap.cpp old mode 100755 new mode 100644 index 9a3cb25..4a24d3d --- a/matleap.cpp +++ b/matleap.cpp @@ -4,7 +4,9 @@ /// @version 1.0 /// @date 2013-09-12 -#include "matleap.h" +// original by Jeff Perry, updated and adjusted by Niklas Halle + +#include "matleap.hpp" #include // Under Windows, a Leap::Controller must be allocated after the MEX @@ -24,7 +26,7 @@ int version = 4; // 1: orig, 2: with arm info, 3: with more hand info void matleap_exit() { fg->close_connection(); delete fg; - fg = 0; + fg = nullptr; } /// @brief process interface arguments @@ -37,7 +39,8 @@ void matleap_exit() { /// @return command number int get_command(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int command; - // check inputs + + // check inputs - we take exactly one parameter switch (nrhs) { case 1: command = *mxGetPr(prhs[0]); @@ -47,28 +50,17 @@ int get_command(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { default: mexErrMsgTxt("Too many input arguments"); } - // check that inputs agree with command + + // check that outputs agree with command switch (command) { - case -1: { + case -1: // set debug command requires 0 outputs - if (nlhs != 0) - mexErrMsgTxt("Wrong number of outputs specified"); - } + if (nlhs != 0) mexErrMsgTxt("Wrong number of outputs specified"); break; - case 0: { - // get version command requires 1 outputs - if (nlhs != 0 && nlhs != 1) - mexErrMsgTxt("Wrong number of outputs specified"); - } - break; - case 1: { - // frame grab command only requires one input - if (nrhs > 1) - mexErrMsgTxt("Too many inputs specified"); - // frame grab command requires exactly one output - if (nlhs != 0 && nlhs != 1) - mexErrMsgTxt("Wrong number of outputs specified"); - } + case 0: + case 1: + // get version and frame grab command can populate zero or one output + if (nlhs != 0 && nlhs != 1) mexErrMsgTxt("Wrong number of outputs specified"); break; default: mexErrMsgTxt("An unknown command was specified"); @@ -204,31 +196,86 @@ void get_frame(int nlhs, mxArray *plhs[]) { mxSetFieldByNumber(plhs[0], 0, 5, mxCreateDoubleScalar(version)); } -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { +/// @brief entry point for matlab +/// +/// @param nlhs count of left hand side +/// @param plhs pointer to left hand side array +/// @param nrhs count of right hand side +/// @param prhs pointer to right hand side array +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray const *prhs[]) { + // if there is no frame grabber yet, create one if (!fg) { fg = new matleap::frame_grabber; - if (fg == 0) + if (fg == nullptr) { mexErrMsgTxt("Cannot allocate a frame grabber"); + } fg->open_connection(); + // register exit handler mexAtExit(matleap_exit); } + + // parse rhs and lhs to determine what is requested from us switch (get_command(nlhs, plhs, nrhs, prhs)) { - // turn on debug - case -1: + case -1: // turn on debug fg->set_debug(true); - return; - // get version - case 0: + break; + case 0: // get version plhs[0] = mxCreateNumericMatrix(1, 2, mxDOUBLE_CLASS, mxREAL); *(mxGetPr(plhs[0]) + 0) = MAJOR_REVISION; *(mxGetPr(plhs[0]) + 1) = MINOR_REVISION; - return; - // get frame - case 1: + break; + case 1: // get frame get_frame(nlhs, plhs); - return; + break; default: // this is a logic error mexErrMsgTxt("unknown error: please contact developer"); + break; } } + +/* -------- frame grabber class -------- */ + +void matleap::frame_grabber::open_connection() { + mexPrintf("Waiting for connection"); + while (!controllerConnection.isConnected()) { + mexPrintf("."); + usleep(500000); + } + //controllerConnection.enableGesture(Leap::Gesture::TYPE_SWIPE); + controllerConnection.enableGesture(Leap::Gesture::TYPE_CIRCLE); + //controllerConnection.enableGesture(Leap::Gesture::TYPE_KEY_TAP); + //controllerConnection.enableGesture(Leap::Gesture::TYPE_SCREEN_TAP); + mexPrintf(" Connected!\n"); + // TODO: check if needed + //LeapSetPolicyFlags(*controllerConnection, eLeapPolicyFlag_BackgroundFrames, 0); +} + +void matleap::frame_grabber::close_connection() { + mexPrintf("Good bye."); +} + +matleap::frame_grabber::~frame_grabber() { + if (debug) mexPrintf("Closing matleap frame grabber\n"); +} + +void matleap::frame_grabber::set_debug(bool flag) { + if (flag == debug) return; + if (flag) mexPrintf("Toggle debug to %i\n", flag); + debug = flag; +} + +matleap::frame const &matleap::frame_grabber::get_frame() { + auto const &frame = controllerConnection.frame(); + current_frame.id = frame.id(); + if (debug) mexPrintf("Got frame with id %d\n", current_frame.id); + current_frame.timestamp = frame.timestamp(); + current_frame.detectedHands = frame.hands().count(); + current_frame.hands = frame.hands(); + current_frame.has_gesture = !frame.gestures().isEmpty(); + return current_frame; +} + +matleap::frame_grabber::frame_grabber() + : debug(false) { +} diff --git a/matleap.h b/matleap.h deleted file mode 100755 index 24eae30..0000000 --- a/matleap.h +++ /dev/null @@ -1,96 +0,0 @@ -/// @file matleap.h -/// @brief leap motion controller interface -/// @author Jeff Perry -/// @version 1.0 -/// @date 2013-09-12 - -#ifndef MATLEAP_H -#define MATLEAP_H - -#define MAJOR_REVISION 4 -#define MINOR_REVISION 0 - -#include "Leap.h" -#include "mex.h" - -#include - -namespace matleap { - -/// @brief a leap frame - struct frame { - int64_t id; - int64_t timestamp; - uint32_t detectedHands; - Leap::HandList hands; - bool has_gesture; - }; - -/// @brief leap frame grabber interface - class frame_grabber { - private: - bool debug; - Leap::Controller controllerConnection; - frame current_frame; - - public: - /// @brief constructor - frame_grabber() - : debug(false) { - } - - void open_connection() { - mexPrintf("Waiting for connection"); - while (!controllerConnection.isConnected()) { - mexPrintf("."); - usleep(500000); - } - //controllerConnection.enableGesture(Leap::Gesture::TYPE_SWIPE); - controllerConnection.enableGesture(Leap::Gesture::TYPE_CIRCLE); - //controllerConnection.enableGesture(Leap::Gesture::TYPE_KEY_TAP); - //controllerConnection.enableGesture(Leap::Gesture::TYPE_SCREEN_TAP); - mexPrintf(" Connected!\n"); - // TODO: check if needed - //LeapSetPolicyFlags(*controllerConnection, eLeapPolicyFlag_BackgroundFrames, 0); - } - - void close_connection() { - mexPrintf("Good bye."); - } - - /// @brief destructor - ~frame_grabber() { - if (debug) - mexPrintf("Closing matleap frame grabber\n"); - } - - /// @brief debug member access - /// - /// @param flag turn it on/off - void set_debug(bool flag) { - if (flag == debug) - return; - if (flag) - mexPrintf("Setting debug on\n"); - debug = flag; - } - - /// @brief get a frame from the controller - /// - /// @return the frame - frame const &get_frame() { - auto const &frame = controllerConnection.frame(); - current_frame.id = frame.id(); - if (debug) - mexPrintf("Got frame with id %d\n", current_frame.id); - current_frame.timestamp = frame.timestamp(); - current_frame.detectedHands = frame.hands().count(); - current_frame.hands = frame.hands(); - current_frame.has_gesture = !frame.gestures().isEmpty(); - return current_frame; - } - }; - -} // namespace matleap - -#endif diff --git a/matleap.hpp b/matleap.hpp new file mode 100644 index 0000000..0b8e732 --- /dev/null +++ b/matleap.hpp @@ -0,0 +1,60 @@ +/// @file matleap.h +/// @brief leap motion controller interface +/// @author Jeff Perry +/// @version 1.0 +/// @date 2013-09-12 + +#ifndef MATLEAP_H +#define MATLEAP_H + +#define MAJOR_REVISION 4 +#define MINOR_REVISION 0 + +#include "Leap.h" +#include "mex.h" + +#include + +namespace matleap { + +/// @brief a leap frame + struct frame { + int64_t id; + int64_t timestamp; + uint32_t detectedHands; + Leap::HandList hands; + bool has_gesture; + }; + +/// @brief leap frame grabber interface + class frame_grabber { + private: + bool debug; + Leap::Controller controllerConnection; + frame current_frame; + + public: + /// @brief constructor + frame_grabber(); + + void open_connection(); + + void close_connection(); + + /// @brief destructor + ~frame_grabber(); + + /// @brief debug member access + /// + /// @param flag turn it on/off + void set_debug(bool flag); + + /// @brief get a frame from the controller + /// + /// @return the frame + frame const &get_frame(); + }; + +} // namespace matleap + +#endif diff --git a/matleap.o b/matleap.o index 2e6adcb..69a4a8c 100644 Binary files a/matleap.o and b/matleap.o differ diff --git a/startup b/startup new file mode 100755 index 0000000..7e483ea --- /dev/null +++ b/startup @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +nc_print() { + echo -e "\e[35m${*}\e[0m" +} + +nc_print "Starting LEAP Motion service..." +sudo systemctl start leapd.service +nc_print "Starting LEAP Motion control panel..." +LeapControlPanel & +nc_print "Done." diff --git a/test_matleap.m b/test_matleap.m deleted file mode 100755 index 0c6c322..0000000 --- a/test_matleap.m +++ /dev/null @@ -1,57 +0,0 @@ -% @file test_matleap.m -% @brief test matleap functionality -% @author Jeff Perry -% @version 1.0 -% @date 2013-09-12 - -function test_matleap - % remove matleap mex-file from memory - % set debug on - %matleap_debug - % show version - [version]=matleap_version; - fprintf('matleap version %d.%d\n',version(1),version(2)); - % pause to let the hardware wake up - sleep(1) - % get some frames - frame_id=-1; - frames=0; - tic - while(toc<10) - % get a frame - f=matleap_frame; - % only count it if it has a different id - if f.id~=frame_id - frame_id=f.id; - print(f) - frames=frames+1; - end - end - s=toc; - % display performance - fprintf('%d frames\n',frames); - fprintf('%f seconds\n',s); - fprintf('%f fps\n',frames/s); -end - -% sleep for t seconds -function sleep(t) - tic; - while (toc 0 + gesture_count = gesture_count + 1; + else + gesture_count = 0; + end + elseif isequal(two_hands, handCount) + gesture_count = 0; + + %pos = frame.hands(1).palm.position; + pos = frame.hands(1).palm.stabilized_position; + + frequency_pos = pos(1); + %y_one = pos(2); + + P(count, 1:3) = pos; + count = count + 1; + + %pos = frame.hands(2).palm.position; + pos = frame.hands(2).palm.stabilized_position; + + %x_two = pos(1); + height_pos = pos(2); + else + % no hands, do nothing (or more than 2 (how?! :D)) + gesture_count = 0; + end + + % play current sound + [signal_one, offset_one] = get_theremin_sound_bit(frequency_pos, height_pos, offset_one, signal); + %[signal_two, offset_two] = get_theremin_sound_bit(x_two, y_two, offset_two, signal); + full_signal = signal_one;% + signal_two; + + buffer_under_flow = deviceWriter(full_signal(:)); + + if buffer_under_flow ~= 0 + disp("Buffer ran empty!"); + end + + complete_signal = [complete_signal full_signal]; +end + +release(deviceWriter) + +%theremin_player = audioplayer(complete_signal, const_Fs); +%play(theremin_player); + +% extract values +x = P(:,1); % links (-) rechts (+) (LED zu uns) +y = P(:,2); % oben unten +z = P(:,3); % vorne (+) hinten (-) (LED zu uns) + +% plot +figure("Position",[0,0, 1200, 2400]); +t = tiledlayout(4,1); + +nexttile; +plot(x); +ylabel('left right'); + +nexttile; +plot(y); +ylabel('height'); + +nexttile; +plot(z); +ylabel('depth'); + +nexttile; +plot3(z,x,y); +xlabel('depth'); +ylabel('left right'); +zlabel('height'); + +function [sound,offset] = get_theremin_sound_bit(x, y, offset, generator) + % finding ranges for x and y: + %'x' + %min(x) + %max(x) + %'y' + %min(y) + %max(y) + % --> 50 < x < 270 + % --> 90 < y < 350 + + volume = (y) / 1300; + frequency = max(0.003, (x - 50) / 220) * 1000; % https://web.physics.ucsb.edu/~lecturedemonstrations/Composer/Pages/60.17.html # How it works + + base = generator(frequency) + offset; + + offset = base(end); + + sound = sin(base) .* volume; +end \ No newline at end of file diff --git a/theremin_ui.mlapp b/theremin_ui.mlapp new file mode 100644 index 0000000..5f7863f Binary files /dev/null and b/theremin_ui.mlapp differ diff --git a/theremin_ui_alt.mlapp b/theremin_ui_alt.mlapp new file mode 100644 index 0000000..5f7863f Binary files /dev/null and b/theremin_ui_alt.mlapp differ diff --git a/theremine b/theremine deleted file mode 100644 index f6f6d72..0000000 --- a/theremine +++ /dev/null @@ -1,6 +0,0 @@ -while true - frame = matleap_frame - if ~isempty(frame.hands) - pos = frame.hands.palm.stabilized_position - end -end \ No newline at end of file diff --git a/theremine.m b/theremine.m deleted file mode 100644 index a9b908b..0000000 --- a/theremine.m +++ /dev/null @@ -1,169 +0,0 @@ -clear; - -%%%%%%%% -% "constants" % -%%%%%%%% - -% how many updates per second, determines the length of audio snippets -const_frames_per_second = 100; - -const_Fs = 44100; % sampling rate in Hz -const_te = 1/const_frames_per_second; % signal duration in seconds -const_samples_per_frame = ceil(const_Fs * const_te); -const_sample_range = 0:const_samples_per_frame-1; - -% factor the last read frame is multiplied by -const_fade_speed = 0.975; - -% signal "generator" -signal = @(freq) (freq ./ const_Fs .* 2 .* pi .* const_sample_range); - -% time given for calculation -const_calc_offset = 0; - -% dimensions to use for detecting number of hands in frame -zero_hands = size(NaN(0,0)); -one_hand = size(NaN(1,1)); -two_hands = size(NaN(1,2)); - -deviceWriter = audioDeviceWriter('SampleRate', const_Fs, 'SupportVariableSizeInput', true, 'BufferSize', 3 * const_samples_per_frame); - -%%%%%%%%%%%%%%%%%%% -% init matleap by calling for first frame % -%%%%%%%%%%%%%%%%%%% -matleap_frame - -% runtime variables -P = NaN(1000000,3); -count = 1; -done = false; - -x_one = 0; -x_two = 0; - -y_one = 0; -y_two = 0; - -offset_one = 0; -offset_two = 0; - -signal_one = sin(signal(0)); -signal_two = sin(signal(0)); - -full_signal = signal_one + signal_two; -complete_signal = full_signal; - -% time gestures, used for program termination -gesture_count = 0; - -%while count < 100000 && gesture_count < 3 -while gesture_count < (1 * (const_frames_per_second - const_calc_offset)) - frame = matleap_frame; - handCount = size(frame.hands); - - % slowly decrease volume - y_one = y_one * const_fade_speed; - y_two = y_two * const_fade_speed; - - if isequal(one_hand, handCount) - pos = frame.hands(1).palm.position; - %pos = frame.hands(1).palm.stabilized_position; - - x_one = pos(1); - y_one = pos(2); - - P(count, 1:3) = pos; - count = count + 1; - - if frame.gesture > 0 - gesture_count = gesture_count + 1; - else - gesture_count = 0; - end - elseif isequal(two_hands, handCount) - gesture_count = 0; - - pos = frame.hands(1).palm.position; - %pos = frame.hands(1).palm.stabilized_position; - - x_one = pos(1); - y_one = pos(2); - - P(count, 1:3) = pos; - count = count + 1; - - pos = frame.hands(2).palm.position; - %pos = frame.hands(2).palm.stabilized_position; - - x_two = pos(1); - y_two = pos(2); - else - % no hands, do nothing (or more than 2 (how?! :D)) - gesture_count = 0; - end - - % play current sound - [signal_one, offset_one] = get_theremin_sound_bit(x_one, y_one, offset_one, signal); - [signal_two, offset_two] = get_theremin_sound_bit(x_two, y_two, offset_two, signal); - full_signal = signal_one + signal_two; - - if deviceWriter(full_signal(:)) ~= 0 - disp("Buffer ran empty!"); - end - - complete_signal = [complete_signal full_signal]; -end - -release(deviceWriter) - -%theremin_player = audioplayer(complete_signal, const_Fs); -%play(theremin_player); - -% extract values -x = P(:,1); % links (-) rechconst_Ts (+) (LED zu uns) -y = P(:,2); % oben unten -z = P(:,3); % vorne (+) hinten (-) (LED zu uns) - -% plot -figure("Position",[0,0, 1200, 2400]); -t = tiledlayout(4,1); - -nexttile; -plot(x); -ylabel('left right'); - -nexttile; -plot(y); -ylabel('height'); - -nexttile; -plot(z); -ylabel('depth'); - -nexttile; -plot3(z,x,y); -xlabel('depth'); -ylabel('left right'); -zlabel('height'); - -function [sound,offset] = get_theremin_sound_bit(x, y, offset, generator) - % finding ranges for x and y: - %'x' - %min(x) - %max(x) - %'y' - %min(y) - %max(y) - % --> -300 < x < 300 - % --> 0 < y < 600 - - % therefore - volume = y / 2000; - frequency = max(0.0001, (x + 400) / 1200) * 3000; % https://web.physics.ucsb.edu/~lecturedemonstrations/Composer/Pages/60.17.html # How it works - - base = generator(frequency) + offset; - - offset = base(end); - - sound = sin(base) .* volume; -end \ No newline at end of file -- cgit v1.2.3-54-g00ecf