├── .gitignore ├── LibSensel.dll ├── LibSensel.lib ├── LibSenselDecompress.dll ├── LibSenselDecompress.lib ├── Makefile.pdlibbuilder.revised ├── README ├── README.md ├── SENSEL_LICENSE ├── deken_install_example.png ├── makefile ├── sensel-help.pd ├── sensel-led.pd ├── sensel-win-msys-include ├── sensel.h ├── sensel_decompress.h ├── sensel_device.h ├── sensel_protocol.h ├── sensel_protocol.h.diff └── sensel_types.h ├── sensel.c ├── sensel.dll ├── sensel.pd_darwin ├── sensel.pd_linux └── sensel_examples ├── SenselDMX.pd ├── SimpleSenselSound.pd └── abs ├── basicvoice.pd ├── f2scale.pd ├── output2~.pd └── sen-scale.pd /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | sensel_examples/.DS_Store 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /LibSensel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensel/PD-objects/50f70168c2d182ceb5d8355c7dfdfd4ec95a842f/LibSensel.dll -------------------------------------------------------------------------------- /LibSensel.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensel/PD-objects/50f70168c2d182ceb5d8355c7dfdfd4ec95a842f/LibSensel.lib -------------------------------------------------------------------------------- /LibSenselDecompress.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensel/PD-objects/50f70168c2d182ceb5d8355c7dfdfd4ec95a842f/LibSenselDecompress.dll -------------------------------------------------------------------------------- /LibSenselDecompress.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensel/PD-objects/50f70168c2d182ceb5d8355c7dfdfd4ec95a842f/LibSenselDecompress.lib -------------------------------------------------------------------------------- /Makefile.pdlibbuilder.revised: -------------------------------------------------------------------------------- 1 | # Makefile.pdlibbuilder dated 2016-06-26 2 | 3 | version = 0.2.5 4 | 5 | # Helper makefile for Pure Data external libraries. 6 | # Written by Katja Vetter March-June 2015 for the public domain. No warranties. 7 | # Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's 8 | # ShakeNMake. 9 | # 10 | # GNU make version >= 3.81 required. 11 | # 12 | # 13 | #=== characteristics =========================================================== 14 | # 15 | # 16 | # - defines build settings based on autodetected OS and architecture 17 | # - defines rules to build Pd class- or lib executables from C or C++ sources 18 | # - defines rules for libdir installation 19 | # - defines convenience targets for developer and user 20 | # - evaluates implicit dependencies for non-clean builds 21 | # 22 | # 23 | #=== basic usage =============================================================== 24 | # 25 | # 26 | # In your Makefile, define your Pd lib name and class files, and include 27 | # Makefile.pdlibbuilder at the end of the Makefile. Like so: 28 | # 29 | # ________________________________________________________________________ 30 | # 31 | # # Makefile for mylib 32 | # 33 | # lib.name = mylib 34 | # 35 | # class.sources = myclass1.c myclass2.c 36 | # 37 | # datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt 38 | # 39 | # include Makefile.pdlibbuilder 40 | # ________________________________________________________________________ 41 | # 42 | # 43 | # For files in class.sources it is assumed that class basename == source file 44 | # basename. The default target builds all classes as individual executables 45 | # with Pd's default extension for the platform. For anything more than the 46 | # most basic usage, continue reading. 47 | # 48 | # 49 | #=== list of Makefile.pdlibbuilder API variables =============================== 50 | # 51 | # 52 | # Variables available for definition in your library Makefile: 53 | # 54 | # - lib.name 55 | # - lib.setup.sources 56 | # - class.sources 57 | # - common.sources 58 | # - shared.sources 59 | # - .class.sources 60 | # - .class.ldflags 61 | # - .class.ldlibs 62 | # - cflags 63 | # - ldflags 64 | # - ldlibs 65 | # - datafiles 66 | # - datadirs 67 | # - makefiles 68 | # - makefiledirs 69 | # - externalsdir 70 | # 71 | # Optional multiline defines evaluated per operating system: 72 | # 73 | # - forLinux 74 | # - forDarwin 75 | # - forWindows 76 | # 77 | # 78 | # Variables avaialable for (re)definition via command arguments: 79 | # 80 | # - pdbinpath (Windows only) 81 | # - pdincludepath 82 | # - DESTDIR 83 | # - prefix 84 | # - libdir 85 | # - pkglibdir 86 | # - CPPFLAGS 87 | # - CFLAGS 88 | # - LDFLAGS 89 | # - CC 90 | # - CXX 91 | # - INSTALL 92 | # - INSTALL_PROGRAM 93 | # - INSTALL_DATA 94 | # - INSTALL_DIR 95 | # 96 | # Variables available for your makefile or as command argument: 97 | # 98 | # - objectsdir 99 | # - make-lib-executable 100 | # - suppress-wunused 101 | # 102 | # 103 | #=== descriptions of Makefile.pdlibbuilder API variables ======================= 104 | # 105 | # 106 | # lib.name: 107 | # Name of the library directory as it will be installed / distributed. Also the 108 | # name of the lib executable in the case where all classes are linked into 109 | # a single binary. 110 | # 111 | # lib.setup.sources: 112 | # Source file(s) (C or C++) which must be compiled only when linking all classes 113 | # into a single lib binary. 114 | # 115 | # class.sources: 116 | # All sources files (C or C++) for which the condition holds that 117 | # class name == source file basename. 118 | # 119 | # .class.sources: 120 | # Source file(s) (C or C++) specific to class . Use this for 121 | # multiple-source classes or when class name != source file basename. 122 | # 123 | # common.sources: 124 | # Source file(s) which must be statically linked to each class in the library. 125 | # 126 | # shared.sources: 127 | # Source file(s) (C or C++) to build a shared dynamic link lib, to be linked 128 | # with all class executables. 129 | # 130 | # cflags, ldflags, ldlibs: 131 | # Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic 132 | # link libs) for the whole library. These flags are added to platform-specific 133 | # flags defined by Makefile.pdlibbuilder. 134 | # 135 | # .class.ldflags and .class.ldlibs: 136 | # Define ldflags resp. ldlibs specific to class . These flags are 137 | # added to platform-specific flags defined by Makefile.pdlibbuilder, and flags 138 | # defined in your Makefile for the whole library. Note: cflags can not be 139 | # defined per class in the current implementation. 140 | # 141 | # datafiles and datadirs: 142 | # All extra files you want to include in binary distributions of the 143 | # library: abstractions and help patches, example patches, meta patch, readme 144 | # and license texts, manuals, sound files, etcetera. Use 'datafiles' for all 145 | # files that should go into your lib rootdir and 'datadirs' for complete 146 | # directories you want to copy from source to distribution. 147 | # 148 | # externalsdir: 149 | # Relative path to directory 'externals' in the context of pd-extended SVN, or 150 | # any other centralized build layout for multiple libraries. Default value 151 | # is '..', meaning the direct parent. The value is used in search paths for 152 | # pd core components (header files, and executable in the case of Windows). 153 | # 154 | # forLinux, forDarwin, forWindows: 155 | # Shorthand for 'variable definitions for Linux only' etc. Use like: 156 | # define forLinux 157 | # cflags += -DLINUX 158 | # class.sources += linuxthing.c 159 | # endef 160 | # 161 | # makefiles and makefiledirs: 162 | # Extra makefiles or directories with makefiles that should be made in sub-make 163 | # processes. 164 | # 165 | # pdbinpath: 166 | # For Windows only. Directory where pd.dll can be found for linking. 167 | # 168 | # pdincludepath: 169 | # Directory where Pd API m_pd.h can be found, and other Pd header files. 170 | # 171 | # DESTDIR, prefix, libdir: 172 | # Components of the path for installation as conventionally used on Linux. 173 | # 174 | # pkglibdir: 175 | # Base path for installation of Pd library directories. Default is specified 176 | # per OS, see section about paths below. 177 | # 178 | # objectsdir: 179 | # Alias of pkglibdir. Can be defined in your makefile to enable project- 180 | # dependent relative install locations. 181 | # 182 | # CPPFLAGS: 183 | # Preprocessor flags which are not strictly required for building. 184 | # 185 | # CFLAGS: 186 | # Compiler flags which are not strictly required for building. Compiler flags 187 | # defined by Makefile.pdlibbuilder for warning, optimization and architecture 188 | # specification are overriden by CFLAGS. 189 | # 190 | # LDFLAGS: 191 | # Linker flags which are not strictly required for building. Linker flags 192 | # defined by Makefile.pdlibbuilder for architecture specification are overriden 193 | # by LDFLAGS. 194 | # 195 | # CC and CXX: 196 | # C and C++ compiler programs as defined in your build environment. 197 | # 198 | # INSTALL, INSTALL_PROGRAM, INSTALL_DATA, INSTALL_DIR: 199 | # Definitions of install program, may be overriden via command argument. 200 | # 201 | # make-lib-executable: 202 | # When this variable is defined 'yes' in your makefile or as command argument, 203 | # Makefile.pdlibbuilder will try to build all classes into a single library 204 | # executable (but it will force exit if lib.setup.sources is undefined). 205 | # If your makefile defines 'make-lib-executable=yes' as the library default, 206 | # this can still be overriden with 'make-lib-executable=no' as command argument 207 | # to build individual class executables (the Makefile.pdlibbuilder default.) 208 | # 209 | # suppress-wunused: 210 | # When this variable is defined ('yes' or any other value), -Wunused-variable, 211 | # -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed, 212 | # but the other warnings from -Wall are retained. 213 | # 214 | # 215 | #=== paths ===================================================================== 216 | # 217 | # 218 | # Source files in directories other than current working directory must be 219 | # prefixed with their relative path. Do not rely on VPATH or vpath. 220 | # Object (.o) files are built in the directory of their source files. 221 | # Executables are built in current working directory. 222 | # 223 | # Variable 'pdincludepath' stores a location where m_pd.h is expected to reside. 224 | # Locations where Makefile.pdlibbuilder tries to find it, in order of priority: 225 | # 226 | # any OS: $(externalsdir)../pd/src 227 | # 228 | # Linux: /usr/include/pdextended 229 | # /usr/include/pd 230 | # 231 | # OSX: /Applications/Pd-extended.app/Contents/Resources/include/pdextended 232 | # /Applications/Pd.app/Contents/Resources/src 233 | # 234 | # Windows: %PROGRAMFILES%/pd/include/pdextended 235 | # %PROGRAMFILES%/pd/src 236 | # 237 | # The path for installation of all library components is constructed as: 238 | # 239 | # installpath := $(DESTDIR)$(objectsdir)/$(lib.name) 240 | # 241 | # Default for 'objectsdir' is defined per platform and follows this convention: 242 | # https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files 243 | # 244 | # Linux: /usr/local/lib/pd-externals 245 | # OSX: ~/Library/Pd 246 | # Windows: %APPDATA%/Pd 247 | # 248 | # The rationale for not installing to ~/pd-externals by default on Linux 249 | # is that some people share the home dir between 32 and 64 bit installations. 250 | # 251 | # 252 | #=== targets =================================================================== 253 | # 254 | # 255 | # all: build $(executables) plus optional post target 256 | # post: target to build after $(executables) 257 | # alldebug: build all with -g option turned on for debug symbols 258 | # : force clean build of an individual class 259 | # .pre: make preprocessor output file in current working directory 260 | # .lst: make asm/source output file in current working directory 261 | # 262 | # install: install executables and data files 263 | # clean: remove build products from source tree 264 | # 265 | # help: print help text 266 | # vars: print makefile variables 267 | # allvars: print all variables 268 | # depend: print generated prerequisites 269 | # coffee: dummy target 270 | # 271 | # Variable $(executables) expands to class executables plus optional shared lib, 272 | # or alternatively to single lib executable when make-lib-executable=true. 273 | # Targets pre and post can be defined by library makefile. Make sure to include 274 | # Makefile.pdlibbuilder first so default target all will not be redefined. 275 | # 276 | # 277 | #=== Pd-extended libdir concept ================================================ 278 | # 279 | # 280 | # For libdir layout as conceived by Hans-Christoph Steiner, see: 281 | # 282 | # https://puredata.info/docs/developer/Libdir 283 | # 284 | # Files README.txt, LICENSE.txt and -meta.pd are part of the libdir 285 | # convention. Help patches for each class and abstraction are supposed to be 286 | # available. Makefile.pdlibbuilder does not force the presence of these files 287 | # however. It does not automatically include such files in libdir installations. 288 | # Data files you want to include in distributions must be defined explicitly in 289 | # your Makefile. 290 | # 291 | # 292 | #=== Makefile.pdlibbuilder syntax conventions ================================== 293 | # 294 | # 295 | # Makefile.pdlibbuilder variable names are lower case. Default make variables, 296 | # environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR) 297 | # are upper case. Use target 'allvars' to print all variables and their values. 298 | # 299 | # 'Fields' in data variables are separated by dots, like in 'foo.class.sources'. 300 | # Words in variables expressing a function or command are separated by dashes, 301 | # like in 'make-lib-executable'. 302 | # 303 | # 304 | #=== useful make options ======================================================= 305 | # 306 | # 307 | # Use 'make -d ' to print debug details of the make process. 308 | # Use 'make -p ' to print make's database. 309 | # 310 | # 311 | #=== TODO ====================================================================== 312 | # 313 | # 314 | # - decide whether to use -static-libgcc or shared dll in MinGW 315 | # - cygwin support 316 | # - android support 317 | # - Windows 64 bit support 318 | # - figure out how to handle '$' in filenames 319 | # - add makefile template targets dpkg-source dist libdir distclean tags? 320 | # 321 | # 322 | #=== end of documentation sections ============================================= 323 | # 324 | # 325 | ################################################################################ 326 | ################################################################################ 327 | ################################################################################ 328 | 329 | 330 | # GNU make version 3.81 (2006) or higher is required because of the following: 331 | # - function 'info' 332 | # - variable '.DEFAULT_GOAL' 333 | 334 | # force exit when make version is < 3.81 335 | ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81) 336 | $(error GNU make version 3.81 or higher is required) 337 | endif 338 | 339 | # Relative path to externals root dir in multi-lib source tree like 340 | # pd-extended SVN. Default is parent of current working directory. May be 341 | # defined differently in including makefile. This variable is used to probe for 342 | # paths. 343 | externalsdir ?= .. 344 | 345 | # variable you can use to check if Makefile.pdlibbuilder is already included 346 | Makefile.pdlibbuilder = true 347 | 348 | 349 | #=== operating system ========================================================== 350 | 351 | 352 | # The following systems are defined: Linux, Darwin, Windows. GNU and 353 | # GNU/kFreeBSD are treated as Linux to get the same options. System-specific 354 | # multiline defines (optionally set in library makefile) are conditionally 355 | # evaluated here. 356 | 357 | uname := $(shell uname) 358 | 359 | ifeq ($(findstring $(uname), Linux GNU GNU/kFreeBSD), $(uname)) 360 | system = Linux 361 | $(eval $(forLinux)) 362 | endif 363 | 364 | ifeq ($(uname), Darwin) 365 | system = Darwin 366 | $(eval $(forDarwin)) 367 | endif 368 | 369 | ifeq ($(findstring MINGW, $(uname)), MINGW) 370 | system = Windows 371 | $(eval $(forWindows)) 372 | endif 373 | 374 | # TODO: Cygwin, Android 375 | 376 | 377 | #=== flags and paths for Linux ================================================= 378 | 379 | 380 | ifeq ($(system), Linux) 381 | prefix = /usr/local 382 | libdir := $(prefix)/lib 383 | pkglibdir = $(libdir)/pd-externals 384 | pdincludepath := $(firstword $(wildcard \ 385 | $(externalsdir)/../pd/src \ 386 | /usr/include/pdextended \ 387 | /usr/include/pd)) 388 | extension = pd_linux 389 | cpp.flags := -DUNIX 390 | c.flags := -fpic 391 | c.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags 392 | c.ldlibs := -lc -lm 393 | cxx.flags := -fpic -fcheck-new 394 | cxx.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags 395 | cxx.ldlibs := -lc -lm -lstdc++ 396 | shared.extension = so 397 | shared.ldflags := -rdynamic -fpic -shared -Wl,-soname,$(shared.lib) 398 | stripflags = --strip-unneeded -R .note -R .comment 399 | endif 400 | 401 | 402 | #=== flags and paths for Darwin ================================================ 403 | 404 | 405 | # On OSX we try to build fat binaries by default. It is assumed that OSX i386 406 | # can build for ppc and OSX x86_64 can't. TODO: try to refine this condition. 407 | # LLVM-clang doesn't support -fcheck-new, therefore this flag is omitted for 408 | # OSX x86_64. 409 | 410 | ifeq ($(system), Darwin) 411 | ifeq ($(macos_target),) 412 | macos_target = 10.9 413 | endif 414 | pkglibdir = $(HOME)/Library/Pd 415 | pdincludepath := $(firstword $(wildcard \ 416 | $(externalsdir)/../pd/src \ 417 | /Applications/Pd-extended*.app/Contents/Resources/include/pdextended \ 418 | /Applications/Pd*.app/Contents/Resources/src)) 419 | extension = pd_darwin 420 | cpp.flags := -DUNIX -DMACOSX -I /sw/include 421 | c.flags := 422 | c.ldflags := -undefined suppress -flat_namespace -bundle 423 | c.ldlibs := -lc 424 | cxx.ldflags := -undefined suppress -flat_namespace -bundle 425 | cxx.ldlibs := -lc 426 | shared.extension = dylib 427 | shared.ldflags = -dynamiclib -undefined dynamic_lookup \ 428 | -install_name @loader_path/$(shared.lib) \ 429 | -compatibility_version 1 -current_version 1.0 430 | stripflags = -x 431 | ifeq ($(machine), i386) 432 | cxx.flags := -fcheck-new 433 | arch.c.flags := -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=$(macos_target) 434 | arch.ld.flags := -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=$(macos_target) 435 | endif 436 | ifeq ($(machine), x86_64) 437 | arch.c.flags := -arch x86_64 -mmacosx-version-min=$(macos_target) 438 | arch.ld.flags := -arch x86_64 -mmacosx-version-min=$(macos_target) 439 | endif 440 | endif 441 | 442 | 443 | #=== flags and paths for Windows =============================================== 444 | 445 | 446 | # Standard paths on Windows contain spaces, and GNU make functions treat such 447 | # paths as lists, with unintended effects. Therefore we must use shell function 448 | # ls instead of make's wildcard, and probe for each standard path individually. 449 | # Using double quotes around paths with spaces is obligatory. Since some path 450 | # variables are assembled or re-expanded later, great care must be taken to put 451 | # quotes at appropriate points throughout the makefile. Thanks, Bill. 452 | 453 | # paths for 32-bit executables on 64-bit Windows aren't yet defined here (TODO) 454 | ifeq ($(system), Windows) 455 | pkglibdir := $(APPDATA)/Pd 456 | pdbinpath := $(wildcard $(externalsdir)/../pd/bin) 457 | pdincludepath := $(wildcard $(externalsdir)/../pd/src) 458 | ifndef pdbinpath 459 | pdbinpath := $(shell ls -d "$(PROGRAMFILES)/pd/bin") 460 | endif 461 | ifndef pdincludepath 462 | pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/include/pdextended") 463 | endif 464 | ifndef pdincludepath 465 | pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/src") 466 | endif 467 | endif 468 | 469 | # On Windows we build 32 bit by default to match Pd(-extended) binary 470 | # distributions. This may change in the future. 471 | # TODO: decide whether -mms-bitfields should be specified. 472 | ifeq ($(system), Windows) 473 | extension = dll 474 | CC = gcc 475 | CXX = g++ 476 | arch.c.flags := -march=pentium4 -msse -msse2 -mfpmath=sse 477 | cpp.flags := -DMSW -DNT 478 | c.flags := 479 | c.ldflags := -static-libgcc -shared \ 480 | -Wl,--enable-auto-import "$(pdbinpath)/pd.dll" 481 | c.ldlibs := 482 | cxx.flags := -fcheck-new 483 | cxx.ldflags := -static-libstdc++ -shared \ 484 | -Wl,--enable-auto-import "$(pdbinpath)/pd.dll" 485 | cxx.ldlibs := 486 | shared.extension = dll 487 | shared.ldflags := -static-libgcc -shared "$(pdbinpath)/pd.dll" 488 | stripflags = --strip-unneeded -R .note -R .comment 489 | endif 490 | 491 | 492 | ################################################################################ 493 | ### variables: library name and version ######################################## 494 | ################################################################################ 495 | 496 | 497 | # strip possibles spaces from lib.name, they mess up calculated file names 498 | lib.name := $(strip $(lib.name)) 499 | 500 | # if meta file exists, check library version 501 | metafile := $(wildcard $(lib.name)-meta.pd) 502 | 503 | ifdef metafile 504 | lib.version := $(shell sed -n \ 505 | 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \ 506 | $(metafile)) 507 | endif 508 | 509 | 510 | ################################################################################ 511 | ### variables: files ########################################################### 512 | ################################################################################ 513 | 514 | 515 | #=== sources =================================================================== 516 | 517 | 518 | # (re)define .class.sources using file names in class.sources 519 | 520 | define add-class-source 521 | $(notdir $(basename $v)).class.sources += $v 522 | endef 523 | 524 | $(foreach v, $(class.sources), $(eval $(add-class-source))) 525 | 526 | # derive class names from .class.sources variables 527 | sourcevariables := $(filter %.class.sources, $(.VARIABLES)) 528 | classes := $(basename $(basename $(sourcevariables))) 529 | 530 | # accumulate all source files specified in makefile 531 | classes.sources := $(sort $(foreach v, $(sourcevariables), $($v))) 532 | all.sources := $(classes.sources) $(lib.setup.sources) \ 533 | $(shared.sources) $(common.sources) 534 | 535 | 536 | #=== object files ============================================================== 537 | 538 | 539 | # construct object filenames from all C and C++ source file names 540 | classes.objects := $(addsuffix .o, $(basename $(classes.sources))) 541 | common.objects := $(addsuffix .o, $(basename $(common.sources))) 542 | shared.objects := $(addsuffix .o, $(basename $(shared.sources))) 543 | lib.setup.objects := $(addsuffix .o, $(basename $(lib.setup.sources))) 544 | all.objects = $(classes.objects) $(common.objects) $(shared.objects) \ 545 | $(lib.setup.objects) 546 | 547 | 548 | #=== executables =============================================================== 549 | 550 | 551 | # use recursive variables here because executable extension is not yet known 552 | 553 | # construct class executable names from class names 554 | classes.executables = $(addsuffix .$(extension), $(classes)) 555 | 556 | # construct shared lib executable name if shared sources are defined 557 | ifdef shared.sources 558 | shared.lib = lib$(lib.name).$(shared.extension) 559 | else 560 | shared.lib = 561 | endif 562 | 563 | 564 | ################################################################################ 565 | ### variables per platform ##################################################### 566 | ################################################################################ 567 | 568 | 569 | #=== flags per architecture ==================================================== 570 | 571 | 572 | # Set architecture-dependent cflags, mainly for Linux. For Mac and Windows, 573 | # arch.c.flags are overriden below. 574 | 575 | machine := $(shell uname -m) 576 | 577 | # Raspberry Pi 1st generation 578 | ifeq ($(machine), armv6l) 579 | arch.c.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard 580 | endif 581 | 582 | # Beagle, Udoo, RPi2 etc. 583 | ifeq ($(machine), armv7l) 584 | arch.c.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard 585 | endif 586 | 587 | # Intel 32 bit, build with SSE and SSE2 instructions 588 | ifeq ($(findstring $(machine), i386 i686), $(machine)) 589 | arch.c.flags = -march=pentium4 -mfpmath=sse -msse -msse2 590 | endif 591 | 592 | # Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions 593 | ifeq ($(findstring $(machine), ia64 x86_64), $(machine)) 594 | arch.c.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 595 | endif 596 | 597 | 598 | #=== paths ===================================================================== 599 | 600 | 601 | # Default pkglibdir is specified above per operating system. It is aliased as 602 | # 'objectsdir' to retain compatibility with pd-extended template. Assignment 603 | # operator '?=' is used to enable a project-relative path definition in the 604 | # including makefile. 605 | objectsdir ?= $(pkglibdir) 606 | 607 | # base path where all components of the lib will be installed by default 608 | installpath := $(DESTDIR)$(objectsdir)/$(lib.name) 609 | 610 | # check if pdincludepath contains spaces (as is often the case on Windows) 611 | # if so, store the path so we can later do checks with it 612 | pdincludepathwithspaces := $(if $(word 2, $(pdincludepath)), $(pdincludepath)) 613 | 614 | 615 | #=== accumulated build flags =================================================== 616 | 617 | 618 | # From GNU make docs: 'Users expect to be able to specify CFLAGS freely 619 | # themselves.' So we use CFLAGS to define options which are not strictly 620 | # required for compilation: optimizations, architecture specifications, and 621 | # warnings. CFLAGS can be safely overriden using a make command argument. 622 | # Variables cflags, ldflags and ldlibs may be defined in including makefile. 623 | 624 | optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer 625 | warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing 626 | 627 | # suppress -Wunused-variable & Co if you don't want to clutter a build log 628 | ifdef suppress-wunused 629 | warn.flags += $(addprefix -Wno-unused-, function parameter value variable) 630 | endif 631 | 632 | CFLAGS = $(warn.flags) $(optimization.flags) $(arch.c.flags) 633 | 634 | # preprocessor flags 635 | cpp.flags += -DPD -I "$(pdincludepath)" $(CPPFLAGS) 636 | 637 | # architecture specifications for linker are overridable by LDFLAGS 638 | LDFLAGS := $(arch.ld.flags) 639 | 640 | # now add the same ld flags to shared dynamic lib 641 | shared.ldflags := $(shared.ldflags) $(LDFLAGS) 642 | 643 | # accumulated flags for C compiler / linker 644 | c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS) 645 | c.ldflags := $(c.ldflags) $(ldflags) $(LDFLAGS) 646 | c.ldlibs := $(c.ldlibs) $(ldlibs) 647 | 648 | # accumulated flags for C++ compiler / linker 649 | cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS) 650 | cxx.ldflags := $(cxx.ldflags) $(ldflags) $(LDFLAGS) 651 | cxx.ldlibs := $(cxx.ldlibs) $(ldlibs) 652 | 653 | 654 | ################################################################################ 655 | ### variables: tools ########################################################### 656 | ################################################################################ 657 | 658 | 659 | # aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument 660 | compile-c := $(CC) 661 | compile-cxx := $(CXX) 662 | 663 | 664 | ################################################################################ 665 | ### checks ##################################################################### 666 | ################################################################################ 667 | 668 | 669 | # At this point most variables are defined. Now do some checks and info's 670 | # before rules begin. 671 | 672 | # 'forward declaration' of default target, needed to do checks 673 | all: 674 | 675 | # To avoid unpredictable results, make sure the default target is not redefined 676 | # by including makefile. 677 | ifneq ($(.DEFAULT_GOAL), all) 678 | $(error Default target must be 'all'.) 679 | endif 680 | 681 | # find out which target(s) will be made 682 | ifdef MAKECMDGOALS 683 | goals := $(MAKECMDGOALS) 684 | else 685 | goals := all 686 | endif 687 | 688 | # store path to Pd API m_pd.h if it is found 689 | ifdef pdincludepath 690 | mpdh := $(shell ls "$(pdincludepath)/m_pd.h") 691 | endif 692 | 693 | # print Makefile.pdlibbuilder version 694 | $(info ++++ info: using Makefile.pdlibbuilder version $(version)) 695 | 696 | # when making target all, check if m_pd.h is found and print info about it 697 | ifeq ($(goals), all) 698 | $(if $(mpdh), \ 699 | $(info ++++ info: using Pd API $(mpdh)), \ 700 | $(warning Where is Pd API m_pd.h? Do 'make help' for info.)) 701 | endif 702 | 703 | # print target info 704 | $(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name))) 705 | 706 | # when installing, print installpath info 707 | $(if $(filter install install-lib, $(goals)), $(info ++++ info: \ 708 | installpath is '$(installpath)')) 709 | 710 | 711 | #=== define executables ======================================================== 712 | 713 | 714 | # By default we build class executables, and optionally a shared dynamic link 715 | # lib. When make-lib-executable=yes we build all classes into a single lib 716 | # executable, on the condition that variable lib.setup.sources is defined. 717 | 718 | ifeq ($(make-lib-executable),yes) 719 | $(if $(lib.setup.sources), ,\ 720 | $(error Can not build library blob because lib.setup.sources is undefined)) 721 | executables := $(lib.name).$(extension) 722 | else 723 | executables := $(classes.executables) $(shared.lib) 724 | endif 725 | 726 | 727 | ################################################################################ 728 | ### rules: special targets ##################################################### 729 | ################################################################################ 730 | 731 | 732 | # Disable built-in rules. If some target can't be built with the specified 733 | # rules, it should not be built at all. 734 | MAKEFLAGS += --no-builtin-rules 735 | 736 | .PRECIOUS: 737 | .SUFFIXES: 738 | .PHONY: all post build-lib \ 739 | $(classes) $(makefiledirs) $(makefiles) \ 740 | install install-executables install-datafiles install-datadirs \ 741 | force clean vars allvars depend help 742 | 743 | 744 | ################################################################################ 745 | ### rules: build targets ####################################################### 746 | ################################################################################ 747 | 748 | 749 | # Target all forces the build of targets [$(executables) post] in 750 | # deterministic order. Target $(executables) builds class executables plus 751 | # optional shared lib or alternatively a single lib executable when 752 | # make-lib-executable=true. Target post is optionally defined by 753 | # library makefile. 754 | 755 | all: post 756 | post: $(executables) 757 | 758 | all: 759 | $(info ++++info: target all in lib $(lib.name) completed) 760 | 761 | # build all with -g option turned on for debug symbols 762 | alldebug: c.flags += -g 763 | alldebug: cxx.flags += -g 764 | alldebug: all 765 | 766 | 767 | #=== class executable ========================================================== 768 | 769 | 770 | # recipe for linking objects in class executable 771 | # argument $1 = compiler type (c or cxx) 772 | # argument $2 = class basename 773 | define link-class 774 | $(compile-$1) \ 775 | $($1.ldflags) $($2.class.ldflags) \ 776 | -o $2.$(extension) \ 777 | $(addsuffix .o, $(basename $($2.class.sources))) \ 778 | $(addsuffix .o, $(basename $(common.sources))) \ 779 | $($1.ldlibs) $($2.class.ldlibs) $(shared.lib) 780 | endef 781 | 782 | # general rule for linking object files in class executable 783 | %.$(extension): $(shared.lib) 784 | $(info ++++ info: linking objects in $@ for lib $(lib.name)) 785 | $(if $(filter %.cc %.cpp, $($*.class.sources)), \ 786 | $(call link-class,cxx,$*), \ 787 | $(call link-class,c,$*)) 788 | 789 | 790 | #=== library blob ============================================================== 791 | 792 | 793 | # build all classes into single executable 794 | build-lib: $(lib.name).$(extension) 795 | $(info ++++ info: library blob $(lib.name).$(extension) completed) 796 | 797 | # recipe for linking objects in lib executable 798 | # argument $1 = compiler type (c or cxx) 799 | define link-lib 800 | $(compile-$1) \ 801 | $($1.ldflags) $(lib.ldflags) \ 802 | -o $(lib.name).$(extension) $(all.objects) \ 803 | $($1.ldlibs) $(lib.ldlibs) 804 | endef 805 | 806 | # rule for linking objects in lib executable 807 | # declared conditionally to avoid name clashes 808 | ifeq ($(make-lib-executable),yes) 809 | $(lib.name).$(extension): $(all.objects) 810 | $(if $(filter %.cc %.cpp, $(all.sources)), \ 811 | $(call link-lib,cxx), \ 812 | $(call link-lib,c)) 813 | endif 814 | 815 | 816 | #=== shared dynamic lib ======================================================== 817 | 818 | 819 | # recipe for linking objects in shared executable 820 | # argument $1 = compiler type (c or cxx) 821 | define link-shared 822 | $(compile-$1) \ 823 | $(shared.ldflags) \ 824 | -o lib$(lib.name).$(shared.extension) $(shared.objects) \ 825 | $($1.ldlibs) $(shared.ldlibs) 826 | endef 827 | 828 | # rule for linking objects in shared executable 829 | # build recipe is in macro 'link-shared' 830 | lib$(lib.name).$(shared.extension): $(shared.objects) 831 | $(info ++++ info: linking objects in shared lib $@) 832 | $(if $(filter %.cc %.cpp, $(shared.sources)), \ 833 | $(call link-shared,cxx), \ 834 | $(call link-shared,c)) 835 | 836 | 837 | #=== object files ============================================================== 838 | 839 | 840 | # recipe to make .o file from source 841 | # argument $1 is compiler type (c or cxx) 842 | define make-object-file 843 | $(info ++++ info: making $@ in lib $(lib.name)) 844 | $(compile-$1) \ 845 | $($1.flags) \ 846 | -o $@ -c $< 847 | endef 848 | 849 | # Three rules to create .o files. These are double colon 'terminal' rules, 850 | # meaning they are the last in a rules chain. 851 | 852 | %.o:: %.c 853 | $(call make-object-file,c) 854 | 855 | %.o:: %.cc 856 | $(call make-object-file,cxx) 857 | 858 | %.o:: %.cpp 859 | $(call make-object-file,cxx) 860 | 861 | 862 | #=== explicit prerequisites for class executables ============================== 863 | 864 | 865 | # For class executables, prerequisite rules are declared in run time. Target 866 | # 'depend' prints these rules for debugging purposes. 867 | 868 | # declare explicit prerequisites rule like 'class: class.extension' 869 | # argument $v is class basename 870 | define declare-class-target 871 | $v: $v.$(extension) 872 | endef 873 | 874 | # declare explicit prerequisites rule like 'class.extension: object1.o object2.o' 875 | # argument $v is class basename 876 | define declare-class-executable-target 877 | $v.$(extension): $(addsuffix .o, $(basename $($v.class.sources))) \ 878 | $(addsuffix .o, $(basename $(common.sources))) 879 | endef 880 | 881 | # evaluate explicit prerequisite rules for all classes 882 | $(foreach v, $(classes), $(eval $(declare-class-target))) 883 | $(foreach v, $(classes), $(eval $(declare-class-executable-target))) 884 | 885 | 886 | #=== implicit prerequisites for class executables ============================== 887 | 888 | 889 | # Evaluating implicit prerequisites (header files) with help from the 890 | # preprocessor is 'expensive' so this is done conditionally and selectively. 891 | # Note that it is also possible to trigger a build via install targets, in 892 | # which case implicit prerequisites are not checked. 893 | 894 | # When the Pd include path contains spaces it will mess up the implicit 895 | # prerequisites rules. Also it is known that multiple arch flags are 896 | # incompatible with preprocessor option -MM on OSX <= 10.5. Dependency 897 | # tracking must be disabled in those cases. 898 | 899 | oldfat := $(and $(filter ppc i386, $(machine)), \ 900 | $(filter-out 0 1, $(words $(filter -arch, $(c.flags))))) 901 | 902 | disable-dependency-tracking := $(strip $(pdincludepathwithspaces) $(oldfat)) 903 | 904 | ifndef disable-dependency-tracking 905 | must-build-everything := $(filter all, $(goals)) 906 | must-build-class := $(filter $(classes), $(goals)) 907 | must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources)) 908 | endif 909 | 910 | # declare implicit prerequisites rule like 'object.o: header1.h header2.h ...' 911 | # argument $1 is input source file(s) 912 | # dir is explicitly added because option -MM strips it by default 913 | define declare-object-target 914 | $(dir $1)$(filter %.o: %.h, $(shell $(CPP) $(c.flags) -MM $1)) $(MAKEFILE_LIST) 915 | endef 916 | 917 | # evaluate implicit prerequisite rules when rebuilding everything 918 | ifdef must-build-everything 919 | $(if $(wildcard $(all.objects)), \ 920 | $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \ 921 | $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v)))) 922 | endif 923 | 924 | # evaluate implicit prerequisite rules when selectively building classes 925 | ifdef must-build-class 926 | $(foreach v, $(must-build-sources), \ 927 | $(eval $(call declare-object-target, $v))) 928 | $(foreach v, $(shared.sources), \ 929 | $(eval $(call declare-object-target, $v))) 930 | endif 931 | 932 | 933 | ################################################################################ 934 | ### rules: preprocessor and assembly files ##################################### 935 | ################################################################################ 936 | 937 | 938 | # Preprocessor and assembly output files for bug tracing etc. They are not part 939 | # of the build processes for executables. By default these files are created in 940 | # the current working directory. Dependency tracking is not performed, the build 941 | # is forced instead to make sure it's up to date. 942 | 943 | force: 944 | 945 | 946 | #=== preprocessor file ========================================================= 947 | 948 | 949 | # make preprocessor output file with extension .pre 950 | # argument $1 = compiler type (c or cxx) 951 | define make-preprocessor-file 952 | $(info ++++ info: making preprocessor output file $(notdir $*.pre) \ 953 | in current working directory) 954 | $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre) 955 | endef 956 | 957 | %.pre:: %.c force 958 | $(call make-preprocessor-file,c) 959 | 960 | %.pre:: %.cc force 961 | $(call make-preprocessor-file,cxx) 962 | 963 | %.pre:: %.cpp force 964 | $(call make-preprocessor-file,cxx) 965 | 966 | 967 | #=== assembly file ============================================================= 968 | 969 | 970 | # make C / assembly interleaved output file with extension .lst 971 | # argument $1 = compiler type (c or cxx) 972 | define make-assembly-file 973 | $(info ++++ info: making assembly output file $(notdir $*.lst) \ 974 | in current working directory) 975 | $(compile-$1) \ 976 | -c -Wa,-a,-ad -fverbose-asm \ 977 | $($1.flags) \ 978 | $< > $(notdir $*.lst) 979 | endef 980 | 981 | %.lst:: %.c force 982 | $(call make-assembly-file,c) 983 | 984 | %.lst:: %.cc force 985 | $(call make-assembly-file,cxx) 986 | 987 | %.lst:: %.cpp force 988 | $(call make-assembly-file,cxx) 989 | 990 | 991 | ################################################################################ 992 | ### rules: installation targets ################################################ 993 | ################################################################################ 994 | 995 | 996 | # Install targets depend on successful exit status of target all because nothing 997 | # must be installed in case of a build error. 998 | 999 | 1000 | # -p = preserve time stamps 1001 | # -m = set permission mode (as in chmod) 1002 | # -d = create all components of specified directories 1003 | INSTALL = install 1004 | INSTALL_PROGRAM := $(INSTALL) -p -m 644 1005 | INSTALL_DATA := $(INSTALL) -p -m 644 1006 | INSTALL_DIR := $(INSTALL) -m 755 -d 1007 | 1008 | # strip spaces from file names 1009 | executables := $(strip $(executables)) 1010 | datafiles := $(strip $(datafiles)) 1011 | datadirs := $(strip $(datadirs)) 1012 | 1013 | # Do not make any install sub-target with empty variable definition because the 1014 | # install program would exit with an error. 1015 | install: $(if $(executables), install-executables) 1016 | install: $(if $(datafiles), install-datafiles) 1017 | install: $(if $(datadirs), install-datadirs) 1018 | 1019 | install-executables: all 1020 | $(INSTALL_DIR) -v "$(installpath)" 1021 | $(INSTALL_PROGRAM) $(executables) "$(installpath)" 1022 | $(info ++++ info: executables of lib $(lib.name) installed \ 1023 | from $(CURDIR) to $(installpath)) 1024 | 1025 | install-datafiles: all 1026 | $(INSTALL_DIR) -v "$(installpath)" 1027 | $(INSTALL_DATA) $(datafiles) "$(installpath)" 1028 | $(info ++++ info: data files of lib $(lib.name) installed \ 1029 | from $(CURDIR) to $(installpath)) 1030 | 1031 | install-datadirs: all 1032 | $(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";) 1033 | $(foreach v, $(datadirs), \ 1034 | $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";) 1035 | $(info ++++ info: data directories of lib $(lib.name) installed \ 1036 | from $(CURDIR) to $(installpath)) 1037 | 1038 | 1039 | ################################################################################ 1040 | ### rules: distribution targets ################################################ 1041 | ################################################################################ 1042 | 1043 | 1044 | # TODO 1045 | # These targets are implemented in Makefile Template, but I have to figure out 1046 | # how to do it under the not-so-strict conditions of Makefile.pdlibbuilder. 1047 | 1048 | # make source package 1049 | dist: 1050 | @echo "target dist not yet implemented" 1051 | 1052 | # make Debian source package 1053 | dpkg-source: 1054 | @echo "target dpkg-source not yet implemented" 1055 | 1056 | $(ORIGDIR): 1057 | 1058 | $(DISTDIR): 1059 | 1060 | 1061 | ################################################################################ 1062 | ### rules: clean targets ####################################################### 1063 | ################################################################################ 1064 | 1065 | 1066 | # delete build products from build tree 1067 | clean: 1068 | rm -f $(all.objects) 1069 | rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib) 1070 | rm -f *.pre *.lst 1071 | 1072 | # remove distribution directories and tarballs from build tree 1073 | distclean: clean 1074 | @echo "target distclean not yet implemented" 1075 | 1076 | 1077 | ################################################################################ 1078 | ### rules: submake targets ##################################################### 1079 | ################################################################################ 1080 | 1081 | 1082 | # Iterate over sub-makefiles or makefiles in other directories. 1083 | 1084 | # When 'continue-make=yes' is set, sub-makes will report 'true' to the parent 1085 | # process regardless of their real exit status. This prevents the parent make 1086 | # from being aborted by a sub-make error. Useful when you want to quickly find 1087 | # out which sub-makes from a large set will succeed. 1088 | ifeq ($(continue-make),yes) 1089 | continue = || true 1090 | endif 1091 | 1092 | # These targets will trigger sub-make processes for entries in 'makefiledirs' 1093 | # and 'makefiles'. 1094 | all alldebug install clean distclean dist dkpg-source: \ 1095 | $(makefiledirs) $(makefiles) 1096 | 1097 | # this expands to identical rules for each entry in 'makefiledirs' 1098 | $(makefiledirs): 1099 | $(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue) 1100 | 1101 | # this expands to identical rules for each entry in 'makefiles' 1102 | $(makefiles): 1103 | $(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue) 1104 | 1105 | 1106 | ################################################################################ 1107 | ### rules: convenience targets ################################################# 1108 | ################################################################################ 1109 | 1110 | 1111 | #=== show variables ============================================================ 1112 | 1113 | 1114 | # Several 'function' macro's cause errors when expanded within a rule or without 1115 | # proper arguments. Variables which are set with the define directive are only 1116 | # shown by name for that reason. 1117 | functions = \ 1118 | add-class-source \ 1119 | declare-class-target \ 1120 | declare-class-executable-target \ 1121 | declare-object-target \ 1122 | link-class \ 1123 | link-lib \ 1124 | link-shared \ 1125 | make-object-file \ 1126 | make-preprocessor-file \ 1127 | make-assembly-file 1128 | 1129 | 1130 | # show variables from makefiles 1131 | vars: 1132 | $(info ++++ info: showing makefile variables:) 1133 | $(foreach v,\ 1134 | $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\ 1135 | $(if $(filter file, $(origin $v)),\ 1136 | $(info variable $v = $($v)))) 1137 | $(foreach v, $(functions), $(info 'function' name: $v)) 1138 | @echo 1139 | 1140 | # show all variables 1141 | allvars: 1142 | $(info ++++ info: showing default, automatic and makefile variables:) 1143 | $(foreach v, \ 1144 | $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \ 1145 | $(info variable ($(origin $v)) $v = $($v))) 1146 | $(foreach v, $(functions), $(info 'function' name: $v)) 1147 | @echo 1148 | 1149 | 1150 | #=== show dependencies ========================================================= 1151 | 1152 | 1153 | # show generated prerequisites rules 1154 | depend: 1155 | $(info ++++ info: generated prerequisite rules) 1156 | $(foreach v, $(classes), $(info $(declare-class-target))) 1157 | $(foreach v, $(classes), $(info $(declare-class-executable-target))) 1158 | $(foreach v, $(all.sources), $(info $(call declare-object-target, $v))) 1159 | @echo 1160 | 1161 | 1162 | #=== show help text ============================================================ 1163 | 1164 | 1165 | # brief info about targets and paths 1166 | 1167 | ifdef mpdh 1168 | mpdhinfo := $(mpdh) 1169 | else 1170 | mpdhinfo := m_pd.h was not found. Is Pd(-extended) installed? 1171 | endif 1172 | 1173 | help: 1174 | @echo 1175 | @echo " Main targets:" 1176 | @echo " all: build executables (default target)" 1177 | @echo " install: install all components of the library" 1178 | @echo " vars: print makefile variables for troubleshooting" 1179 | @echo " allvars: print all variables for troubleshooting" 1180 | @echo " help: print this help text" 1181 | @echo 1182 | @echo " Pd API m_pd.h:" 1183 | @echo " $(mpdhinfo)" 1184 | @echo " You may specify your preferred Pd include path as argument to" 1185 | @echo " the make command, like 'pdincludepath=path/to/pd/src'." 1186 | @echo 1187 | @echo " Path for installation of your libdir(s):" 1188 | @echo " $(objectsdir)" 1189 | @echo " Alternatively you may specify your path for installation as argument" 1190 | @echo " to the make command, like 'objectsdir=path/to/pd-externals'." 1191 | @echo 1192 | @echo " Default paths are listed in the doc sections in Makefile.pdlibbuilder." 1193 | @echo 1194 | 1195 | 1196 | #=== dummy target ============================================================== 1197 | 1198 | 1199 | coffee: 1200 | @echo "Makefile.pdlibbuilder: Can not make coffee. Sorry." 1201 | 1202 | 1203 | ################################################################################ 1204 | ### end of rules sections ###################################################### 1205 | ################################################################################ 1206 | 1207 | 1208 | # for syntax highlighting in vim and github 1209 | # vim: set filetype=make: 1210 | 1211 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | DISIS/L2Ork Sensel Purr-Data (and Pure-Data) external for interfacing with the Sensel Morph 2 | by Rachel Hachem and Ivica Ico Bukvic 3 | http://l2ork.icat.vt.edu 4 | Released under the GPL v3 license 5 | 6 | 7 | 8 | CHANGELOG 9 | --------- 10 | 2020-04-13 0.9.0 11 | Initial release by Rachel Hachem 12 | under the guidance of Ivica Ico Bukvic 13 | 14 | 2020-05-20 1.0.0 15 | Threaded implementation with additional features, 16 | including, disconnect, free, identify, improved 17 | console output, versioning, and updated help file by 18 | Ivica Ico Bukvic 19 | 20 | 2020-05-22 v.1.1.0 21 | Improved integration of the contacts API to fix 22 | contact id and provide contact status, as well as 23 | address missed contact status changes, reworked 24 | polling logic and removed reliance on the external 25 | metro, added total contact count, and setting the 26 | polling time by Ivica Ico Bukvic 27 | 28 | 2020-05-22 v.1.2.0 29 | Introduced ability to change LED brightness and 30 | further improved the help file by Ivica Ico Bukvic 31 | 32 | 33 | 34 | 35 | BUILD INSTRUCTIONS 36 | ------------------ 37 | To build for Purr-Data (pd-vanilla setup may be similar with some subtle changes in the include paths and likely does not require MSYS environment, so on Windows changes may be more significant): 38 | 39 | 40 | 41 | 1) Set up a build environment: 42 | 43 | On Windows follow instructions on setting up the MSYS2 environment for Purr-Data (make sure it matches your OS in terms of 32-bit vs 64-bit--most modern iterations of Windows are 64-bit). Info on how to do this can be found here: https://github.com/agraef/purr-data/blob/master/README.md#windows-32-bit-using-msys2 44 | 45 | On Linux and OSX make sure you have your build gcc environment all set up (consult the OS documentation) 46 | 47 | 48 | 49 | 2) Install the Sensel lib for your OS found at https://github.com/sensel/sensel-api/tree/master/sensel-install 50 | 51 | 52 | 53 | 3) Using a terminal (in Windows use the MSYS2 MinGW 32-bit shell) go into this folder and run the following command (these options are assuming you have everything installed in a default path--if you don't you will need to adjust paths accordingly): 54 | 55 | Linux: make pdincludepath=/usr/include/pd-l2ork/ 56 | 57 | OSX: make pdincludepath=/Applications/Pd-l2ork.app/Contents/Resources/app.nw/include/pd-l2ork/ 58 | 59 | Windows: make pdincludepath=/c/Program\ Files\ \(x86\)/Purr\ Data/include/pdl2ork pdbinpath=/c/Program\ Files\ \(x86\)/Purr\ Data/bin/ 60 | 61 | 62 | 63 | 4) If everything compiles correctly, you should be able to run Purr-Data and open the sensel-help.pd to test it out. 64 | 65 | 66 | 67 | Currently, the external only supports detecting of individual contact points and their traits. Future revisions should focus on outputting the grayscale matrix of the surface pressure in a Gem-compatible format (and/or using other Pure-Data-compatible matrix formats that may be used by alternative visual data processing libraries). 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DISIS/L2Ork Sensel 2 | 3 | [Purr-Data](https://agraef.github.io/purr-data/) and [Pure-Data](http://msp.ucsd.edu/software.html) external for interfacing with the [Sensel Morph](http://sensel.com/morph) 4 | 5 | by [Rachel Hachem](https://github.com/rachelhachem) and Ivica Ico Bukvic 6 | 7 | Part of the [ICAT Laptop Orchestra at Virgina Tech](http://l2ork.icat.vt.edu) 8 | 9 | Released under the [GPL v3 license](https://www.gnu.org/licenses/gpl-3.0.en.html) 10 | 11 | # SIMPLE INSTALLATION 12 | 13 | Use the deken package manager to install the externals. In Pure Data, go to the "Help" menu and select **Find Externals**. Search for `sensel` or `senselmorph` and you will be given installation options. 14 | 15 | Install in Documents/Pd/ as recommmended by deken, unless you have a non-standard installation. 16 | 17 | This installs the objects as well as helpfiles and several examples that can be found in your /Pd/externals/senselmorph folder. 18 | 19 | Here's what this looks like on a Mac after selecting a package to install in the deken panel - windows and linux are very simlar: 20 | ![Installing Sensel objects in Pure Data with Deken package manager](./deken_install_example.png) 21 | 22 | # BUILD INSTRUCTIONS 23 | 24 | To build for Purr-Data (pd-vanilla setup may be similar with some subtle changes in the include paths and likely does not require MSYS environment, so on Windows changes may be more significant): 25 | 26 | 1. Set up a build environment: 27 | 28 | * On Windows follow instructions on setting up the MSYS2 environment for Purr-Data (make sure it matches your OS in terms of 32-bit vs 64-bit--most modern iterations of Windows are 64-bit). Info on how to do this can be found in the [purr-data repository.](https://github.com/agraef/purr-data/blob/master/README.md#windows-32-bit-using-msys2) 29 | 30 | * On Linux and OSX make sure you have your build gcc environment all set up (consult the OS documentation) 31 | 32 | 2. Install the Sensel lib for your OS found in the [Sensel API repo](https://github.com/sensel/sensel-api/tree/master/sensel-install) 33 | 34 | 3. Using a terminal (in Windows use the MSYS2 MinGW 32-bit shell) go into this folder and run the following command (these options are assuming you have everything installed in a default path--if you don't you will need to adjust paths accordingly): 35 | 36 | * Linux: `make pdincludepath=/usr/include/pd-l2ork/` 37 | 38 | * OSX: `make pdincludepath=/Applications/Pd-l2ork.app/Contents/Resources/app.nw/include/pd-l2ork/` 39 | 40 | * Windows: `make pdincludepath=/c/Program\ Files\ \(x86\)/Purr\ Data/include/pdl2ork pdbinpath=/c/Program\ Files\ \(x86\)/Purr\ Data/bin/` 41 | 42 | 4. If everything compiles correctly, you should be able to run Purr-Data or Pure Data Vanilla and open the `sensel-help.pd` to test it out. 43 | 44 | # INSTALLATION 45 | Future installations will be mediated by the [deken](https://github.com/pure-data/deken) package manager. If you need to install from this repository, use the following directions. 46 | 47 | ## macOS 48 | 49 | ### Purr Data 50 | 51 | ### Vanilla PD 52 | 53 | Copy the 54 | ``` 55 | sensel.pd_darwin 56 | sensel-help.pd 57 | sensel-led.pd 58 | ``` 59 | files from this repo to your `~/Documents/Pd` folder. You may want to make a "sensel" directory so you can put these files in `~/Documents/Pd/sensel`. 60 | 61 | ## Windows 62 | 63 | ### Purr Data 64 | 65 | ### Vanilla PD 66 | 67 | Copy the 68 | ``` 69 | sensel.dll 70 | sensel-help.pd 71 | sensel-led.pd 72 | LibSensel.dll 73 | LibSensel.lib 74 | LibSenselDecompress.dll 75 | LibSenselDecompress.lib 76 | ``` 77 | files from this repo to your user `Documents/Pd` folder. You may want to make a "sensel" directory so you can put these files in user `/Documents/Pd/sensel`. 78 | 79 | 80 | ## Linux 81 | 82 | ### Purr Data 83 | 84 | ### Vanilla PD 85 | 86 | Copy the 87 | ``` 88 | sensel.pd_linux 89 | sensel-help.pd 90 | sensel-led.pd 91 | ``` 92 | files from this repo to your `~/Documents/Pd` folder. You may want to make a "sensel" directory so you can put these files in `~/Documents/Pd/sensel`. 93 | 94 | # USE 95 | 96 | ## Messages to the `sensel` object inlet: 97 | 98 | * `discover`: discovers and connects to the first available sensel morph device 99 | * `identify:` lists all sensel morph devices' serial numbers in the console 100 | * `disconnect`: disconnects from a connected sensel morph device 101 | * `connect `: connects to a device with a matching serial number 102 | * `poll`: sets the polling rate in ms (1-100) at which the contact data is outputted. Each contact has 20 arguments described below 103 | * `led `: sets the sensel morph led brightness. Note that sending a lot of led messages can quickly bog down the sensel devicem so rate control is encouraged (e.g. see the sensel-led abstraction) 104 | 105 | 106 | ## Messages from `sensel` object outlets: 107 | 108 | ### right outlet 109 | Indicates connection status (1=connected, 0=disconnected) 110 | 111 | ### left outlet 112 | List of all (maximum 16) contact points, with each contact output as a list consisting of 20 arguments: 113 | 114 | 1. contact point number 115 | 2. contact status (0=invalid , 1=start , 2=move , 3=end) 116 | 3. orientation 117 | 4. major axis 118 | 5. minor axis 119 | 6. delta x 120 | 7. delta y 121 | 8. delta force 122 | 9. delta area 123 | 10. min x 124 | 11. min y 125 | 12. max x 126 | 13. max y 127 | 14. peak x 128 | 15. peak y 129 | 16. peak force 130 | 17. x position 131 | 18. y position 132 | 19. total force 133 | 20. area 134 | 135 | More detailed descriptions of the contact data can be found in the [Sensel API guide.](http://guide.sensel.com/api/#contact-data) 136 | 137 | # NOTES 138 | Currently, the external only supports detecting of individual contact points and their traits. Future revisions should focus on outputting the grayscale matrix of the surface pressure in a Gem-compatible format (and/or using other Pure-Data-compatible matrix formats that may be used by alternative visual data processing libraries). 139 | 140 | # CHANGELOG 141 | 142 | ### 2020-04-13 0.9.0 143 | 144 | Initial release by Rachel Hachem under the guidance of Ivica Ico Bukvic. 145 | 146 | ### 2020-05-20 1.0.0 147 | 148 | Threaded implementation with additional features, including, disconnect, free, identify, improved console output, versioning, and updated help file by Ivica Ico Bukvic . 149 | 150 | ### 2020-05-22 v.1.1.0 151 | 152 | Improved integration of the contacts API to fix contact id and provide contact status, as well as address missed contact status changes, reworked polling logic and removed reliance on the external metro, added total contact count, and setting the polling time by Ivica Ico Bukvic. 153 | Added SimpleSenselSynth example by [Peter Nyboer](https://github.com/nyboer). 154 | 155 | ### 2020-05-22 v.1.2.0 156 | 157 | Introduced ability to change LED brightness and further improved the help file by Ivica Ico Bukvic. 158 | -------------------------------------------------------------------------------- /SENSEL_LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-2017 Sensel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /deken_install_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensel/PD-objects/50f70168c2d182ceb5d8355c7dfdfd4ec95a842f/deken_install_example.png -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # Sensel requires Sensel API, so the user needs to download it from https://github.com/sensel/sensel-api 2 | # Next go to sensel-install inside the downloaded git repository and install the OSX pkg file 3 | # Only then will this build cleanly 4 | 5 | sensel.class.sources = sensel.c 6 | sensel.class.ldlibs = -L./ -lsensel 7 | 8 | define forWindows 9 | sensel.class.ldlibs = -L/C/Program\ Files/Sensel/SenselLib/x86 -lsensel 10 | CPPFLAGS += -I./sensel-win-msys-include 11 | endef 12 | 13 | datafiles = sensel-help.pd sensel-led.pd 14 | 15 | include Makefile.pdlibbuilder.revised 16 | -------------------------------------------------------------------------------- /sensel-help.pd: -------------------------------------------------------------------------------- 1 | #N canvas 58 52 1296 693 10; 2 | #X obj 698 169 cnv 15 174 83 empty empty empty 20 12 0 14 -261689 -66577 3 | 0; 4 | #X obj 490 136 sensel; 5 | #X obj 523 159 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 6 | 1; 7 | #X msg 490 14 discover; 8 | #X msg 569 39 connect SM01174813923; 9 | #X msg 490 39 disconnect; 10 | #X msg 490 64 identify; 11 | #X text 540 158 connection indicator; 12 | #X msg 569 64 connect SM01172411629; 13 | #X text 15 81 Released under the GPL v3 License: https://www.gnu.org/licenses/gpl-3.0.en.html 14 | , f 45; 15 | #X text 15 186 disconnect: disconnects from a connected sensel morph 16 | device, f 75; 17 | #X text 15 135 discover: discovers and connects to the first available 18 | sensel morph device, f 75; 19 | #X text 15 152 identify: lists all available sensel morph devices' 20 | serial numbers, f 69; 21 | #X text 15 118 INPUTS:; 22 | #X text 15 283 OUTPUTS:; 23 | #X text 15 347 1: contact point number; 24 | #X floatatom 655 402 5 0 0 0 X: - -, f 5; 25 | #X text 15 300 right outlet: indicates connection status (1=connected 26 | \, 0=disconnected), f 72; 27 | #X floatatom 709 402 5 0 0 0 Y: - -, f 5; 28 | #X floatatom 788 402 5 0 0 0 Force: - -, f 5; 29 | #X text 563 401 1st contact; 30 | #X floatatom 672 464 5 0 0 0 X: - -, f 5; 31 | #X floatatom 726 464 5 0 0 0 Y: - -, f 5; 32 | #X floatatom 805 464 5 0 0 0 Force: - -, f 5; 33 | #X text 580 463 2nd contact; 34 | #X floatatom 689 526 5 0 0 0 X: - -, f 5; 35 | #X floatatom 743 526 5 0 0 0 Y: - -, f 5; 36 | #X floatatom 822 526 5 0 0 0 Force: - -, f 5; 37 | #X floatatom 707 588 5 0 0 0 X: - -, f 5; 38 | #X floatatom 761 588 5 0 0 0 Y: - -, f 5; 39 | #X floatatom 840 588 5 0 0 0 Force: - -, f 5; 40 | #X floatatom 724 650 5 0 0 0 X: - -, f 5; 41 | #X floatatom 778 650 5 0 0 0 Y: - -, f 5; 42 | #X floatatom 857 650 5 0 0 0 Force: - -, f 5; 43 | #X obj 890 136 sensel; 44 | #X obj 923 159 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 45 | 1; 46 | #X msg 890 14 discover; 47 | #X msg 971 38 connect SM01174813923; 48 | #X msg 890 38 disconnect; 49 | #X msg 890 64 identify; 50 | #X text 940 158 connection indicator; 51 | #X msg 971 62 connect SM01172411629; 52 | #X floatatom 1056 402 5 0 0 0 X: - -, f 5; 53 | #X floatatom 1109 402 5 0 0 0 Y: - -, f 5; 54 | #X floatatom 1188 402 5 0 0 0 Force: - -, f 5; 55 | #X text 964 401 1st contact; 56 | #X floatatom 1073 464 5 0 0 0 X: - -, f 5; 57 | #X floatatom 1126 464 5 0 0 0 Y: - -, f 5; 58 | #X floatatom 1205 464 5 0 0 0 Force: - -, f 5; 59 | #X text 981 463 2nd contact; 60 | #X floatatom 1090 524 5 0 0 0 X: - -, f 5; 61 | #X floatatom 1143 524 5 0 0 0 Y: - -, f 5; 62 | #X floatatom 1222 524 5 0 0 0 Force: - -, f 5; 63 | #X floatatom 1108 588 5 0 0 0 X: - -, f 5; 64 | #X floatatom 1161 588 5 0 0 0 Y: - -, f 5; 65 | #X floatatom 1240 588 5 0 0 0 Force: - -, f 5; 66 | #X floatatom 1125 650 5 0 0 0 X: - -, f 5; 67 | #X floatatom 1178 650 5 0 0 0 Y: - -, f 5; 68 | #X floatatom 1257 650 5 0 0 0 Force: - -, f 5; 69 | #X text 15 169 connect : connects to a device with a 70 | matching serial number, f 75; 71 | #X text 934 123 This is a second instance for connecting second sensel 72 | to the same computer, f 42; 73 | #X obj 698 301 print output_from_sensel_1; 74 | #X obj 490 377 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 75 | #X text 15 364 2: contact status (0=invalid \, 1=start \, 2=move \, 76 | 3=end); 77 | #X text 15 381 3: orientation; 78 | #X text 15 398 4: major axis; 79 | #X text 15 415 5: minor axis; 80 | #X text 15 432 6: delta x; 81 | #X text 15 449 7: delta y; 82 | #X text 15 466 8: delta force; 83 | #X text 15 483 9: delta area; 84 | #X text 15 500 10: min x; 85 | #X text 15 517 11: min y; 86 | #X text 15 534 12: max x; 87 | #X text 15 551 13: max y; 88 | #X text 15 568 14: peak x; 89 | #X text 15 585 15: peak y; 90 | #X text 15 602 16: peak force; 91 | #X text 15 619 17: x position; 92 | #X text 15 636 18: y position; 93 | #X text 15 653 19: total force; 94 | #X text 15 670 20: area; 95 | #X text 15 317 left outlet: list of all contact points \, with each 96 | contact outputted as a list consisting of 20 arguments:, f 68; 97 | #X obj 507 439 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 98 | #X obj 524 501 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 99 | #X obj 542 563 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 100 | #X obj 559 625 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 101 | #X text 597 525 3rd contact; 102 | #X text 615 587 4th contact; 103 | #X text 632 649 5th contact; 104 | #X text 998 523 3rd contact; 105 | #X text 1016 587 4th contact; 106 | #X text 1033 649 5th contact; 107 | #X obj 959 625 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 108 | #X obj 942 563 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 109 | #X obj 924 501 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 110 | #X obj 907 439 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 111 | #X obj 890 377 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 112 | #X floatatom 698 350 5 0 0 0 - - -, f 5; 113 | #X text 734 350 total number of contacts; 114 | #X text 496 221 The route object focuses only on the first 5 points 115 | \, plus the total number of contacts. simply add more \, as needed 116 | \, up to the sensel morph's supported limit., f 32; 117 | #X msg 714 63 poll \$1; 118 | #X obj 714 44 nbx 5 14 1 100 0 1 empty empty empty 0 -8 0 10 -262144 119 | -1 -1 10 256 0; 120 | #X obj 281 439 timer; 121 | #X obj 281 418 t b b; 122 | #X floatatom 281 460 5 0 0 0 - - -, f 5; 123 | #X text 498 317 Since we already stripped the first argument (contact 124 | point number) \, unpacks below only have 19 arguments., f 28; 125 | #X obj 625 106 r led; 126 | #X text 663 92 Messages from below that set the sensel LEDs. The message 127 | format is: led , f 36; 128 | #X text 15 203 poll: sets the polling rate in ms (1-100) at which the 129 | contact data is outputted. Each contact has 20 arguments described 130 | below., f 75; 131 | #X obj 840 608 sensel-led 3; 132 | #X obj 857 670 sensel-led 4; 133 | #X obj 822 546 sensel-led 2; 134 | #X obj 805 484 sensel-led 1; 135 | #X obj 788 422 sensel-led 0; 136 | #X obj 490 295 route 0 1 2 3 4; 137 | #X obj 698 329 route contacts; 138 | #X obj 490 179 t a a a; 139 | #X floatatom 989 316 5 0 0 0 - - -, f 5; 140 | #X obj 890 295 route 0 1 2 3 4; 141 | #X obj 989 295 route contacts; 142 | #N canvas 0 22 450 300 META 0; 143 | #X text 30 62 DESCRIPTION L2Ork external for the Sensel Morph multitouch 144 | controller; 145 | #X text 30 42 LICENSE GPL v3; 146 | #X text 30 22 KEYWORDS controller multitouch Sensel Morph L2Ork; 147 | #X text 30 95 INLET_0 connect disconnect discover identify poll led 148 | ; 149 | #X text 30 115 OUTLET_0 numbered contacts list (20 args) and contacts 150 | message showing the current total number of contacts; 151 | #X text 30 148 LIBRARY external; 152 | #X text 30 168 AUTHOR Rachel Hachem and Ivica Ico Bukvic; 153 | #X text 30 188 WEBSITE http://l2ork.icat.vt.edu; 154 | #X text 30 208 RELEASE_DATE 2020; 155 | #X text 30 228 HELP_PATCH_AUTHORS Ivica Ico Bukvic; 156 | #X restore 211 671 pd META; 157 | #X obj 191 548 cnv 15 249 116 empty empty empty 20 12 0 14 -261689 158 | -66577 0; 159 | #X text 15 233 led : sets the sensel morph 160 | led brightness \, sending a lot of led messages can quickly bog down 161 | the sensel device \, so rate control is encouraged (e.g. see the sensel-led 162 | abstraction)., f 76; 163 | #X text 15 51 Developed in collaboration with the Sensel Inc. Special 164 | thanks to Peter Nyboer for his support. See README for version info. 165 | , f 67; 166 | #X text 15 31 by Rachel Hachem and Ivica Ico Bukvic 167 | , f 68; 168 | #X text 15 14 DISIS/L2Ork Sensel Morph external; 169 | #X text 261 671 http://l2ork.icat.vt.edu; 170 | #X text 320 419 The number to the left shows time in ms between sensel 171 | frames. It varies based on the number of contacts \, LED messages to 172 | the Sensel object \, and may be useful for setting a reasonable polling 173 | rate)., f 27; 174 | #X obj 890 179 t a a; 175 | #X obj 730 258 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 176 | 1; 177 | #X text 747 257 Toggle console output; 178 | #X text 705 176 WARNING! Copious and prolonged console output in purr-data 179 | only can over time adversely affect the overall performance., f 26 180 | ; 181 | #X text 200 556 IMPORTANT! On Linux \, to be able to connect to the 182 | sensel device \, you may need to adjust permissions for accessing the 183 | ttyACM* (serial) devices by adding your user to the dialout group by 184 | typing in terminal:, f 38; 185 | #X text 200 638 sudo adduser dialout; 186 | #X obj 698 279 spigot; 187 | #X text 714 14 Set internal polling time (1-100ms \, default 10ms) 188 | , f 26; 189 | #X connect 1 0 117 0; 190 | #X connect 1 1 2 0; 191 | #X connect 3 0 1 0; 192 | #X connect 4 0 1 0; 193 | #X connect 5 0 1 0; 194 | #X connect 6 0 1 0; 195 | #X connect 8 0 1 0; 196 | #X connect 19 0 114 0; 197 | #X connect 23 0 113 0; 198 | #X connect 27 0 112 0; 199 | #X connect 30 0 110 0; 200 | #X connect 33 0 111 0; 201 | #X connect 34 0 129 0; 202 | #X connect 34 1 35 0; 203 | #X connect 36 0 34 0; 204 | #X connect 37 0 34 0; 205 | #X connect 38 0 34 0; 206 | #X connect 39 0 34 0; 207 | #X connect 41 0 34 0; 208 | #X connect 62 15 16 0; 209 | #X connect 62 16 18 0; 210 | #X connect 62 17 19 0; 211 | #X connect 83 15 21 0; 212 | #X connect 83 16 22 0; 213 | #X connect 83 17 23 0; 214 | #X connect 84 15 25 0; 215 | #X connect 84 16 26 0; 216 | #X connect 84 17 27 0; 217 | #X connect 85 15 28 0; 218 | #X connect 85 16 29 0; 219 | #X connect 85 17 30 0; 220 | #X connect 86 15 31 0; 221 | #X connect 86 16 32 0; 222 | #X connect 86 17 33 0; 223 | #X connect 93 15 56 0; 224 | #X connect 93 16 57 0; 225 | #X connect 93 17 58 0; 226 | #X connect 94 15 53 0; 227 | #X connect 94 16 54 0; 228 | #X connect 94 17 55 0; 229 | #X connect 95 15 50 0; 230 | #X connect 95 16 51 0; 231 | #X connect 95 17 52 0; 232 | #X connect 96 15 46 0; 233 | #X connect 96 16 47 0; 234 | #X connect 96 17 48 0; 235 | #X connect 97 15 42 0; 236 | #X connect 97 16 43 0; 237 | #X connect 97 17 44 0; 238 | #X connect 101 0 1 0; 239 | #X connect 102 0 101 0; 240 | #X connect 103 0 105 0; 241 | #X connect 104 0 103 0; 242 | #X connect 104 1 103 1; 243 | #X connect 107 0 1 0; 244 | #X connect 115 0 62 0; 245 | #X connect 115 0 104 0; 246 | #X connect 115 1 83 0; 247 | #X connect 115 2 84 0; 248 | #X connect 115 3 85 0; 249 | #X connect 115 4 86 0; 250 | #X connect 116 0 98 0; 251 | #X connect 117 0 115 0; 252 | #X connect 117 1 116 0; 253 | #X connect 117 2 135 0; 254 | #X connect 119 0 97 0; 255 | #X connect 119 1 96 0; 256 | #X connect 119 2 95 0; 257 | #X connect 119 3 94 0; 258 | #X connect 119 4 93 0; 259 | #X connect 120 0 118 0; 260 | #X connect 129 0 119 0; 261 | #X connect 129 1 120 0; 262 | #X connect 130 0 135 1; 263 | #X connect 135 0 61 0; 264 | -------------------------------------------------------------------------------- /sensel-led.pd: -------------------------------------------------------------------------------- 1 | #N canvas 643 247 336 420 10; 2 | #X obj 228 118 inlet; 3 | #X obj 199 95 loadbang; 4 | #X obj 126 373 s led; 5 | #X obj 199 118 \$1; 6 | #X obj 171 182 pack 0 0 0; 7 | #X obj 114 27 loadbang; 8 | #X obj 171 205 t l l; 9 | #X msg 198 226 \$3; 10 | #X obj 198 247 change; 11 | #X obj 198 268 t 1; 12 | #X msg 126 351 led \$2 \$3; 13 | #X obj 126 321 t l 0; 14 | #X obj 114 49 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 15 | 1; 16 | #X obj 132 49 loadbang; 17 | #X obj 132 71 \$2; 18 | #X obj 132 93 sel 0; 19 | #X text 16 360 ARGUMENTS:; 20 | #X text 16 377 1: LED id; 21 | #X text 16 393 2: output rate (default 10ms); 22 | #X obj 114 118 metro 10; 23 | #X obj 126 296 spigot; 24 | #X obj 228 140 moses 100; 25 | #X msg 279 161 100; 26 | #X connect 0 0 21 0; 27 | #X connect 1 0 3 0; 28 | #X connect 3 0 4 1; 29 | #X connect 4 0 6 0; 30 | #X connect 5 0 12 0; 31 | #X connect 6 0 20 0; 32 | #X connect 6 1 7 0; 33 | #X connect 7 0 8 0; 34 | #X connect 8 0 9 0; 35 | #X connect 9 0 20 1; 36 | #X connect 10 0 2 0; 37 | #X connect 11 0 10 0; 38 | #X connect 11 1 20 1; 39 | #X connect 12 0 19 0; 40 | #X connect 13 0 14 0; 41 | #X connect 14 0 15 0; 42 | #X connect 15 1 19 1; 43 | #X connect 19 0 4 0; 44 | #X connect 20 0 11 0; 45 | #X connect 21 0 4 2; 46 | #X connect 21 1 22 0; 47 | #X connect 22 0 4 2; 48 | -------------------------------------------------------------------------------- /sensel-win-msys-include/sensel.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************************** 2 | * MIT License 3 | * 4 | * Copyright (c) 2013-2017 Sensel, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | ******************************************************************************************/ 24 | 25 | #ifndef __SENSEL_H__ 26 | #define __SENSEL_H__ 27 | 28 | #ifdef WIN32 29 | #include 30 | #else 31 | #define WINAPI 32 | #endif 33 | 34 | #ifdef SENSEL_EXPORTS 35 | #define SENSEL_API __declspec(dllexport) 36 | #else 37 | #define SENSEL_API __declspec(dllimport) 38 | #endif 39 | 40 | #ifndef WIN32 41 | #ifdef SENSEL_API 42 | #undef SENSEL_API 43 | #define SENSEL_API __attribute__ ((visibility ("default"))) 44 | #endif 45 | #endif 46 | 47 | #define SENSEL_MAX_DEVICES 16 // Maximum number of devices supported by the API 48 | 49 | #define FRAME_CONTENT_PRESSURE_MASK 0x01 // Mask indicating that the frame includes pressure data 50 | #define FRAME_CONTENT_LABELS_MASK 0x02 // Mask indicating that the frame includes labels data 51 | #define FRAME_CONTENT_CONTACTS_MASK 0x04 // Mask indicating that the frame includes contacts data 52 | #define FRAME_CONTENT_ACCEL_MASK 0x08 // Mask indicating that the frame includes acceleromter data 53 | 54 | #define CONTACT_MASK_ELLIPSE 0x01 // Mask indicating that the contact data contains ellipse info 55 | #define CONTACT_MASK_DELTAS 0x02 // Mask indicating that the contact data contains deltas info 56 | #define CONTACT_MASK_BOUNDING_BOX 0x04 // Mask indicating that the contact data contains bound box info 57 | #define CONTACT_MASK_PEAK 0x08 // Mask indicating that the contact data contains peak info 58 | 59 | #ifdef __cplusplus 60 | extern "C" { 61 | #endif 62 | 63 | /*! 64 | * @discussion Handle to a Sensel device 65 | */ 66 | typedef void *SENSEL_HANDLE; 67 | 68 | /*! 69 | * @discussion Status returned by API calls 70 | */ 71 | typedef enum 72 | { 73 | SENSEL_OK = 0, // Call was successful 74 | SENSEL_ERROR = -1, // Call returned an error 75 | } SenselStatus; 76 | 77 | /*! 78 | * @discussion Device scan reporting mode 79 | */ 80 | typedef enum 81 | { 82 | SCAN_MODE_DISABLE, 83 | SCAN_MODE_SYNC, 84 | SCAN_MODE_ASYNC, 85 | } SenselScanMode; 86 | 87 | /*! 88 | * @discussion Describes the current state of a contact 89 | */ 90 | typedef enum 91 | { 92 | SCAN_DETAIL_HIGH = 0, // Scan at full resolution 93 | SCAN_DETAIL_MEDIUM = 1, // Scan at half resolution 94 | SCAN_DETAIL_LOW = 2, // Scan at quarter resolution 95 | SCAN_DETAIL_UNKNOWN = 3, 96 | } SenselScanDetail; 97 | 98 | /*! 99 | * @discussion Describes the current state of a contact 100 | */ 101 | typedef enum 102 | { 103 | CONTACT_INVALID = 0, // Contact is invalid 104 | CONTACT_START = 1, // Contact has started 105 | CONTACT_MOVE = 2, // Contact has moved 106 | CONTACT_END = 3, // Contact has ended 107 | } SenselContactState; 108 | 109 | /*! 110 | * @discussion Structure containing sensor information 111 | */ 112 | typedef struct 113 | { 114 | unsigned char max_contacts; // Maximum number of contacts the sensor supports 115 | unsigned short num_rows; // Total number of rows 116 | unsigned short num_cols; // Total number of columns 117 | float width; // Width of the sensor in millimeters 118 | float height; // Height of the sensor in millimeters 119 | } SenselSensorInfo; 120 | 121 | /*! 122 | * @discussion Structure containing firmware information 123 | */ 124 | typedef struct 125 | { 126 | unsigned char fw_protocol_version; // Sensel communication protocol supported by the device 127 | unsigned char fw_version_major; // Major version of the firmware 128 | unsigned char fw_version_minor; // Minor version of the firmware 129 | unsigned short fw_version_build; // ?? 130 | unsigned char fw_version_release; // ?? 131 | unsigned short device_id; // Sensel device type 132 | unsigned char device_revision; // Device revision 133 | } SenselFirmwareInfo; 134 | 135 | 136 | /*! 137 | * @discussion Structure containing all information related to a detected contact 138 | * The content_bit_mask reflects which data is valid 139 | */ 140 | typedef struct 141 | { 142 | unsigned char content_bit_mask; // Mask of what contact data is valid 143 | unsigned char id; // Contact id 144 | unsigned int state; // Contact state (enum SenselContactState) 145 | float x_pos; // X position in mm 146 | float y_pos; // Y position in mm 147 | float total_force; // Total contact force in grams 148 | float area; // Area in sensor elements 149 | 150 | // CONTACT_MASK_ELLIPSE 151 | float orientation; // Angle in degrees 152 | float major_axis; // Length of the major axis in mm 153 | float minor_axis; // Length of the minor axis in mm 154 | 155 | // CONTACT_MASK_DELTAS 156 | float delta_x; // X contact displacement in mm 157 | float delta_y; // Y contact displacement in mm 158 | float delta_force; // Force delta in grams 159 | float delta_area; // Area delta in sensor elements 160 | 161 | // CONTACT_MASK_BOUNDING_BOX 162 | float min_x; // Bounding box min X coordinate in mm 163 | float min_y; // Bounding box min Y coordinate in mm 164 | float max_x; // Bounding box max X coordinate in mm 165 | float max_y; // Bounding box max Y coordinate in mm 166 | 167 | // CONTACT_MASK_PEAK 168 | float peak_x; // X position of the peak in mm 169 | float peak_y; // Y position of the peak in mm 170 | float peak_force; // Peak force in grams 171 | } SenselContact; 172 | 173 | /*! 174 | * @discussion Accelerometer information 175 | */ 176 | typedef struct 177 | { 178 | int x; // X axis acceleration 179 | int y; // Y axis acceleration 180 | int z; // Z axis acceleration 181 | } SenselAccelData; 182 | 183 | /*! 184 | * @discussion Container for one frame of data. 185 | * Available content of the frame needs to be checked by looking at the content_bit_mask 186 | */ 187 | typedef struct 188 | { 189 | unsigned char content_bit_mask; // Data contents of the frame 190 | int lost_frame_count; // Number of frames dropped 191 | unsigned char n_contacts; // Number of contacts 192 | SenselContact *contacts; // Array of contacts 193 | float *force_array; // Force image buffer 194 | unsigned char *labels_array; // Labels buffer 195 | SenselAccelData *accel_data; // Accelerometer data 196 | } SenselFrameData; 197 | 198 | /*! 199 | * @discussion Sensel identifier information 200 | */ 201 | typedef struct 202 | { 203 | unsigned char idx; // ID of the sensor 204 | unsigned char serial_num[64]; // Serial number of the sensor 205 | unsigned char com_port[64]; // Com port associated with the sensor 206 | } SenselDeviceID; 207 | 208 | /*! 209 | * @discussion List of connected Sensel devices 210 | */ 211 | typedef struct 212 | { 213 | unsigned char num_devices; // Num of devices found 214 | SenselDeviceID devices[SENSEL_MAX_DEVICES]; // Sensel device ID details 215 | } SenselDeviceList; 216 | 217 | /*! 218 | * @param handle Sensel device handle to be allocated 219 | * @return SENSEL_OK on success or error 220 | * @discussion Opens the first available Sensel sensor 221 | */ 222 | SENSEL_API 223 | SenselStatus WINAPI senselOpen(SENSEL_HANDLE *handle); 224 | 225 | /*! 226 | * @param list Device list to be populated 227 | * @return SENSEL_OK on success or error 228 | * @discussion Scans for all availale sensel devices and populates list accordingly 229 | */ 230 | SENSEL_API 231 | SenselStatus WINAPI senselGetDeviceList(SenselDeviceList *list); 232 | 233 | /*! 234 | * @param handle Sensel device handle to be initialized 235 | * @param idx identifier of the device to open 236 | * @return SENSEL_OK on success or error 237 | * @discussion Opens the devices associated to the given idx as returned by senselGetDeviceList. 238 | * senselGetDeviceList must be called prior to this call 239 | */ 240 | SENSEL_API 241 | SenselStatus WINAPI senselOpenDeviceByID(SENSEL_HANDLE *handle, unsigned char idx); 242 | 243 | /*! 244 | * @param handle Sensel device handle to be initialized 245 | * @param serial_num serial_number of the device to open 246 | * @return SENSEL_OK on success or error 247 | * @discussion Opens the devices associated to the given serial_num as returned by senselGetDeviceList. 248 | * senselGetDeviceList must be called prior to this call 249 | */ 250 | SENSEL_API 251 | SenselStatus WINAPI senselOpenDeviceBySerialNum(SENSEL_HANDLE *handle, unsigned char *serial_num); 252 | 253 | /*! 254 | * @param handle Sensel device handle to be initialized 255 | * @param com_port com_port path of the device to open 256 | * @return SENSEL_OK on success or error 257 | * @discussion Opens the devices associated to the given com_port as returned by senselGetDeviceList. 258 | * senselGetDeviceList must be called prior to this call 259 | */ 260 | SENSEL_API 261 | SenselStatus WINAPI senselOpenDeviceByComPort(SENSEL_HANDLE *handle, unsigned char *com_port); 262 | 263 | /*! 264 | * @param handle Sensel device to be closed 265 | * @return SENSEL_OK on success or error 266 | * @discussion Closes the device associated with handle and frees all memory. 267 | */ 268 | SENSEL_API 269 | SenselStatus WINAPI senselClose(SENSEL_HANDLE handle); 270 | 271 | /*! 272 | * @param handle Sensel device to reset 273 | * @return SENSEL_OK on success or error 274 | * @discussion Executes a soft reset the device referenced by handle. 275 | * All registers are reset to their initial state 276 | */ 277 | SENSEL_API 278 | SenselStatus WINAPI senselSoftReset(SENSEL_HANDLE handle); 279 | 280 | /*! 281 | * @param handle Sensel device handle to information about 282 | * @param info Pointer to a structure to populate 283 | * @return SENSEL_OK on success or error 284 | * @discussion Retrieves the sensor information 285 | */ 286 | SENSEL_API 287 | SenselStatus WINAPI senselGetSensorInfo(SENSEL_HANDLE handle, SenselSensorInfo *info); 288 | 289 | /*! 290 | * @param handle Sensel device handle for which to create a FrameData structure for 291 | * @param data Pointer to FrameData to allocate. 292 | * @return SENSEL_OK on success or error 293 | * @discussion Allocates a FrameData and initializes all buffers according to device capabilities. 294 | */ 295 | SENSEL_API 296 | SenselStatus WINAPI senselAllocateFrameData(SENSEL_HANDLE handle, SenselFrameData **data); 297 | 298 | /*! 299 | * @param handle Sensel device handle 300 | * @param data FrameData to free. 301 | * @return SENSEL_OK on success or error 302 | * @discussion Frees all memory allocated to FrameData including the FrameData itself. 303 | */ 304 | SENSEL_API 305 | SenselStatus WINAPI senselFreeFrameData(SENSEL_HANDLE handle, SenselFrameData *data); 306 | 307 | /*! 308 | * @param handle Sensel device handle 309 | * @param detail Scan detail level 310 | * @return SENSEL_OK on success or error 311 | * @discussion Set the level of scanning detail returned by the device. This setting trades precision for performance. 312 | */ 313 | SENSEL_API 314 | SenselStatus WINAPI senselSetScanDetail(SENSEL_HANDLE handle, SenselScanDetail detail); 315 | 316 | /*! 317 | * @param handle Sensel device handle 318 | * @param detail Pointer to scan detail level to retrieve 319 | * @return SENSEL_OK on success or error 320 | * @discussion Get the current scanning level setting 321 | */ 322 | SENSEL_API 323 | SenselStatus WINAPI senselGetScanDetail(SENSEL_HANDLE handle, SenselScanDetail *detail); 324 | 325 | /*! 326 | * @param handle Sensel device handle 327 | * @param content Pointer to frame content supported by device 328 | * @return SENSEL_OK on success or error 329 | * @discussion Retrieve the frame content that the device supports 330 | */ 331 | SENSEL_API 332 | SenselStatus WINAPI senselGetSupportedFrameContent(SENSEL_HANDLE handle, unsigned char *content); 333 | 334 | /*! 335 | * @param handle Sensel device handle 336 | * @param content Frame content mask 337 | * @return SENSEL_OK on success or error 338 | * @discussion Sets the information returned by the sensor. 339 | * content can be any combination of FRAME_CONTENT_*_MASK. 340 | * FrameData returned in subsequent GetFrame calls will reflect this setting. 341 | */ 342 | SENSEL_API 343 | SenselStatus WINAPI senselSetFrameContent(SENSEL_HANDLE handle, unsigned char content); 344 | 345 | /*! 346 | * @param handle Sensel device handle 347 | * @param content Pointer to content level to retrieve 348 | * @return SENSEL_OK on success or error 349 | * @discussion Get the current frame content mask from the device 350 | */ 351 | SENSEL_API 352 | SenselStatus WINAPI senselGetFrameContent(SENSEL_HANDLE handle, unsigned char *content); 353 | 354 | /*! 355 | * @param handle Sensel device handle 356 | * @return SENSEL_OK on success or error 357 | * @discussion Start sensor scanning 358 | */ 359 | SENSEL_API 360 | SenselStatus WINAPI senselStartScanning(SENSEL_HANDLE handle); 361 | 362 | /*! 363 | * @param handle Sensel device handle 364 | * @return SENSEL_OK on success or error 365 | * @discussion Stop sensor scanning 366 | */ 367 | SENSEL_API 368 | SenselStatus WINAPI senselStopScanning(SENSEL_HANDLE handle); 369 | 370 | /*! 371 | * @param handle Sensel device handle 372 | * @return SENSEL_OK on success or error 373 | * @discussion Reads out and stores all pending frames from the sensor 374 | */ 375 | SENSEL_API 376 | SenselStatus WINAPI senselReadSensor(SENSEL_HANDLE handle); 377 | 378 | /*! 379 | * @param handle Sensel device handle 380 | * @param num_avail_frames Will contain the number of frames available to GetFrame 381 | * @return SENSEL_OK on success or error 382 | * @discussion Returns in num_avail_frames the number of data frames available. 383 | */ 384 | SENSEL_API 385 | SenselStatus WINAPI senselGetNumAvailableFrames(SENSEL_HANDLE handle, unsigned int *num_avail_frames); 386 | 387 | /*! 388 | * @param handle Sensel device handle 389 | * @param data Pointer to pre-allocated FrameData to populate 390 | * @return SENSEL_OK on success or error 391 | * @discussion Returns one frame of data in data. 392 | */ 393 | SENSEL_API 394 | SenselStatus WINAPI senselGetFrame(SENSEL_HANDLE handle, SenselFrameData *data); 395 | 396 | /*! 397 | * @param handle Sensel device handle 398 | * @param num_leds Pointer to number of leds on device 399 | * @return SENSEL_OK on success or error 400 | * @discussion Retrieve number of LEDs available on the device 401 | */ 402 | SENSEL_API 403 | SenselStatus WINAPI senselGetNumAvailableLEDs(SENSEL_HANDLE handle, unsigned char *num_leds); 404 | 405 | /*! 406 | * @param handle Sensel device handle 407 | * @param max_brightness Pointer to maximum per LED brightness 408 | * @return SENSEL_OK on success or error 409 | * @discussion Retrieve the maximum brightness value an LED can be set to 410 | */ 411 | SENSEL_API 412 | SenselStatus WINAPI senselGetMaxLEDBrightness(SENSEL_HANDLE handle, unsigned short *max_brightness); 413 | 414 | /*! 415 | * @param handle Sensel device handle 416 | * @param led_id Index of the LED to update 417 | * @param brightness Brightness setting 418 | * @return SENSEL_OK on success or error 419 | * @discussion Update the brightness of one LED 420 | */ 421 | SENSEL_API 422 | SenselStatus WINAPI senselSetLEDBrightness(SENSEL_HANDLE handle, unsigned char led_id, unsigned short brightness); 423 | 424 | /*! 425 | * @param handle Sensel device handle 426 | * @param led_id Index of the LED to update 427 | * @param brightness Pointer to brightness setting 428 | * @return SENSEL_OK on success or error 429 | * @discussion Retrieve the current brightness of an LED 430 | */ 431 | SENSEL_API 432 | SenselStatus WINAPI senselGetLEDBrightness(SENSEL_HANDLE handle, unsigned char led_id, unsigned short *brightness); 433 | 434 | /*! 435 | * @param handle Sensel device handle 436 | * @param pressed Pointer to hold state of power button 437 | * @return SENSEL_OK on success or error 438 | * @discussion Pressed will be 1 if button was pressed or 0 otherwize 439 | */ 440 | SENSEL_API 441 | SenselStatus WINAPI senselGetPowerButtonPressed(SENSEL_HANDLE handle, unsigned char *pressed); 442 | 443 | /* 444 | * Advanced API 445 | * The following calls are advanced and can break functionality if not used properly. 446 | */ 447 | 448 | /*! 449 | * @param handle Sensel device handle 450 | * @param fw_info Pointer to SenselFirmwareInfo structure to populate 451 | * @return SENSEL_OK on success or error 452 | * @discussion Retrieve firmware device information 453 | */ 454 | SENSEL_API 455 | SenselStatus WINAPI senselGetFirmwareInfo(SENSEL_HANDLE handle, SenselFirmwareInfo* fw_info); 456 | 457 | /*! 458 | * @param handle Sensel device handle 459 | * @param val 0 to disable - 1 to enable 460 | * @return SENSEL_OK on success or error 461 | * @discussion Set contact blob merging setting 462 | */ 463 | SENSEL_API 464 | SenselStatus WINAPI senselSetContactsEnableBlobMerge(SENSEL_HANDLE handle, unsigned char val); 465 | 466 | /*! 467 | * @param handle Sensel device handle 468 | * @param val Pointer to contain current setting 469 | * @return SENSEL_OK on success or error 470 | * @discussion Get contact blob merging setting 471 | */ 472 | SENSEL_API 473 | SenselStatus WINAPI senselGetContactsEnableBlobMerge(SENSEL_HANDLE handle, unsigned char *val); 474 | 475 | /*! 476 | * @param handle Sensel device handle 477 | * @param val Force value 478 | * @return SENSEL_OK on success or error 479 | * @discussion Sets the minimum force a contact needs to have to be reported 480 | */ 481 | SENSEL_API 482 | SenselStatus WINAPI senselSetContactsMinForce(SENSEL_HANDLE handle, unsigned short val); 483 | 484 | /*! 485 | * @param handle Sensel device handle 486 | * @param val Pointer to contain current setting 487 | * @return SENSEL_OK on success or error 488 | * @discussion Gets the minimum force a contact needs to have to be reported 489 | */ 490 | SENSEL_API 491 | SenselStatus WINAPI senselGetContactsMinForce(SENSEL_HANDLE handle, unsigned short *val); 492 | 493 | /*! 494 | * @param handle Sensel device handle 495 | * @param val true: Enabled - false: Disabled 496 | * @return SENSEL_OK on success or error 497 | * @discussion Sets if the baseline is dynamic and evolves over time 498 | */ 499 | SENSEL_API 500 | SenselStatus WINAPI senselSetDynamicBaselineEnabled(SENSEL_HANDLE handle, unsigned char val); 501 | 502 | /*! 503 | * @param handle Sensel device handle 504 | * @param val Pointer to contain current setting 505 | * @return SENSEL_OK on success or error 506 | * @discussion Retreives the current dynamic baselining setting 507 | */ 508 | SENSEL_API 509 | SenselStatus WINAPI senselGetDynamicBaselineEnabled(SENSEL_HANDLE handle, unsigned char *val); 510 | 511 | /*! 512 | * @param handle Sensel device handle 513 | * @param num Number of buffers 514 | * @return SENSEL_OK on success or error 515 | * @discussion Sets the number of frame buffers the device should store internaly. 516 | */ 517 | SENSEL_API 518 | SenselStatus WINAPI senselSetBufferControl(SENSEL_HANDLE handle, unsigned char num); 519 | 520 | /*! 521 | * @param handle Sensel device handle 522 | * @param num Pointer to contain current setting 523 | * @return SENSEL_OK on success or error 524 | * @discussion Gets the number of frame buffers the device should store internaly. 525 | */ 526 | SENSEL_API 527 | SenselStatus WINAPI senselGetBufferControl(SENSEL_HANDLE handle, unsigned char *num); 528 | 529 | /*! 530 | * @param handle Sensel device handle 531 | * @param mode Scan mode setting 532 | * @return SENSEL_OK on success or error 533 | * @discussion Sets the current scan mode. 534 | */ 535 | SENSEL_API 536 | SenselStatus WINAPI senselSetScanMode(SENSEL_HANDLE handle, SenselScanMode mode); 537 | 538 | /*! 539 | * @param handle Sensel device handle 540 | * @param mode Pointer to retrieve Scan mode setting 541 | * @return SENSEL_OK on success or error 542 | * @discussion Gets the current scan mode. 543 | */ 544 | SENSEL_API 545 | SenselStatus WINAPI senselGetScanMode(SENSEL_HANDLE handle, SenselScanMode *mode); 546 | 547 | /*! 548 | * @param handle Sensel device handle 549 | * @param val Max framerate 550 | * @return SENSEL_OK on success or error 551 | * @discussion Sets the maximum framerate at which the device should report 552 | */ 553 | SENSEL_API 554 | SenselStatus WINAPI senselSetMaxFrameRate(SENSEL_HANDLE handle, unsigned short val); 555 | 556 | /*! 557 | * @param handle Sensel device handle 558 | * @param val Pointer to retrieve current max framerate 559 | * @return SENSEL_OK on success or error 560 | * @discussion Gets the maximum framerate at which the device should report 561 | */ 562 | SENSEL_API 563 | SenselStatus WINAPI senselGetMaxFrameRate(SENSEL_HANDLE handle, unsigned short *val); 564 | 565 | /*! 566 | * @param handle Sensel device handle 567 | * @param mask Contact information mask 568 | * @return SENSEL_OK on success or error 569 | * @discussion Sets the contact information reported by the sensor 570 | * mask can be any combination of CONTACT_MASK_* 571 | * Contacts returned in subsequent GetFrame calls will reflect this setting. 572 | */ 573 | SENSEL_API 574 | SenselStatus WINAPI senselSetContactsMask(SENSEL_HANDLE handle, unsigned char mask); 575 | 576 | /*! 577 | * @param handle Sensel device handle 578 | * @param mask Pointer to retrieve current max framerate 579 | * @return SENSEL_OK on success or error 580 | * @discussion Gets the current contact mask setting for the device 581 | */ 582 | SENSEL_API 583 | SenselStatus WINAPI senselGetContactsMask(SENSEL_HANDLE handle, unsigned char *mask); 584 | 585 | /*! 586 | * @param handle Sensel device handle 587 | * @param reg Register to read 588 | * @param size Size of the register 589 | * @param buf Buffer to store the result 590 | * @return SENSEL_OK on success or error 591 | * @discussion Reads size bytes from register reg and stores the value in buf. 592 | */ 593 | SENSEL_API 594 | SenselStatus WINAPI senselReadReg(SENSEL_HANDLE handle, unsigned char reg, unsigned char size, unsigned char *buf); 595 | 596 | /*! 597 | * @param handle Sensel device handle 598 | * @param reg Register to write 599 | * @param size Size of the register 600 | * @param buf Buffer containing the data to write 601 | * @return SENSEL_OK on success or error 602 | * @discussion Writes size bytes from buf into register reg 603 | */ 604 | SENSEL_API 605 | SenselStatus WINAPI senselWriteReg(SENSEL_HANDLE handle, unsigned char reg, unsigned char size, unsigned char *buf); 606 | 607 | /*! 608 | * @param handle Sensel device handle 609 | * @param reg Register to write 610 | * @param buf_size Size of the "buf" buffer 611 | * @param buf Buffer to store the result 612 | * @param read_size Variable to store the number of bytes read from register 613 | * @return SENSEL_OK on success or error 614 | * @discussion Reads up to buf_size bytes from register reg and stores it in buf. On success, read_size will 615 | * contain the number of bytes read from the register. 616 | */ 617 | SENSEL_API 618 | SenselStatus WINAPI senselReadRegVS(SENSEL_HANDLE handle, unsigned char reg, unsigned int buf_size, unsigned char *buf, unsigned int *read_size); 619 | 620 | /*! 621 | * @param handle Sensel device handle 622 | * @param reg Register to write 623 | * @param size Size of data to write from buf 624 | * @param buf Buffer holding data to write 625 | * @param write_size Variable to store the number of bytes actually written 626 | * @return SENSEL_OK on success or error 627 | * @discussion Write up to size bytes from buf to register reg. On success, write_size will 628 | * contain the number of bytes written to the register. 629 | */ 630 | SENSEL_API 631 | SenselStatus WINAPI senselWriteRegVS(SENSEL_HANDLE handle, unsigned char reg, unsigned int size, unsigned char *buf, unsigned int *write_size); 632 | 633 | #ifdef __cplusplus 634 | } 635 | #endif 636 | 637 | #endif //__SENSEL_H__ 638 | -------------------------------------------------------------------------------- /sensel-win-msys-include/sensel_decompress.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************************** 2 | * SENSEL CONFIDENTIAL 3 | * 4 | * Copyright (c) 2013-2017 Sensel, Inc. 5 | * All Rights Reserved. 6 | * 7 | * NOTICE: All information contained herein is, and remains the property of Sensel, Inc. 8 | * The intellectual and technical concepts contained herein are proprietary to Sensel, Inc. 9 | * and may be covered by U.S. and Foreign Patents, patents in process, and are protected 10 | * by trade secret or copyright law. Dissemination of this information or reproduction of 11 | * this material is strictly forbidden unless prior written permission is obtained from 12 | * Sensel, Inc. 13 | ******************************************************************************************/ 14 | 15 | 16 | #ifndef __SENSEL_DECOMPRESS_H___ 17 | #define __SENSEL_DECOMPRESS_H__ 18 | 19 | #include "sensel.h" 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | /*! 26 | * @param handle Sensel device handle where to allocate decompression handle 27 | * @return SENSEL_OK on success or error 28 | * @discussion Allocates a decompression handle inside the device handle 29 | */ 30 | SENSEL_API 31 | SenselStatus WINAPI senselInitDecompressionHandle(SENSEL_HANDLE handle, unsigned char *data); 32 | 33 | /*! 34 | * @param handle Sensel device handle from which to free the decompression handle 35 | * @return SENSEL_OK on success or error 36 | * @discussion Frees the decompression handle from the provided device handle 37 | */ 38 | SENSEL_API 39 | SenselStatus WINAPI senselFreeDecompressionHandle(SENSEL_HANDLE handle); 40 | 41 | /*! 42 | * @param handle Sensel device handle 43 | * @param data Metadata in raw form 44 | * @return SENSEL_OK on success or error 45 | * @discussion Notifies the decompression engine that a scan detail change was requested 46 | */ 47 | SENSEL_API 48 | SenselStatus WINAPI senselDecompressionTriggerDetailChange(SENSEL_HANDLE handle, unsigned char *data); 49 | 50 | /*! 51 | * @param handle Sensel device handle 52 | * @param frame_data Raw protocol payload to process 53 | * @param data_size Size of the payload 54 | * @param content_mask Content mask as reported for this frame 55 | * @param data Frame data to store the decompression result 56 | * @param decompress_bytes_read Will hold the number of bytes read from the payload 57 | * @return SENSEL_OK on success or error 58 | * @discussion Decompresses the payload pointed to by frame_data and fills the FrameData structure 59 | * accordingly. 60 | */ 61 | SENSEL_API 62 | SenselStatus WINAPI senselDecompressFrame(SENSEL_HANDLE handle, unsigned char* frame_data, int data_size, 63 | unsigned char content_mask, SenselFrameData *data, unsigned int *decompress_bytes_read); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | 70 | #endif //__SENSEL_DECOMPRESS_H__ 71 | -------------------------------------------------------------------------------- /sensel-win-msys-include/sensel_device.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************************** 2 | * MIT License 3 | * 4 | * Copyright (c) 2013-2017 Sensel, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | ******************************************************************************************/ 24 | 25 | #ifndef __SENSEL_ADVANCED_H__ 26 | #define __SENSEL_ADVANCED_H__ 27 | 28 | #include "sensel.h" 29 | #include "sensel_protocol.h" 30 | 31 | #define DEFAULT_BOARD_ADDR 0x01 32 | 33 | #define SENSEL_MAGIC "S3NS31" 34 | #define SENSEL_MAGIC_LEN 6 35 | #define SENSEL_NULL_LABEL 255 36 | 37 | #define CONTACT_DEFAULT_SEND_SIZE 10 38 | #define CONTACT_ELLIPSE_SEND_SIZE 6 39 | #define CONTACT_DELTAS_SEND_SIZE 8 40 | #define CONTACT_BOUNDING_BOX_SEND_SIZE 8 41 | #define CONTACT_PEAK_SEND_SIZE 6 42 | 43 | typedef void *SENSEL_DECOMP_HANDLE; 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | typedef struct 50 | { 51 | #if WIN32 52 | void* serial_handle; 53 | #else 54 | int serial_fd; 55 | #endif 56 | } SenselSerialHandle; 57 | 58 | typedef struct sensel_device_s 59 | { 60 | SenselSerialHandle sensor_serial; // Handle to the serial interface 61 | SenselFirmwareInfo fw_info; // Device firmware information 62 | SenselSensorInfo sensor_info; // Sensor information 63 | SENSEL_DECOMP_HANDLE decomp_handle; // Decompression handle 64 | 65 | unsigned char supported_frame_content; // Content the device supports 66 | // Temporary buffers for force frame decompression 67 | unsigned char *frame_buffer; 68 | int frame_buffer_capacity; 69 | int frame_buffer_size; 70 | 71 | // Conversion factors 72 | float dims_value_scale; // Dimension value scale 73 | float force_value_scale; // Force value scale 74 | float angle_value_scale; // Angle value scale 75 | float area_value_scale; // Area value scale 76 | 77 | // Variables to keep track of sensel scan state 78 | unsigned char frame_content_control; // Curent frame content control 79 | unsigned char scan_buffer_control; // Number of scan buffers currently enabled 80 | SenselScanMode scan_mode; // Current scan mode setting 81 | unsigned char scanning_active; // Is scanning enabled / disabled 82 | int num_buffered_frames; // Number of frames currently buffered 83 | unsigned char prev_rolling_frame_counter; 84 | unsigned int prev_timestamp; // Timestamp of the previous frame 85 | 86 | unsigned char dynamic_baseline_enabled; // Is dynamic baselining enabled 87 | 88 | // Used for LED control 89 | unsigned char num_leds; // Maximum number of LEDs 90 | unsigned short max_led_brightness; // Maximum brightness value 91 | unsigned char led_reg_size; // Size of the LED brightness register 92 | void *led_array; // LED brightness array 93 | } SenselDevice; 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #endif //__SENSEL_ADVANCED_H__ 100 | -------------------------------------------------------------------------------- /sensel-win-msys-include/sensel_protocol.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************************** 2 | * MIT License 3 | * 4 | * Copyright (c) 2013-2017 Sensel, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | ******************************************************************************************/ 24 | 25 | #ifndef __SENSEL_PROTOCOL_H__ 26 | #define __SENSEL_PROTOCOL_H__ 27 | 28 | #include "sensel_types.h" 29 | 30 | #ifdef __MINGW32__ 31 | #define PACK( __Declaration__, __Name__ ) __Declaration__ __attribute__((__packed__)) __Name__ 32 | #elif defined WIN32 33 | #define PACK( __Declaration__, __Name__ ) __pragma( pack(push, 1) ) \ 34 | __Declaration__ __Name__ __pragma( pack(pop) ) 35 | #else 36 | #define PACK( __Declaration__, __Name__ ) __Declaration__ __attribute__((__packed__)) __Name__ 37 | #endif 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | // Type declarations 45 | typedef int16 vel_t; 46 | typedef uint8 label_t; 47 | typedef uint8 blobid_t; 48 | typedef uint8 grid_coord_t; 49 | typedef uint8 contact_type_t; 50 | typedef uint16 pressure_t; 51 | typedef uint16 force_t; 52 | typedef uint32 uid_t; 53 | 54 | PACK( 55 | typedef struct 56 | { 57 | uint8 r_w_addr; 58 | uint8 reg; 59 | uint8 size; 60 | uint8 padding; 61 | }, 62 | sensel_protocol_cmd_t); 63 | 64 | PACK( 65 | typedef struct 66 | { 67 | uint8 r_w_addr; 68 | uint8 reg; 69 | uint8 size; 70 | uint8 header_size; 71 | uint32 vs_size; 72 | uint8 checksum; 73 | uint8 padding; 74 | }, 75 | sensel_protocol_cmd_vs_t); 76 | 77 | PACK( 78 | typedef struct 79 | { 80 | uint8 fw_protocol_version; 81 | uint8 fw_version_major; 82 | uint8 fw_version_minor; 83 | uint16 fw_version_build; 84 | uint8 fw_version_release; 85 | uint16 device_id; 86 | uint8 device_revision; 87 | }, 88 | sensel_firmware_info_t); 89 | 90 | PACK( 91 | typedef struct 92 | { 93 | int16 x; 94 | int16 y; 95 | int16 z; 96 | }, 97 | sensel_accel_data_t); 98 | 99 | // This type is for storing contact information 100 | // NOTE: I use unsigned types for some of these fields. I may want to consider signed types for faster processing. 101 | PACK( 102 | typedef struct 103 | { 104 | label_t id; // TODO: type could be something like contact_id 105 | contact_type_t type; 106 | uint16 x_pos; // x position multiplied by 256 107 | uint16 y_pos; // y position multiplied by 256 108 | uint16 total_force; 109 | uint16 area; // area in sensor elements 110 | 111 | int16 orientation; // angle from -90 to 90 multiplied by 16 112 | uint16 major_axis; // length of the major axis multiplied by 256 113 | uint16 minor_axis; // length of the minor axis multiplied by 256 114 | 115 | int16 delta_x; 116 | int16 delta_y; 117 | int16 delta_force; 118 | int16 delta_area; 119 | 120 | uint16 min_x; 121 | uint16 min_y; 122 | uint16 max_x; 123 | uint16 max_y; 124 | 125 | uint16 peak_x; 126 | uint16 peak_y; 127 | uint16 peak_force; 128 | }, 129 | contact_raw_t); 130 | 131 | // This type is for storing x,y locations on the grid 132 | PACK( 133 | typedef struct 134 | { 135 | grid_coord_t x; 136 | grid_coord_t y; 137 | }, 138 | grid_loc_t); 139 | 140 | 141 | #ifdef __cplusplus 142 | } 143 | #endif 144 | 145 | #endif //__SENSEL_PROTOCOL_H__ 146 | -------------------------------------------------------------------------------- /sensel-win-msys-include/sensel_protocol.h.diff: -------------------------------------------------------------------------------- 1 | --- "/c/Program Files/Sensel/SenselLib/include/sensel_protocol.h" 2018-02-28 14:18:54.000000000 -0500 2 | +++ sensel_protocol.h 2020-04-13 17:37:15.784703900 -0400 3 | @@ -27,7 +27,9 @@ 4 | 5 | #include "sensel_types.h" 6 | 7 | -#ifdef WIN32 8 | +#ifdef __MINGW32__ 9 | + #define PACK( __Declaration__, __Name__ ) __Declaration__ __attribute__((__packed__)) __Name__ 10 | +#elif defined WIN32 11 | #define PACK( __Declaration__, __Name__ ) __pragma( pack(push, 1) ) \ 12 | __Declaration__ __Name__ __pragma( pack(pop) ) 13 | #else 14 | -------------------------------------------------------------------------------- /sensel-win-msys-include/sensel_types.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************************** 2 | * MIT License 3 | * 4 | * Copyright (c) 2013-2017 Sensel, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | ******************************************************************************************/ 24 | 25 | #ifndef __SENSEL_TYPES_H__ 26 | #define __SENSEL_TYPES_H__ 27 | 28 | // TODO: We may not want to define any of these types in our library 29 | // to maintain maximum compatibility with external code 30 | // Code should be using stdint.h 31 | 32 | #ifdef WIN32 33 | #ifndef __cplusplus 34 | #define false (0) 35 | #define true (1) 36 | #define bool unsigned char 37 | #endif 38 | #else 39 | #include 40 | #endif 41 | 42 | typedef unsigned char uint8; 43 | typedef unsigned short uint16; 44 | typedef unsigned int uint32; 45 | typedef unsigned long long int uint64; 46 | 47 | typedef char int8; 48 | typedef short int16; 49 | typedef int int32; 50 | typedef long long int int64; 51 | 52 | 53 | #endif //__SENSEL_TYPES_H__ 54 | -------------------------------------------------------------------------------- /sensel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "g_canvas.h" 5 | 6 | #include 7 | #include 8 | #include "sensel.h" 9 | #include "sensel_device.h" 10 | 11 | #ifdef __MINGW32__ 12 | #include 13 | #include 14 | #elif defined WIN32 15 | // TODO: consider including native Windows compiler 16 | // ifdef for threads and adapt threads below 17 | #else 18 | #include 19 | #include 20 | #endif 21 | 22 | /* 23 | The Sensel Morph Pd external, written by 24 | Rachel Hachem 25 | under the guidance of Ivica Ico Bukvic 26 | 27 | 2020-04-13 v.0.9.0 28 | Initial release by Rachel Hachem 29 | under the guidance of Ivica Ico Bukvic 30 | 31 | 2020-05-20 v.1.0.0 32 | Threaded implementation with additional features, 33 | including, disconnect, free, identify, improved 34 | console output, versioning, updated help file, and 35 | bug-fixes to support multiple sensel morphs by 36 | Ivica Ico Bukvic 37 | 38 | 2020-05-22 v.1.1.0 39 | Improved integration of the contacts API to fix 40 | contact id and provide contact status, as well as 41 | address missed contact status changes, reworked 42 | polling logic and removed reliance on the external 43 | metro, added total contact count, and setting the 44 | polling time by Ivica Ico Bukvic 45 | 46 | 2020-05-22 v.1.2.0 47 | Introduced ability to change LED brightness and 48 | further improved the help file by Ivica Ico Bukvic 49 | 50 | 51 | Please see the supporting help file for the 52 | explanation of its features. 53 | */ 54 | static t_class *sensel_class; 55 | 56 | /* 57 | Single-linked list for accumulating data output 58 | */ 59 | typedef struct _data 60 | { 61 | t_atom args[20]; 62 | int type; // 0 = data (20 args) 63 | // 1 = number of contacts (only one arg) 64 | struct _data *next; 65 | } t_data; 66 | 67 | /* 68 | An array keeping track of which devices are 69 | already connected up to maximum allowed by 70 | the sensel API 71 | */ 72 | static t_symbol sensel_connected_devices[SENSEL_MAX_DEVICES]; 73 | 74 | /* 75 | Adds a device to the list of connected devices, 76 | returning: 77 | 0 for success 78 | -1 for failure (shouldn't happen as API should throw error first) 79 | */ 80 | static int add_connected_to_sensel_device_list(t_symbol *s) 81 | { 82 | int i = 0; 83 | 84 | while (i < SENSEL_MAX_DEVICES) 85 | { 86 | if (sensel_connected_devices[i].s_name == NULL) 87 | { 88 | sensel_connected_devices[i] = *s; 89 | return(0); 90 | } 91 | else 92 | i++; 93 | } 94 | return(-1); 95 | } 96 | 97 | /* 98 | Removes device from the list of connected devices, 99 | returning: 100 | 0 for success 101 | -1 for failure (shouldn't happen as API should throw error first) 102 | */ 103 | static int remove_connected_to_sensel_device_list(t_symbol *s) 104 | { 105 | int i = 0; 106 | 107 | while (i < SENSEL_MAX_DEVICES) 108 | { 109 | if (sensel_connected_devices[i].s_name != NULL) 110 | { 111 | if (!strcmp(sensel_connected_devices[i].s_name, s->s_name)) 112 | { 113 | sensel_connected_devices[i].s_name = NULL; 114 | return(0); 115 | } 116 | i++; 117 | } 118 | } 119 | return(-1); 120 | } 121 | 122 | /* 123 | Checks if a device we wish to connect is already 124 | on the list of connected devices, returns: 125 | 1 for yes 126 | 0 for no 127 | */ 128 | static int check_if_already_on_sensel_device_list(t_symbol *s) 129 | { 130 | int i = 0; 131 | 132 | while (i < SENSEL_MAX_DEVICES) 133 | { 134 | if (sensel_connected_devices[i].s_name != NULL) 135 | { 136 | if (!strcmp(sensel_connected_devices[i].s_name, s->s_name)) 137 | return(1); 138 | } 139 | i++; 140 | } 141 | return(0); 142 | } 143 | 144 | /* 145 | Main Sensel Morph data structure 146 | */ 147 | typedef struct _sensel 148 | { 149 | t_object x_obj; 150 | t_atom x_atom; 151 | t_canvas *x_canvas; 152 | 153 | t_outlet *x_outlet_data; 154 | t_outlet *x_outlet_status; 155 | 156 | SENSEL_HANDLE x_handle; 157 | SenselFrameData *x_frame; 158 | int x_connected; 159 | int x_thread_connected; 160 | 161 | pthread_t x_unsafe_t; 162 | pthread_mutex_t x_unsafe_mutex; 163 | int x_unsafe; 164 | t_data *x_data; 165 | t_data *x_data_end; 166 | int x_n_contacts; 167 | int x_poll_wait; 168 | 169 | short unsigned int x_led[24]; 170 | short unsigned int x_thread_led[24]; 171 | 172 | t_clock *x_clock_output; 173 | int x_clock_set; 174 | 175 | t_symbol *x_serial; 176 | 177 | } t_sensel; 178 | 179 | /* 180 | Struct for passing args to the Sensel thread 181 | */ 182 | typedef struct _threadedFunctionParams 183 | { 184 | t_sensel *s_inst; 185 | } t_threadedFunctionParams; 186 | 187 | /* 188 | Forward declarations 189 | */ 190 | static void sensel_poll(t_sensel *x); 191 | 192 | /* 193 | Allows adjustment of the wait time 194 | in between poll reads from the Sensel socket 195 | */ 196 | static void sensel_set_poll_wait_time(t_sensel *x, t_floatarg f) 197 | { 198 | if (f < 1.0 || f > 100.0) 199 | { 200 | error("sensel: poll time must be between 1 and 100ms (default 10ms)."); 201 | return; 202 | } 203 | x->x_poll_wait = (int)(f * 1000.0); 204 | } 205 | 206 | /* 207 | Sets Sensel's LED with an ID to a desired brightness in (0-100) 208 | */ 209 | static void sensel_set_led(t_sensel *x, t_floatarg id, t_floatarg brightness) 210 | { 211 | if (x->x_connected == 1) 212 | { 213 | if (id >= 0 && id <= 23 && brightness >= 0 && brightness <= 100) 214 | { 215 | x->x_led[(int)id] = (int)brightness; 216 | } 217 | } 218 | } 219 | 220 | /* 221 | Processes changes in LEDs via subthread call 222 | */ 223 | static void sensel_update_leds(t_sensel *x) 224 | { 225 | for (int i = 0; i < 24; i++) 226 | { 227 | if (x->x_led[i] != x->x_thread_led[i]) 228 | { 229 | x->x_thread_led[i] = x->x_led[i]; 230 | senselSetLEDBrightness(x->x_handle, i, x->x_thread_led[i]); 231 | } 232 | } 233 | } 234 | 235 | /* 236 | Threaded function that reads from the Sensel 237 | without blocking the main audio thread 238 | */ 239 | static void *sensel_pthreadForAudioUnfriendlyOperations(void *ptr) 240 | { 241 | t_threadedFunctionParams *rPars = (t_threadedFunctionParams*)ptr; 242 | t_sensel *x = rPars->s_inst; 243 | 244 | while(x->x_unsafe > -1) 245 | { 246 | pthread_mutex_lock(&x->x_unsafe_mutex); 247 | // inform the external when the thread is ready 248 | if (x->x_unsafe == 1) 249 | x->x_unsafe = 0; 250 | 251 | if (x->x_thread_connected != x->x_connected) 252 | { 253 | x->x_thread_connected = x->x_connected; 254 | if (x->x_thread_connected) 255 | { 256 | // Start scanning the Sensel device 257 | senselStartScanning(x->x_handle); 258 | } 259 | else { 260 | // This is where we stop scanning and disconnect 261 | senselStopScanning(x->x_handle); 262 | senselFreeFrameData(x->x_handle, x->x_frame); 263 | senselClose(x->x_handle); 264 | } 265 | } 266 | 267 | // only poll for new data if the previous sensel_output_data 268 | // has been processed (I suppose this could be also done 269 | // with a semaphore but since Windows pthreads implementation 270 | // via CygWin is not entirely compatible, I figured this may 271 | // be a "cleaner" way to do this 272 | if (x->x_clock_set == 0) 273 | { 274 | sensel_poll(x); 275 | } 276 | 277 | sensel_update_leds(x); 278 | 279 | pthread_mutex_unlock(&x->x_unsafe_mutex); 280 | 281 | usleep(x->x_poll_wait); 282 | } 283 | pthread_exit(0); 284 | 285 | return(0); 286 | } 287 | 288 | /* 289 | Outputs received data via clock delay that is triggered 290 | from the sub-thread 291 | */ 292 | static void sensel_output_data(t_sensel *x) 293 | { 294 | if (x->x_clock_set == 1) 295 | { 296 | while (x->x_data != NULL) 297 | { 298 | switch (x->x_data->type) 299 | { 300 | case 0: // data 301 | outlet_list(x->x_outlet_data, gensym("list"), 20, x->x_data->args); 302 | break; 303 | case 1: // number of contacts 304 | outlet_anything(x->x_outlet_data, gensym("contacts"), 1, &x->x_data->args[0]); 305 | break; 306 | } 307 | t_data *last = x->x_data; 308 | x->x_data = x->x_data->next; 309 | free(last); 310 | } 311 | x->x_clock_set = 0; 312 | } 313 | } 314 | 315 | /* 316 | Connects the Pd patch to a specific Sensel device, using 317 | the serial number as an argument. 318 | */ 319 | static void sensel_connect(t_sensel *x, t_symbol *s) 320 | { 321 | post("sensel: connecting to device with serial number %s...", s->s_name); 322 | 323 | if (x->x_connected == 1) 324 | { 325 | error("sensel: connect failed--device already connected."); 326 | return; 327 | } 328 | 329 | if (check_if_already_on_sensel_device_list(s)) 330 | { 331 | error("sensel: connect failed--device is already connected to another sensel object."); 332 | return; 333 | } 334 | 335 | // List of all available Sensel devices 336 | SenselDeviceList list; 337 | 338 | // Get a list of available Sensel devices 339 | senselGetDeviceList(&list); 340 | if (list.num_devices == 0) 341 | { 342 | error("sensel: connect failed--no device found."); 343 | return; 344 | } 345 | 346 | int result = senselOpenDeviceBySerialNum(&x->x_handle, (unsigned char *)s->s_name); 347 | 348 | if (!result) 349 | { 350 | // Set the frame content to scan contact data 351 | senselSetFrameContent(x->x_handle, FRAME_CONTENT_CONTACTS_MASK); 352 | // Allocate a frame of data, must be done before reading frame data 353 | senselAllocateFrameData(x->x_handle, &x->x_frame); 354 | post("sensel: successfully connected to device with a serial number %s.", s->s_name); 355 | x->x_connected = 1; 356 | 357 | x->x_serial = s; 358 | add_connected_to_sensel_device_list(x->x_serial); 359 | 360 | // sensel_connected_devices[0] = *gensym("blah"); 361 | outlet_float(x->x_outlet_status, x->x_connected); 362 | } 363 | 364 | if (x->x_connected != 1) { 365 | error("sensel: connect failed--device with a serial number %s not found.", s->s_name); 366 | } 367 | } 368 | 369 | /* 370 | Discovers and connects to the first available Sensel Morph 371 | */ 372 | static void sensel_discover(t_sensel *x) 373 | { 374 | 375 | if (x->x_connected == 1) 376 | { 377 | error("sensel: discover failed--device already connected."); 378 | return; 379 | } 380 | 381 | // List of all available Sensel devices 382 | SenselDeviceList list; 383 | 384 | // Get a list of available Sensel devices 385 | senselGetDeviceList(&list); 386 | if (list.num_devices == 0) 387 | { 388 | error("sensel: discover failed--no device found."); 389 | return; 390 | } 391 | 392 | int i = 0; 393 | int found = 0; 394 | 395 | while(i < list.num_devices) 396 | { 397 | if (!check_if_already_on_sensel_device_list(gensym((const char *)list.devices[i].serial_num))) 398 | { 399 | found = 1; 400 | break; 401 | } 402 | i++; 403 | } 404 | if (!found) 405 | { 406 | error("sensel: discover failed--all discoverable devices are already connected to another sensel object."); 407 | return; 408 | } 409 | 410 | // Open a Sensel device by the id in the SenselDeviceList, handle initialized 411 | senselOpenDeviceByID(&x->x_handle, list.devices[i].idx); 412 | 413 | // Set the frame content to scan contact data 414 | senselSetFrameContent(x->x_handle, FRAME_CONTENT_CONTACTS_MASK); 415 | 416 | // Allocate a frame of data, must be done before reading frame data 417 | senselAllocateFrameData(x->x_handle, &x->x_frame); 418 | 419 | // Post information to the Pd console 420 | post("sensel: successfully connected to device with a serial number %s.", list.devices[i].serial_num); 421 | 422 | x->x_serial = gensym((const char *)list.devices[i].serial_num); 423 | add_connected_to_sensel_device_list(x->x_serial); 424 | 425 | x->x_connected = 1; 426 | 427 | outlet_float(x->x_outlet_status, x->x_connected); 428 | } 429 | 430 | /* 431 | Lists serial numbers of all available Sensel Morphs 432 | */ 433 | static void sensel_identify(t_sensel *x) 434 | { 435 | // disable polling while doing identifying 436 | // as this tends to misbehave on Macs when 437 | // it gets this request while outputting data 438 | pthread_mutex_lock(&x->x_unsafe_mutex); 439 | 440 | // List of all available Sensel devices 441 | SenselDeviceList list; 442 | 443 | // Get a list of available Sensel devices 444 | senselGetDeviceList(&list); 445 | if (list.num_devices == 0) 446 | { 447 | post("sensel: identify found no devices."); 448 | return; 449 | } 450 | 451 | post("sensel: identify found following devices:"); 452 | 453 | int i; 454 | for (i = 0; i < list.num_devices; i++) 455 | { 456 | post("%d: %s", i+1, list.devices[i].serial_num); 457 | } 458 | // reenable polling since we are now done 459 | pthread_mutex_unlock(&x->x_unsafe_mutex); 460 | } 461 | 462 | /* 463 | Polls for the Sensel contact data. Outputs a list for every 464 | current contact, each comprised of 19 data points, listed 465 | clearly in the code. 466 | */ 467 | static void sensel_poll(t_sensel *x) 468 | { 469 | 470 | if (x->x_connected == 1) 471 | { 472 | 473 | unsigned int num_frames = 0; 474 | 475 | t_data *temp; 476 | 477 | // Read all available data from the Sensel device 478 | senselReadSensor(x->x_handle); 479 | 480 | senselGetNumAvailableFrames(x->x_handle, &num_frames); 481 | 482 | for (unsigned int f = 0; f < num_frames; f++) 483 | { 484 | 485 | // Read one frame of data 486 | senselGetFrame(x->x_handle, x->x_frame); 487 | 488 | for (int c = 0; c < x->x_frame->n_contacts; c++) 489 | { 490 | 491 | if (x->x_data == NULL) // this is the first time around 492 | { 493 | x->x_data = (t_data *)getbytes(sizeof(t_data)); 494 | x->x_data->next = NULL; 495 | x->x_data->type = 0; 496 | 497 | x->x_data_end = x->x_data; 498 | } 499 | else 500 | { 501 | temp = (t_data *)getbytes(sizeof(t_data)); 502 | temp->next = NULL; 503 | temp->type = 0; 504 | 505 | x->x_data_end->next = temp; 506 | x->x_data_end = temp; 507 | } 508 | 509 | SETFLOAT(&(x->x_data_end->args[0]), x->x_frame->contacts[c].id); 510 | SETFLOAT(&(x->x_data_end->args[1]), x->x_frame->contacts[c].state); 511 | SETFLOAT(&(x->x_data_end->args[2]), x->x_frame->contacts[c].orientation); 512 | SETFLOAT(&(x->x_data_end->args[3]), x->x_frame->contacts[c].major_axis); 513 | SETFLOAT(&(x->x_data_end->args[4]), x->x_frame->contacts[c].minor_axis); 514 | SETFLOAT(&(x->x_data_end->args[5]), x->x_frame->contacts[c].delta_x); 515 | SETFLOAT(&(x->x_data_end->args[6]), x->x_frame->contacts[c].delta_y); 516 | SETFLOAT(&(x->x_data_end->args[7]), x->x_frame->contacts[c].delta_force); 517 | SETFLOAT(&(x->x_data_end->args[8]), x->x_frame->contacts[c].delta_area); 518 | SETFLOAT(&(x->x_data_end->args[9]), x->x_frame->contacts[c].min_x); 519 | SETFLOAT(&(x->x_data_end->args[10]), x->x_frame->contacts[c].min_y); 520 | SETFLOAT(&(x->x_data_end->args[11]), x->x_frame->contacts[c].max_x); 521 | SETFLOAT(&(x->x_data_end->args[12]), x->x_frame->contacts[c].max_y); 522 | SETFLOAT(&(x->x_data_end->args[13]), x->x_frame->contacts[c].peak_x); 523 | SETFLOAT(&(x->x_data_end->args[14]), x->x_frame->contacts[c].peak_y); 524 | SETFLOAT(&(x->x_data_end->args[16]), x->x_frame->contacts[c].x_pos); 525 | SETFLOAT(&(x->x_data_end->args[17]), x->x_frame->contacts[c].y_pos); 526 | SETFLOAT(&(x->x_data_end->args[19]), x->x_frame->contacts[c].area); 527 | 528 | if (x->x_frame->contacts[c].state != 3) 529 | { 530 | SETFLOAT(&(x->x_data_end->args[15]), x->x_frame->contacts[c].peak_force); 531 | SETFLOAT(&(x->x_data_end->args[18]), x->x_frame->contacts[c].total_force); 532 | } 533 | else 534 | { 535 | SETFLOAT(&(x->x_data_end->args[15]), 0); 536 | SETFLOAT(&(x->x_data_end->args[18]), 0); 537 | } 538 | 539 | x->x_data_end->type = 0; 540 | } 541 | // output a total number of contacts 542 | if (x->x_frame->n_contacts != x->x_n_contacts) 543 | { 544 | if (x->x_data == NULL) // this is the first time around 545 | { 546 | x->x_data = (t_data *)getbytes(sizeof(t_data)); 547 | x->x_data->next = NULL; 548 | x->x_data->type = 1; 549 | 550 | x->x_data_end = x->x_data; 551 | } 552 | else 553 | { 554 | temp = (t_data *)getbytes(sizeof(t_data)); 555 | temp->next = NULL; 556 | temp->type = 1; 557 | 558 | x->x_data_end->next = temp; 559 | x->x_data_end = temp; 560 | } 561 | SETFLOAT(&(x->x_data_end->args[0]), x->x_frame->n_contacts); 562 | x->x_n_contacts = x->x_frame->n_contacts; 563 | } 564 | } 565 | 566 | if (x->x_data != NULL) 567 | { 568 | clock_delay(x->x_clock_output, 0); 569 | x->x_clock_set = 1; 570 | } 571 | } 572 | } 573 | 574 | /* 575 | Constructor for the sensel object 576 | */ 577 | static void *sensel_new() 578 | { 579 | post("L2Ork Sensel Morph v.1.2.0"); 580 | 581 | t_sensel *x = (t_sensel *)pd_new(sensel_class); 582 | 583 | x->x_outlet_data = outlet_new(&x->x_obj, &s_list); 584 | x->x_outlet_status = outlet_new(&x->x_obj, &s_float); 585 | 586 | x->x_connected = 0; 587 | x->x_thread_connected = 0; 588 | x->x_n_contacts = 0; 589 | x->x_frame = NULL; 590 | x->x_data = NULL; 591 | x->x_data_end = NULL; 592 | 593 | for (int i = 0; i < 24; i++) 594 | { 595 | x->x_led[i] = 0; 596 | x->x_thread_led[i] = 0; 597 | } 598 | 599 | x->x_clock_output = clock_new(x, (t_method)sensel_output_data); 600 | x->x_clock_set = 0; 601 | 602 | // prep the secondary thread init variable 603 | x->x_unsafe = 1; 604 | 605 | // initialize 10ms polling time expressed in useconds 606 | x->x_poll_wait = 10000; 607 | 608 | t_threadedFunctionParams rPars; 609 | rPars.s_inst = x; 610 | pthread_mutex_init(&x->x_unsafe_mutex, NULL); 611 | //pthread_cond_init(&x->x_unsafe_cond, NULL); 612 | pthread_create( &x->x_unsafe_t, NULL, (void *) &sensel_pthreadForAudioUnfriendlyOperations, (void *) &rPars); 613 | 614 | // wait until other thread has properly intialized so that 615 | // rPars do not get destroyed before the thread has gotten its 616 | // pointer information 617 | while(x->x_unsafe == 1) 618 | { 619 | sched_yield(); 620 | } 621 | 622 | return(x); 623 | } 624 | 625 | /* 626 | Disconnects the Sensel Morph 627 | */ 628 | static void sensel_disconnect(t_sensel *x) 629 | { 630 | if (x->x_connected) 631 | { 632 | x->x_connected = 0; 633 | while(x->x_thread_connected != x->x_connected) 634 | sched_yield(); 635 | 636 | remove_connected_to_sensel_device_list(x->x_serial); 637 | x->x_serial = NULL; 638 | 639 | outlet_float(x->x_outlet_status, x->x_connected); 640 | } 641 | else 642 | { 643 | error("sensel: disconnect failed--no device connected."); 644 | } 645 | } 646 | 647 | 648 | /* 649 | Frees the object (when it is deleted) 650 | */ 651 | static void sensel_free(t_sensel * x) 652 | { 653 | if (x->x_connected) { 654 | sensel_disconnect(x); 655 | } 656 | 657 | x->x_unsafe = -1; 658 | 659 | pthread_join(x->x_unsafe_t, NULL); 660 | pthread_mutex_destroy(&x->x_unsafe_mutex); 661 | 662 | clock_free(x->x_clock_output); 663 | 664 | // delete any leftover single-linked output data list 665 | t_data *last = NULL; 666 | while (x->x_data != NULL) 667 | { 668 | outlet_list(x->x_outlet_data, gensym("list"), 19, x->x_data->args); 669 | last = x->x_data; 670 | x->x_data = x->x_data->next; 671 | free(last); 672 | } 673 | } 674 | 675 | /* 676 | Init sensel object 677 | */ 678 | void sensel_setup(void) 679 | { 680 | sensel_class = class_new(gensym("sensel"), 681 | (t_newmethod)sensel_new, (t_method)sensel_free, 682 | sizeof(t_sensel), CLASS_DEFAULT, 0); 683 | 684 | //class_addbang(sensel_class, (t_method)sensel_bang); 685 | class_addmethod(sensel_class, (t_method)sensel_connect, 686 | gensym("connect"), A_SYMBOL, 0); 687 | class_addmethod(sensel_class, (t_method)sensel_discover, 688 | gensym("discover"), 0); 689 | class_addmethod(sensel_class, (t_method)sensel_disconnect, 690 | gensym("disconnect"), 0); 691 | class_addmethod(sensel_class, (t_method)sensel_identify, 692 | gensym("identify"), 0); 693 | class_addmethod(sensel_class, (t_method)sensel_set_poll_wait_time, 694 | gensym("poll"), A_FLOAT); 695 | class_addmethod(sensel_class, (t_method)sensel_set_led, 696 | gensym("led"), A_FLOAT, A_FLOAT, 0); 697 | } 698 | -------------------------------------------------------------------------------- /sensel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensel/PD-objects/50f70168c2d182ceb5d8355c7dfdfd4ec95a842f/sensel.dll -------------------------------------------------------------------------------- /sensel.pd_darwin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensel/PD-objects/50f70168c2d182ceb5d8355c7dfdfd4ec95a842f/sensel.pd_darwin -------------------------------------------------------------------------------- /sensel.pd_linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensel/PD-objects/50f70168c2d182ceb5d8355c7dfdfd4ec95a842f/sensel.pd_linux -------------------------------------------------------------------------------- /sensel_examples/SenselDMX.pd: -------------------------------------------------------------------------------- 1 | #N canvas 419 62 1238 755 12; 2 | #X declare -path list-abs; 3 | #X declare -path comport; 4 | #X declare -path list-abs; 5 | #X declare -path ./abs; 6 | #X declare -path mapping; 7 | #X obj 133 464 vsl 15 128 0 255 0 0 empty empty empty 0 -9 0 10 -258113 8 | -1 -1 0 1; 9 | #X obj 213 464 vsl 15 128 0 255 0 0 empty empty empty 0 -9 0 10 -4034 10 | -1 -1 0 1; 11 | #X obj 293 464 vsl 15 128 0 255 0 0 empty empty empty 0 -9 0 10 -4160 12 | -1 -1 0 1; 13 | #X obj 466 66 list-replace; 14 | #X obj 466 9 r value; 15 | #X obj 500 36 r index; 16 | #X obj 575 67 list; 17 | #X obj 43 460 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -228856 18 | -1 -1 0 1; 19 | #X text 11 15 126 6 LSB MSB start_code ... 231; 20 | #X text 12 -2 Format for list to send over Enttec USB DMX is:; 21 | #X text 11 32 where LSB MSB : length of start_code + length of 22 | ; 23 | #X text 11 100 For a simple RGB light \, you might have 4 channels 24 | - Brightness \, R \, G \, B.; 25 | #X text 114 193 0 0 0 0 255 200 150 50; 26 | #X text 305 193 231; 27 | #X obj 67 363 % 256; 28 | #X obj 130 361 / 256; 29 | #X floatatom 97 330 5 0 0 0 - - -; 30 | #X floatatom 129 417 5 0 0 0 - - -; 31 | #X obj 130 390 i; 32 | #X floatatom 66 416 5 0 0 0 - - -; 33 | #X msg 98 272 8; 34 | #X text 10 193 126 6 9 0 0; 35 | #X obj 98 302 + 1; 36 | #X text 29 221 calculate LSB and MSB; 37 | #X text 29 240 for a list of 8 channels; 38 | #X text 131 301 start code adds one element to list length; 39 | #X text 11 59 is simply a list where index position is channel 40 | and value is the value.; 41 | #X text 11 141 If the light is set to start at channel 5 \, you can 42 | make a; 43 | #X text 11 157 bright orange with a list such as:; 44 | #X text 22 641 Control of simple Litake DMX RGB light fixture; 45 | #N canvas 0 50 548 466 initial-list-creation 0; 46 | #X obj 171 133 t b b b; 47 | #X obj 190 346 list append; 48 | #X msg 289 229 231; 49 | #X obj 190 233 until; 50 | #X msg 190 267 0; 51 | #X msg 91 230 126 6 1 2; 52 | #X obj 190 383 outlet; 53 | #X obj 171 106 loadbang; 54 | #X msg 190 201 513; 55 | #X obj 287 363 list; 56 | #X text 58 19 sets up a list for all possible 512 channels; 57 | #X text 59 43 by maxing out the list \, we don't need to update; 58 | #X text 58 63 the LSB and MSB values for the "header"; 59 | #X connect 0 0 5 0; 60 | #X connect 0 1 8 0; 61 | #X connect 0 2 2 0; 62 | #X connect 1 0 6 0; 63 | #X connect 1 0 9 0; 64 | #X connect 2 0 1 0; 65 | #X connect 3 0 4 0; 66 | #X connect 4 0 1 0; 67 | #X connect 5 0 1 0; 68 | #X connect 7 0 0 0; 69 | #X connect 8 0 3 0; 70 | #X connect 9 0 1 1; 71 | #X restore 571 35 pd initial-list-creation; 72 | #X text 461 -34 thanks to https://wiki.labomedia.org/index.php/Pure_Data_vs_Enttec_Pro 73 | ; 74 | #X msg 655 162 ports; 75 | #X msg 492 161 open \$1; 76 | #X obj 531 243 route ports; 77 | #X obj 531 272 print Ports; 78 | #X obj 655 132 loadbang; 79 | #X msg 562 161 baud 115200; 80 | #X msg 491 133 2; 81 | #X obj 792 242 sensel; 82 | #X msg 788 162 discover; 83 | #X msg 788 183 disconnect; 84 | #X msg 788 204 identify; 85 | #X msg 879 183 connect SM01172411629; 86 | #X msg 879 162 connect SM01173912638; 87 | #X obj 791 274 route contacts; 88 | #X obj 492 208 comport; 89 | #X msg 706 162 close; 90 | #N canvas 557 61 723 717 XY-left-first3 0; 91 | #X obj 226 155 moses 115; 92 | #X obj 226 126 list-nth 16; 93 | #X obj 328 126 list-nth 0; 94 | #X obj 138 125 list-nth 1; 95 | #X obj 139 154 sel 3; 96 | #X obj 232 259 0; 97 | #X obj 275 220 t b; 98 | #X obj 44 35 inlet; 99 | #X obj 367 216 loadbang; 100 | #X msg 369 252 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 101 | #X text 230 102 X; 102 | #X text 129 101 Touch state; 103 | #X obj 45 131 list-nth 17; 104 | #X text 49 107 Y; 105 | #X text 330 98 Contact ID; 106 | #X obj 44 69 t list list list list b, f 56; 107 | #X obj 230 382 list-replace; 108 | #X obj 230 435 list-filter; 109 | #X obj 328 381 list; 110 | #X obj 427 126 1000; 111 | #X obj 213 324 min; 112 | #X msg 380 293 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 113 | #X obj 325 433 > 0; 114 | #X obj 229 469 list split 3; 115 | #X obj 226 497 route bang; 116 | #X obj 338 565 outlet; 117 | #X connect 0 1 6 0; 118 | #X connect 1 0 0 0; 119 | #X connect 2 0 16 1; 120 | #X connect 3 0 4 0; 121 | #X connect 4 0 5 0; 122 | #X connect 5 0 20 1; 123 | #X connect 6 0 5 0; 124 | #X connect 7 0 15 0; 125 | #X connect 8 0 9 0; 126 | #X connect 9 0 16 2; 127 | #X connect 12 0 20 0; 128 | #X connect 15 0 12 0; 129 | #X connect 15 1 3 0; 130 | #X connect 15 2 1 0; 131 | #X connect 15 3 2 0; 132 | #X connect 15 4 19 0; 133 | #X connect 16 0 17 0; 134 | #X connect 16 0 18 0; 135 | #X connect 17 0 23 0; 136 | #X connect 17 1 22 0; 137 | #X connect 18 0 16 2; 138 | #X connect 19 0 20 1; 139 | #X connect 20 0 16 0; 140 | #X connect 21 0 16 0; 141 | #X connect 22 0 17 1; 142 | #X connect 23 0 24 0; 143 | #X connect 23 2 24 0; 144 | #X connect 24 1 25 0; 145 | #X restore 624 357 pd XY-left-first3; 146 | #X obj 624 390 unpack 0 0 0; 147 | #N canvas 43 248 641 434 left-avg-force 0; 148 | #X obj 221 193 moses 115; 149 | #X obj 221 164 list-nth 16; 150 | #X obj 323 164 list-nth 0; 151 | #X obj 37 165 list-nth 1; 152 | #X obj 38 194 sel 3; 153 | #X obj 221 256 0; 154 | #X obj 221 225 t b; 155 | #X obj 44 35 inlet; 156 | #X obj 367 216 loadbang; 157 | #X msg 367 250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 158 | #X text 225 140 X; 159 | #X text 28 141 Touch state; 160 | #X obj 49 65 t list list list list; 161 | #X obj 127 325 list-replace; 162 | #X obj 127 289 t f; 163 | #X obj 229 327 list; 164 | #X obj 128 392 outlet; 165 | #N canvas 0 23 566 554 list-mean-nozero 0; 166 | #X obj 71 47 inlet; 167 | #X obj 70 371 outlet; 168 | #X obj 90 116 list-drip; 169 | #X obj 90 143 route float; 170 | #X obj 70 308 f; 171 | #X obj 70 342 /; 172 | #X obj 89 223 t a b; 173 | #N canvas 370 313 450 300 accum 0; 174 | #X obj 182 102 0; 175 | #X obj 135 79 inlet; 176 | #X obj 182 79 inlet; 177 | #X obj 135 169 outlet; 178 | #X obj 135 137 +; 179 | #X obj 168 138 f; 180 | #X connect 0 0 4 1; 181 | #X connect 1 0 4 0; 182 | #X connect 2 0 0 0; 183 | #X connect 4 0 3 0; 184 | #X connect 4 0 5 0; 185 | #X connect 5 0 4 1; 186 | #X restore 89 258 pd accum; 187 | #N canvas 425 298 450 300 count 0; 188 | #X obj 133 59 b; 189 | #X obj 133 35 inlet; 190 | #X obj 183 35 inlet; 191 | #X obj 164 111 + 1; 192 | #X obj 133 133 outlet; 193 | #X msg 183 71 1; 194 | #X obj 133 110 f 1; 195 | #X connect 0 0 6 0; 196 | #X connect 1 0 0 0; 197 | #X connect 2 0 5 0; 198 | #X connect 3 0 6 1; 199 | #X connect 5 0 6 1; 200 | #X connect 6 0 3 0; 201 | #X connect 6 0 4 0; 202 | #X restore 161 259 pd count; 203 | #X obj 71 83 t b a b b; 204 | #X obj 91 178 sel 0; 205 | #X msg 162 40 1 2 3 4 5; 206 | #X msg 163 65 1 0 2 0 3 4 0 5; 207 | #X text 67 400 average X position of contacts on the left; 208 | #X connect 0 0 9 0; 209 | #X connect 2 0 3 0; 210 | #X connect 3 0 10 0; 211 | #X connect 4 0 5 0; 212 | #X connect 5 0 1 0; 213 | #X connect 6 0 7 0; 214 | #X connect 6 1 8 0; 215 | #X connect 7 0 4 1; 216 | #X connect 8 0 5 1; 217 | #X connect 9 0 4 0; 218 | #X connect 9 1 2 0; 219 | #X connect 9 2 7 1; 220 | #X connect 9 3 8 1; 221 | #X connect 10 1 6 0; 222 | #X connect 11 0 9 0; 223 | #X connect 12 0 9 0; 224 | #X restore 127 358 pd list-mean-nozero; 225 | #X text 325 136 Contact ID; 226 | #X obj 127 166 list-nth 18; 227 | #X text 131 142 Press; 228 | #X connect 0 1 6 0; 229 | #X connect 1 0 0 0; 230 | #X connect 2 0 13 1; 231 | #X connect 3 0 4 0; 232 | #X connect 4 0 5 0; 233 | #X connect 5 0 14 0; 234 | #X connect 6 0 5 0; 235 | #X connect 7 0 12 0; 236 | #X connect 8 0 9 0; 237 | #X connect 9 0 13 2; 238 | #X connect 12 0 19 0; 239 | #X connect 12 1 3 0; 240 | #X connect 12 2 1 0; 241 | #X connect 12 3 2 0; 242 | #X connect 13 0 15 0; 243 | #X connect 13 0 17 0; 244 | #X connect 14 0 13 0; 245 | #X connect 15 0 13 2; 246 | #X connect 17 0 16 0; 247 | #X connect 19 0 14 0; 248 | #X restore 441 359 pd left-avg-force; 249 | #X obj 443 424 - 127; 250 | #X obj 442 448 abs; 251 | #X obj 1008 392 unpack 0 0 0; 252 | #N canvas 1509 479 723 717 XY-rt-first3 0; 253 | #X obj 226 155 moses 115; 254 | #X obj 226 126 list-nth 16; 255 | #X obj 328 126 list-nth 0; 256 | #X obj 138 125 list-nth 1; 257 | #X obj 139 154 sel 3; 258 | #X obj 232 259 0; 259 | #X obj 226 193 t b; 260 | #X obj 44 35 inlet; 261 | #X obj 367 216 loadbang; 262 | #X msg 369 252 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 263 | #X text 230 102 X; 264 | #X text 129 101 Touch state; 265 | #X obj 45 131 list-nth 17; 266 | #X text 49 107 Y; 267 | #X text 330 98 Contact ID; 268 | #X obj 44 69 t list list list list b, f 56; 269 | #X obj 230 382 list-replace; 270 | #X obj 230 435 list-filter; 271 | #X obj 328 381 list; 272 | #X obj 427 126 1000; 273 | #X obj 213 324 min; 274 | #X msg 380 293 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 275 | #X obj 325 433 > 0; 276 | #X obj 229 469 list split 3; 277 | #X obj 226 497 route bang; 278 | #X obj 338 565 outlet; 279 | #X connect 0 0 6 0; 280 | #X connect 1 0 0 0; 281 | #X connect 2 0 16 1; 282 | #X connect 3 0 4 0; 283 | #X connect 4 0 5 0; 284 | #X connect 5 0 20 1; 285 | #X connect 6 0 5 0; 286 | #X connect 7 0 15 0; 287 | #X connect 8 0 9 0; 288 | #X connect 9 0 16 2; 289 | #X connect 12 0 20 0; 290 | #X connect 15 0 12 0; 291 | #X connect 15 1 3 0; 292 | #X connect 15 2 1 0; 293 | #X connect 15 3 2 0; 294 | #X connect 15 4 19 0; 295 | #X connect 16 0 17 0; 296 | #X connect 16 0 18 0; 297 | #X connect 17 0 23 0; 298 | #X connect 17 1 22 0; 299 | #X connect 18 0 16 2; 300 | #X connect 19 0 20 1; 301 | #X connect 20 0 16 0; 302 | #X connect 21 0 16 0; 303 | #X connect 22 0 17 1; 304 | #X connect 23 0 24 0; 305 | #X connect 23 2 24 0; 306 | #X connect 24 1 25 0; 307 | #X restore 1008 359 pd XY-rt-first3; 308 | #N canvas 0 23 670 441 Chs-1-4 0; 309 | #X obj 149 192 t f b; 310 | #X obj 176 290 s index; 311 | #X obj 149 342 s value; 312 | #X obj 149 316 i; 313 | #X obj 176 264 + 4; 314 | #X obj 229 192 t f b; 315 | #X obj 256 290 s index; 316 | #X obj 229 342 s value; 317 | #X obj 229 316 i; 318 | #X obj 256 264 + 4; 319 | #X obj 309 192 t f b; 320 | #X obj 336 290 s index; 321 | #X obj 309 342 s value; 322 | #X obj 309 316 i; 323 | #X obj 336 264 + 4; 324 | #X obj 59 192 t f b; 325 | #X obj 86 286 s index; 326 | #X obj 59 338 s value; 327 | #X obj 59 312 i; 328 | #X obj 86 260 + 4; 329 | #X obj 86 234 1; 330 | #X obj 176 238 2; 331 | #X obj 256 238 3; 332 | #X obj 335 237 4; 333 | #X text 373 234 channel; 334 | #X text 375 265 +4 - offset in position of list; 335 | #X obj 54 122 inlet; 336 | #X obj 141 117 inlet; 337 | #X obj 223 121 inlet; 338 | #X obj 301 117 inlet; 339 | #X text 48 87 Bright Red Green Blue; 340 | #X connect 0 0 3 0; 341 | #X connect 0 1 21 0; 342 | #X connect 3 0 2 0; 343 | #X connect 4 0 1 0; 344 | #X connect 5 0 8 0; 345 | #X connect 5 1 22 0; 346 | #X connect 8 0 7 0; 347 | #X connect 9 0 6 0; 348 | #X connect 10 0 13 0; 349 | #X connect 10 1 23 0; 350 | #X connect 13 0 12 0; 351 | #X connect 14 0 11 0; 352 | #X connect 15 0 18 0; 353 | #X connect 15 1 20 0; 354 | #X connect 18 0 17 0; 355 | #X connect 19 0 16 0; 356 | #X connect 20 0 19 0; 357 | #X connect 21 0 4 0; 358 | #X connect 22 0 9 0; 359 | #X connect 23 0 14 0; 360 | #X connect 26 0 15 0; 361 | #X connect 27 0 0 0; 362 | #X connect 28 0 5 0; 363 | #X connect 29 0 10 0; 364 | #X restore 635 537 pd Chs-1-4; 365 | #N canvas 0 23 670 441 Chs-5-8 0; 366 | #X obj 149 192 t f b; 367 | #X obj 176 290 s index; 368 | #X obj 149 342 s value; 369 | #X obj 149 316 i; 370 | #X obj 176 264 + 4; 371 | #X obj 229 192 t f b; 372 | #X obj 256 290 s index; 373 | #X obj 229 342 s value; 374 | #X obj 229 316 i; 375 | #X obj 256 264 + 4; 376 | #X obj 309 192 t f b; 377 | #X obj 336 290 s index; 378 | #X obj 309 342 s value; 379 | #X obj 309 316 i; 380 | #X obj 336 264 + 4; 381 | #X obj 59 192 t f b; 382 | #X obj 86 286 s index; 383 | #X obj 59 338 s value; 384 | #X obj 59 312 i; 385 | #X obj 86 260 + 4; 386 | #X text 373 234 channel; 387 | #X text 375 265 +4 - offset in position of list; 388 | #X obj 54 122 inlet; 389 | #X obj 141 117 inlet; 390 | #X obj 223 121 inlet; 391 | #X obj 301 117 inlet; 392 | #X text 48 87 Bright Red Green Blue; 393 | #X obj 86 234 5; 394 | #X obj 176 238 6; 395 | #X obj 256 238 7; 396 | #X obj 335 237 8; 397 | #X connect 0 0 3 0; 398 | #X connect 0 1 28 0; 399 | #X connect 3 0 2 0; 400 | #X connect 4 0 1 0; 401 | #X connect 5 0 8 0; 402 | #X connect 5 1 29 0; 403 | #X connect 8 0 7 0; 404 | #X connect 9 0 6 0; 405 | #X connect 10 0 13 0; 406 | #X connect 10 1 30 0; 407 | #X connect 13 0 12 0; 408 | #X connect 14 0 11 0; 409 | #X connect 15 0 18 0; 410 | #X connect 15 1 27 0; 411 | #X connect 18 0 17 0; 412 | #X connect 19 0 16 0; 413 | #X connect 22 0 15 0; 414 | #X connect 23 0 0 0; 415 | #X connect 24 0 5 0; 416 | #X connect 25 0 10 0; 417 | #X connect 27 0 19 0; 418 | #X connect 28 0 4 0; 419 | #X connect 29 0 9 0; 420 | #X connect 30 0 14 0; 421 | #X restore 877 540 pd Chs-5-8; 422 | #X obj 832 433 - 127; 423 | #X obj 831 457 abs; 424 | #N canvas 539 171 692 525 rt-avg-force 0; 425 | #X obj 221 193 moses 115; 426 | #X obj 221 164 list-nth 16; 427 | #X obj 323 164 list-nth 0; 428 | #X obj 37 165 list-nth 1; 429 | #X obj 38 194 sel 3; 430 | #X obj 221 256 0; 431 | #X obj 221 225 t b; 432 | #X obj 44 35 inlet; 433 | #X obj 367 216 loadbang; 434 | #X msg 367 250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 435 | #X text 225 140 X; 436 | #X text 28 141 Touch state; 437 | #X obj 49 65 t list list list list; 438 | #X obj 127 325 list-replace; 439 | #X obj 127 289 t f; 440 | #X obj 229 327 list; 441 | #X obj 128 392 outlet; 442 | #N canvas 0 23 566 554 list-mean-nozero 0; 443 | #X obj 71 47 inlet; 444 | #X obj 70 371 outlet; 445 | #X obj 90 116 list-drip; 446 | #X obj 90 143 route float; 447 | #X obj 70 308 f; 448 | #X obj 70 342 /; 449 | #X obj 89 223 t a b; 450 | #N canvas 370 313 450 300 accum 0; 451 | #X obj 182 102 0; 452 | #X obj 135 79 inlet; 453 | #X obj 182 79 inlet; 454 | #X obj 135 169 outlet; 455 | #X obj 135 137 +; 456 | #X obj 168 138 f; 457 | #X connect 0 0 4 1; 458 | #X connect 1 0 4 0; 459 | #X connect 2 0 0 0; 460 | #X connect 4 0 3 0; 461 | #X connect 4 0 5 0; 462 | #X connect 5 0 4 1; 463 | #X restore 89 258 pd accum; 464 | #N canvas 425 298 450 300 count 0; 465 | #X obj 133 59 b; 466 | #X obj 133 35 inlet; 467 | #X obj 183 35 inlet; 468 | #X obj 164 111 + 1; 469 | #X obj 133 133 outlet; 470 | #X msg 183 71 1; 471 | #X obj 133 110 f 1; 472 | #X connect 0 0 6 0; 473 | #X connect 1 0 0 0; 474 | #X connect 2 0 5 0; 475 | #X connect 3 0 6 1; 476 | #X connect 5 0 6 1; 477 | #X connect 6 0 3 0; 478 | #X connect 6 0 4 0; 479 | #X restore 161 259 pd count; 480 | #X obj 71 83 t b a b b; 481 | #X obj 91 178 sel 0; 482 | #X msg 162 40 1 2 3 4 5; 483 | #X msg 163 65 1 0 2 0 3 4 0 5; 484 | #X text 67 400 average X position of contacts on the left; 485 | #X connect 0 0 9 0; 486 | #X connect 2 0 3 0; 487 | #X connect 3 0 10 0; 488 | #X connect 4 0 5 0; 489 | #X connect 5 0 1 0; 490 | #X connect 6 0 7 0; 491 | #X connect 6 1 8 0; 492 | #X connect 7 0 4 1; 493 | #X connect 8 0 5 1; 494 | #X connect 9 0 4 0; 495 | #X connect 9 1 2 0; 496 | #X connect 9 2 7 1; 497 | #X connect 9 3 8 1; 498 | #X connect 10 1 6 0; 499 | #X connect 11 0 9 0; 500 | #X connect 12 0 9 0; 501 | #X restore 127 358 pd list-mean-nozero; 502 | #X text 325 136 Contact ID; 503 | #X obj 127 166 list-nth 18; 504 | #X text 131 142 Press; 505 | #X connect 0 0 6 0; 506 | #X connect 1 0 0 0; 507 | #X connect 2 0 13 1; 508 | #X connect 3 0 4 0; 509 | #X connect 4 0 5 0; 510 | #X connect 5 0 14 0; 511 | #X connect 6 0 5 0; 512 | #X connect 7 0 12 0; 513 | #X connect 8 0 9 0; 514 | #X connect 9 0 13 2; 515 | #X connect 12 0 19 0; 516 | #X connect 12 1 3 0; 517 | #X connect 12 2 1 0; 518 | #X connect 12 3 2 0; 519 | #X connect 13 0 15 0; 520 | #X connect 13 0 17 0; 521 | #X connect 14 0 13 0; 522 | #X connect 15 0 13 2; 523 | #X connect 17 0 16 0; 524 | #X connect 19 0 14 0; 525 | #X restore 830 360 pd rt-avg-force; 526 | #N canvas 0 23 685 444 controlLitakeLight 0; 527 | #X obj 155 140 t f b; 528 | #X obj 182 238 s index; 529 | #X obj 155 290 s value; 530 | #X obj 155 264 i; 531 | #X obj 182 212 + 4; 532 | #X obj 235 140 t f b; 533 | #X obj 262 238 s index; 534 | #X obj 235 290 s value; 535 | #X obj 235 264 i; 536 | #X obj 262 212 + 4; 537 | #X obj 315 140 t f b; 538 | #X obj 342 238 s index; 539 | #X obj 315 290 s value; 540 | #X obj 315 264 i; 541 | #X obj 342 212 + 4; 542 | #X obj 65 140 t f b; 543 | #X obj 92 234 s index; 544 | #X obj 65 286 s value; 545 | #X obj 65 260 i; 546 | #X obj 92 208 + 4; 547 | #X obj 92 182 1; 548 | #X obj 182 186 2; 549 | #X obj 262 186 3; 550 | #X obj 341 185 4; 551 | #X text 379 182 channel; 552 | #X text 381 213 +4 - offset in position of list; 553 | #X floatatom 65 106 5 0 127 0 - - -; 554 | #X floatatom 155 106 5 0 0 0 - - -; 555 | #X floatatom 235 106 5 0 0 0 - - -; 556 | #X floatatom 315 106 5 0 0 0 - - -; 557 | #X obj 57 69 inlet; 558 | #X obj 155 68 inlet; 559 | #X obj 234 69 inlet; 560 | #X obj 316 70 inlet; 561 | #X floatatom 22 107 5 128 250 0 - - -; 562 | #X text 64 317 Litake has max range of 0-127 for brightness. Values 563 | 128-250 control a strobe effect.; 564 | #X connect 0 0 3 0; 565 | #X connect 0 1 21 0; 566 | #X connect 3 0 2 0; 567 | #X connect 4 0 1 0; 568 | #X connect 5 0 8 0; 569 | #X connect 5 1 22 0; 570 | #X connect 8 0 7 0; 571 | #X connect 9 0 6 0; 572 | #X connect 10 0 13 0; 573 | #X connect 10 1 23 0; 574 | #X connect 13 0 12 0; 575 | #X connect 14 0 11 0; 576 | #X connect 15 0 18 0; 577 | #X connect 15 1 20 0; 578 | #X connect 18 0 17 0; 579 | #X connect 19 0 16 0; 580 | #X connect 20 0 19 0; 581 | #X connect 21 0 4 0; 582 | #X connect 22 0 9 0; 583 | #X connect 23 0 14 0; 584 | #X connect 26 0 15 0; 585 | #X connect 27 0 0 0; 586 | #X connect 28 0 5 0; 587 | #X connect 29 0 10 0; 588 | #X connect 30 0 15 0; 589 | #X connect 31 0 0 0; 590 | #X connect 32 0 5 0; 591 | #X connect 33 0 10 0; 592 | #X connect 34 0 15 0; 593 | #X restore 94 606 pd controlLitakeLight; 594 | #X text 962 52 comport is available in deken; 595 | #X obj 800 30 declare -path list-abs; 596 | #X obj 800 52 declare -path comport; 597 | #X text 965 28 uses list-abs package in deken; 598 | #X text 474 448 darken on press; 599 | #X text 508 568 The first three contacts on the left; 600 | #X text 506 589 control RGB mix with their y-positions.; 601 | #X text 852 566 The first three contacts on the left; 602 | #X text 850 587 control RGB mix with their y-positions.; 603 | #X text 508 611 for channels 1-4. Pressure dims the light.; 604 | #X text 849 609 for channels 5-8. Pressure dims the light.; 605 | #N canvas 0 23 552 293 product-links 0; 606 | #X obj 1030 66 declare -path list-abs; 607 | #X text 66 46 https://dmxking.com/usbdmx/ultradmxmicro; 608 | #X text 59 24 DMX King USB DMX adapter.; 609 | #X text 60 148 Enttec DMX Pro (and maybe others?); 610 | #X text 82 166 https://www.enttec.com/range/lighting-communication-protocols/dmx512/ 611 | ; 612 | #X text 59 79 Litake Par Lights DMX; 613 | #X text 79 100 https://www.amazon.com/dp/B01KZPDVQO; 614 | #X text 64 217 Sensel Morph; 615 | #X text 89 240 http://sensel.com/morph; 616 | #X restore 751 648 pd product-links; 617 | #X obj 799 98 declare -path ./abs; 618 | #X text 945 97 local abstractions; 619 | #X obj 848 244 r sensel; 620 | #X obj 465 93 resample 10; 621 | #X obj 801 76 declare -path mapping; 622 | #X text 962 76 mapping is available in deken; 623 | #X obj 442 393 sen-scale 20 1200 0 127; 624 | #X obj 623 419 sen-scale 0 130 0 255; 625 | #X obj 652 447 sen-scale 0 130 0 255; 626 | #X obj 676 483 sen-scale 0 130 0 255; 627 | #X obj 831 394 sen-scale 20 1200 0 127; 628 | #X obj 1007 421 sen-scale 0 130 0 255; 629 | #X obj 1036 449 sen-scale 0 130 0 255; 630 | #X obj 1060 485 sen-scale 0 130 0 255; 631 | #X connect 0 0 60 1; 632 | #X connect 1 0 60 2; 633 | #X connect 2 0 60 3; 634 | #X connect 3 0 6 0; 635 | #X connect 3 0 76 0; 636 | #X connect 4 0 3 0; 637 | #X connect 5 0 3 1; 638 | #X connect 6 0 3 2; 639 | #X connect 7 0 60 0; 640 | #X connect 14 0 19 0; 641 | #X connect 15 0 18 0; 642 | #X connect 16 0 14 0; 643 | #X connect 16 0 15 0; 644 | #X connect 18 0 17 0; 645 | #X connect 20 0 22 0; 646 | #X connect 22 0 16 0; 647 | #X connect 30 0 3 2; 648 | #X connect 32 0 46 0; 649 | #X connect 33 0 46 0; 650 | #X connect 34 0 35 0; 651 | #X connect 36 0 32 0; 652 | #X connect 36 0 37 0; 653 | #X connect 37 0 46 0; 654 | #X connect 38 0 33 0; 655 | #X connect 39 0 45 0; 656 | #X connect 40 0 39 0; 657 | #X connect 41 0 39 0; 658 | #X connect 42 0 39 0; 659 | #X connect 43 0 39 0; 660 | #X connect 44 0 39 0; 661 | #X connect 45 1 48 0; 662 | #X connect 45 1 50 0; 663 | #X connect 45 1 54 0; 664 | #X connect 45 1 59 0; 665 | #X connect 46 1 34 0; 666 | #X connect 47 0 46 0; 667 | #X connect 48 0 49 0; 668 | #X connect 49 0 80 0; 669 | #X connect 49 1 81 0; 670 | #X connect 49 2 82 0; 671 | #X connect 50 0 79 0; 672 | #X connect 51 0 52 0; 673 | #X connect 52 0 55 0; 674 | #X connect 53 0 84 0; 675 | #X connect 53 1 85 0; 676 | #X connect 53 2 86 0; 677 | #X connect 54 0 53 0; 678 | #X connect 57 0 58 0; 679 | #X connect 58 0 56 0; 680 | #X connect 59 0 83 0; 681 | #X connect 75 0 45 0; 682 | #X connect 76 0 46 0; 683 | #X connect 79 0 51 0; 684 | #X connect 80 0 55 1; 685 | #X connect 81 0 55 2; 686 | #X connect 82 0 55 3; 687 | #X connect 83 0 57 0; 688 | #X connect 84 0 56 1; 689 | #X connect 85 0 56 2; 690 | #X connect 86 0 56 3; 691 | -------------------------------------------------------------------------------- /sensel_examples/SimpleSenselSound.pd: -------------------------------------------------------------------------------- 1 | #N canvas 249 104 1300 960 12; 2 | #X declare -path ./abs; 3 | #X declare -path freeverb; 4 | #X obj 88 108 sensel; 5 | #X msg 56 75 discover; 6 | #X msg 132 75 disconnect; 7 | #X obj 86 208 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 8 | #X obj 441 159 route 0 1 2 3 4 5 6 7 8 9 10 12 13 14 15; 9 | #X obj 84 301 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 10 | #X obj 81 392 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 11 | #X obj 83 490 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 12 | #X obj 83 582 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 13 | #X obj 576 218 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 14 | #X obj 574 311 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 15 | #X obj 571 402 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 16 | #X obj 573 500 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 17 | #X obj 573 592 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 18 | #X obj 92 137 route contacts; 19 | #X floatatom 90 167 5 0 0 0 - - -; 20 | #X obj 46 7 declare -path ./abs; 21 | #X obj 610 70 s scale; 22 | #X obj 719 91 s glide; 23 | #X obj 465 111 s quantize_tog; 24 | #X obj 464 85 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 25 | 1; 26 | #X floatatom 610 44 5 0 115 0 - - -; 27 | #N canvas 92 23 288 163 scales 0; 28 | #X obj 101 91 text define -k \$0-scales; 29 | #A set major 0 2 4 5 7 9 11 \; natural_minor 0 2 3 5 7 8 10 \; harmonic_minor 30 | 0 2 3 5 7 8 11 \; melodic_minor 0 2 3 5 7 9 11 \; major_blues 0 2 3 31 | 4 7 9 \; minor_blues 0 3 5 6 7 10 \; pentatonic_major 0 2 4 7 9 \; 32 | pentatonic_minor 0 3 5 7 10 \; pentatonic_neutral 0 2 5 7 10 \; pentatonic_blues 33 | 0 4 5 6 10 \; whole_tone 0 2 4 6 8 10 \; octatonic_diminished_h-w 0 34 | 1 3 4 6 7 9 10 \; octatonic_diminished_w-h 0 2 3 5 6 8 10 11 \; Rock'n'roll 35 | 0 3 4 5 7 9 10 \; major-minor 0 2 4 5 7 8 10 \; minor-major 0 2 3 5 36 | 7 9 11 \; hungarian_major 0 3 4 6 7 9 10 \; hungarian_minor 0 2 3 6 37 | 7 8 11 \; neapolitan_major 0 1 3 5 7 9 11 \; neapolitan_minor 0 1 3 38 | 5 7 8 11 \; ionian 0 2 4 5 7 9 11 \; dorian 0 2 3 5 7 9 10 \; phrygian 39 | 0 1 3 5 7 8 10 \; lydian 0 2 4 6 7 9 11 \; mixolydian 0 2 4 5 7 9 10 40 | \; aeolian 0 2 3 5 7 8 10 \; locrian 0 1 3 5 6 8 10 \; five-note_prometheus 41 | 0 2 4 6 10 \; half-diminished_bebop 0 1 3 5 6 7 8 11 \; chromatic 0 42 | 1 2 3 4 5 6 7 8 9 10 11 \; jazz_minor 0 2 3 5 7 9 11 \; jazz_minor_inverse 43 | 0 1 3 5 7 9 10 \; synthetix_mixture_#5 0 2 4 6 8 9 10 \; pentatonic_hard 44 | 0 2 5 7 9 \; pentatonic_major_#9_b7 0 3 4 7 10 \; pentatonic_major_b2 45 | 0 1 4 7 9 \; pentatonic_major_b2_b5 0 1 4 6 9 \; pentatonic_major_b2_b6 46 | 0 1 4 7 8 \; pentatonic_major_b3 0 1 3 6 9 \; pentatonic_major_b3_b6 47 | 0 2 3 7 8 \; pentatonic_major_b5 0 2 4 6 9 \; pentatonic_major_b6 0 48 | 2 4 7 8 \; pentatonic_major_b9 0 1 4 7 9 \; pentatonic_minor_7_b5 0 49 | 3 5 6 10 \; pentatonic_minor_major_6 0 3 5 7 9 \; pentatonic_minor_with 50 | added_6 0 3 5 7 9 10 \; pentatonic_whole_tone 0 4 6 8 10 \; primary_pentatonic 51 | 0 2 4 7 9 \; altered_diminished 0 1 3 4 6 8 9 \; altered_dominant 0 52 | 1 3 4 6 8 10 \; altered_lydian 0 2 4 6 8 9 11 \; altered_mixolydian 53 | 0 2 4 5 7 8 9 11 \; altered_pentatonic 0 1 5 7 9 \; anhemitonic_hexatonic 54 | 0 2 4 6 8 10 \; augmented_hexatonic 0 3 4 7 8 11 \; auxiliary_diminished 55 | 0 2 3 5 6 8 9 11 \; diminished_b9 0 1 3 5 6 8 9 \; diminished_blues 56 | 0 1 3 4 6 7 9 10 \; diminished_locrian 0 1 3 4 6 8 9 \; diminished_whole-tone 57 | 0 1 3 4 6 8 10 \; dominant_7th 0 2 5 7 9 10 \; dominant_diminished 58 | 0 1 3 4 6 7 9 10 \; double_harmonic_major 0 1 4 5 7 8 11 \; double_harmonic_minor 59 | 0 3 4 5 6 7 8 11 \; eight-note_diminished 0 2 3 5 6 8 9 11 \; enigmatic_scale 60 | 0 1 4 6 8 10 11 \; full_minor 0 2 3 5 7 8 9 10 11 \; half-diminished 61 | 0 2 3 5 6 8 10 \; half-whole 0 1 3 4 6 7 9 10 \; harmonic_and_neapolitan_minor_mixed 62 | 0 1 2 3 5 7 8 11 \; harmonic_major 0 2 4 5 7 8 11 \; inverted_augmented 63 | 0 1 4 5 8 9 \; jeth's_mode 0 2 3 5 6 9 11 \; leading_whole-tone 0 2 64 | 4 6 7 10 11 \; major-minor_mixed 0 2 3 4 5 7 8 9 10 11 \; major_augmented 65 | 0 2 4 5 8 9 11 \; major_inverse 0 1 3 5 7 8 10 \; melodic_major 0 1 66 | 4 5 7 8 10 \; melodic_minor_#11 0 1 3 6 7 9 11 \; minor_b5 0 2 3 5 67 | 6 8 10 \; minor_hexatonic 0 2 3 5 7 10 \; minor_pentatonic_with_leading_notes 68 | 0 2 3 4 5 6 7 9 10 11 \; natural_minor 0 2 3 5 7 8 10 \; nine-note_blues 69 | 0 2 3 4 5 6 7 9 10 \; nine-note_scale 0 2 3 4 6 7 8 9 11 \; overtone 70 | 0 2 3 5 7 9 11 \; pure_minor 0 2 3 5 7 8 10 \; pyramid_hexatonix 0 71 | 2 3 5 6 9 \; suspended_pentatonic 0 2 5 7 10 \; symmetrical_decatonic 72 | 0 1 2 4 5 6 7 8 10 11 \; symetrical_diminished 0 1 3 4 6 7 9 10 \; 73 | utility_minor 0 2 3 5 7 8 10 11 \; whole-half-step_scale 0 2 3 5 6 74 | 8 9 11 \; bebop_dominant 0 2 4 5 7 9 10 11 \; bebop_half-diminished 75 | 0 1 3 5 6 7 8 11 \; bebop_major 0 2 4 5 7 8 9 11 \; bebop_minor 0 2 76 | 3 4 5 7 9 10 \; black_key_pentatonic 0 2 5 7 9 \; blues_ennaetonic 77 | 0 2 3 4 5 6 7 9 10 \; blues_heptatonic 0 3 4 5 6 7 10 \; blues_hexatonic 78 | 0 3 5 6 7 10 \; blues_major 0 2 3 4 7 9 \; blues_minor 0 3 5 6 7 10 79 | \; blues_modified 0 2 3 5 6 7 10 \; blues_nine-note 0 2 3 4 5 6 7 9 80 | 10 \; blues_nonatonic 0 2 3 4 5 6 7 9 10 \; blues_pentatonic 0 3 5 81 | 6 10 \; blues_scale_I 0 3 5 6 10 \; blues_scale_II 0 2 3 4 5 6 7 9 82 | 10 \; blues_scale_III 0 2 3 5 6 7 9 10 \; blues_scale_IV 0 3 4 5 6 83 | 7 10 11 \; blues_scale_V 0 3 4 5 6 7 9 10 11 \; dominant_bebop 0 2 84 | 4 5 7 9 10 11 \; major_bebop_I 0 2 4 5 7 8 9 11 \; major_bebop_II 0 85 | 2 4 5 7 8 9 11 \; minor_bebop 0 2 4 5 7 8 9 11 \;; 86 | #X obj 18 36 text get \$0-scales; 87 | #X obj 18 4 inlet; 88 | #X obj 18 65 outlet; 89 | #X connect 1 0 3 0; 90 | #X connect 2 0 1 0; 91 | #X restore 611 92 pd scales; 92 | #X symbolatom 610 119 25 0 0 0 - - -; 93 | #X floatatom 719 58 5 5 5000 0 - - -; 94 | #N canvas 828 597 995 505 verb 0; 95 | #X obj 261 268 freeverb~; 96 | #X obj 264 52 inlet~; 97 | #X obj 324 53 inlet~; 98 | #X obj 203 411 outlet~; 99 | #X obj 276 417 outlet~; 100 | #X msg 475 247 wet \$1; 101 | #X msg 413 246 dry \$1; 102 | #X msg 811 255 bypass \$1; 103 | #X obj 422 106 vsl 20 100 0 100 0 0 empty empty empty 0 -9 0 10 -228856 104 | -1 -1 0 1; 105 | #X obj 452 107 vsl 20 100 0 100 0 0 empty empty empty 0 -9 0 10 -203904 106 | -1 -1 2970 1; 107 | #X obj 415 221 / 100; 108 | #X obj 476 222 / 100; 109 | #X obj 541 109 vsl 20 100 0 100 0 0 empty empty empty 0 -9 0 10 -228856 110 | -1 -1 1980 1; 111 | #X obj 572 109 vsl 20 100 0 100 0 0 empty empty empty 0 -9 0 10 -203904 112 | -1 -1 8910 1; 113 | #X obj 535 223 / 100; 114 | #X obj 580 224 / 100; 115 | #X msg 533 248 damping \$1; 116 | #X msg 610 250 roomsize \$1; 117 | #X obj 722 112 vsl 20 100 0 100 0 0 empty empty empty 0 -9 0 10 -228856 118 | -1 -1 9900 1; 119 | #X obj 721 228 / 100; 120 | #X msg 719 253 width \$1; 121 | #X obj 811 225 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 122 | 1; 123 | #X obj 319 360 *~; 124 | #X obj 185 362 *~; 125 | #X obj 147 236 cos~; 126 | #X obj 74 237 cos~; 127 | #X obj 73 168 line~; 128 | #X obj 75 205 +~ 0.75; 129 | #X obj 71 57 inlet; 130 | #X obj 261 362 *~; 131 | #X obj 145 358 *~; 132 | #X msg 422 80 0; 133 | #X msg 72 136 \$1 100; 134 | #X msg 460 80 30; 135 | #X msg 715 75 100; 136 | #X msg 581 80 90; 137 | #X msg 547 81 20; 138 | #X text 86 86 reverb wet/dry; 139 | #X text 85 107 by distance from center; 140 | #X obj 587 33 loadbang; 141 | #X text 218 360 dry; 142 | #X text 347 358 wet; 143 | #X text 413 306 darken the; 144 | #X text 413 321 reverb; 145 | #X obj 261 310 lop~ 4000; 146 | #X obj 337 310 lop~ 4000; 147 | #X connect 0 0 44 0; 148 | #X connect 0 1 45 0; 149 | #X connect 1 0 0 0; 150 | #X connect 1 0 30 0; 151 | #X connect 2 0 0 1; 152 | #X connect 2 0 23 0; 153 | #X connect 5 0 0 0; 154 | #X connect 6 0 0 0; 155 | #X connect 7 0 0 0; 156 | #X connect 8 0 10 0; 157 | #X connect 9 0 11 0; 158 | #X connect 10 0 6 0; 159 | #X connect 11 0 5 0; 160 | #X connect 12 0 14 0; 161 | #X connect 13 0 15 0; 162 | #X connect 14 0 16 0; 163 | #X connect 15 0 17 0; 164 | #X connect 16 0 0 0; 165 | #X connect 17 0 0 0; 166 | #X connect 18 0 19 0; 167 | #X connect 19 0 20 0; 168 | #X connect 20 0 0 0; 169 | #X connect 21 0 7 0; 170 | #X connect 22 0 4 0; 171 | #X connect 23 0 4 0; 172 | #X connect 24 0 30 1; 173 | #X connect 24 0 23 1; 174 | #X connect 25 0 22 1; 175 | #X connect 25 0 29 1; 176 | #X connect 26 0 24 0; 177 | #X connect 26 0 27 0; 178 | #X connect 27 0 25 0; 179 | #X connect 28 0 32 0; 180 | #X connect 29 0 3 0; 181 | #X connect 30 0 3 0; 182 | #X connect 31 0 8 0; 183 | #X connect 32 0 26 0; 184 | #X connect 33 0 9 0; 185 | #X connect 34 0 18 0; 186 | #X connect 35 0 13 0; 187 | #X connect 36 0 12 0; 188 | #X connect 39 0 31 0; 189 | #X connect 39 0 33 0; 190 | #X connect 39 0 36 0; 191 | #X connect 39 0 35 0; 192 | #X connect 39 0 34 0; 193 | #X connect 44 0 29 0; 194 | #X connect 45 0 22 0; 195 | #X restore 530 705 pd verb; 196 | #X obj 45 34 declare -path freeverb; 197 | #X obj 506 765 output2~; 198 | #X text 214 34 <- get from deken; 199 | #X text 81 636 The first five contacts use a 10ms slew; 200 | #X text 82 662 for the pitch. This "steps" the notes.; 201 | #X text 454 21 change the pitch quantization on all voices; 202 | #X text 771 737 patch by Peter Nyboer p@nbor.us peter@sensel.com; 203 | #X obj 319 249 basicvoice 1 1 10; 204 | #X obj 339 325 basicvoice 1 1 10; 205 | #X obj 337 416 basicvoice 1 1 10; 206 | #X obj 338 514 basicvoice 1 1 10; 207 | #X obj 339 608 basicvoice 1 1 10; 208 | #X obj 828 616 basicvoice 1 2 300; 209 | #X obj 828 525 basicvoice 1 2 300; 210 | #X obj 826 426 basicvoice 1 2 300; 211 | #X obj 829 335 basicvoice 1 2 300; 212 | #X obj 807 258 basicvoice 1 2 300; 213 | #X text 823 683 for the pitch. This portamentos the notes.; 214 | #X text 822 657 The second five contacts use a 300ms slew; 215 | #N canvas 814 439 848 830 distance-reverb 0; 216 | #X obj 409 188 expr sqrt( pow( ($f1-115) \, 2) + pow( ($f2-65) \, 2) 217 | ); 218 | #X obj 266 30 inlet; 219 | #X obj 363 348 sel 3; 220 | #X obj 367 379 t 0; 221 | #X obj 317 556 array set distances; 222 | #X msg 446 465 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 223 | #X obj 467 556 array define -yrange 0 120 -k distances 16; 224 | #A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 225 | #X obj 269 137 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 226 | #X obj 325 411 0; 227 | #X obj 270 170 t b f; 228 | #X obj 177 133 route 0; 229 | #X obj 180 174 t b; 230 | #X text 57 176 now calc the avg; 231 | #X obj 619 134 route contacts; 232 | #X obj 126 441 array sum distances; 233 | #X obj 125 480 / 1; 234 | #X floatatom 198 512 5 0 0 0 - - -; 235 | #X text 414 345 set to 0 on release; 236 | #X obj 444 437 loadbang; 237 | #X obj 108 511 clip 20 80; 238 | #X obj 104 666 outlet; 239 | #X obj 101 586 *; 240 | #X obj 102 625 * 0.25; 241 | #X obj 359 272 expr abs($f1 - 115); 242 | #X text 503 272 x distance from center; 243 | #X text 138 588 nonlinear \, so only adds a ton of reverb at edges 244 | ; 245 | #X text 595 210 not used: radius from center; 246 | #X obj 166 73 route contacts; 247 | #X obj 261 103 t list list; 248 | #X obj 104 542 sen-scale 20 100 0 1; 249 | #X connect 1 0 13 0; 250 | #X connect 1 0 27 0; 251 | #X connect 2 0 3 0; 252 | #X connect 3 0 8 1; 253 | #X connect 5 0 4 0; 254 | #X connect 7 0 9 0; 255 | #X connect 7 1 2 0; 256 | #X connect 7 16 0 0; 257 | #X connect 7 16 23 0; 258 | #X connect 7 17 0 1; 259 | #X connect 8 0 4 0; 260 | #X connect 9 0 8 0; 261 | #X connect 9 1 4 1; 262 | #X connect 10 0 11 0; 263 | #X connect 11 0 14 0; 264 | #X connect 13 0 15 1; 265 | #X connect 14 0 15 0; 266 | #X connect 15 0 16 0; 267 | #X connect 15 0 19 0; 268 | #X connect 18 0 5 0; 269 | #X connect 19 0 29 0; 270 | #X connect 21 0 22 0; 271 | #X connect 22 0 20 0; 272 | #X connect 23 0 8 1; 273 | #X connect 27 1 28 0; 274 | #X connect 28 0 10 0; 275 | #X connect 28 1 7 0; 276 | #X connect 29 0 21 0; 277 | #X connect 29 0 21 1; 278 | #X restore 33 702 pd distance-reverb; 279 | #X obj 26 146 s sensel; 280 | #X connect 0 0 14 0; 281 | #X connect 0 0 4 0; 282 | #X connect 0 0 45 0; 283 | #X connect 0 0 46 0; 284 | #X connect 1 0 0 0; 285 | #X connect 2 0 0 0; 286 | #X connect 3 15 33 0; 287 | #X connect 3 16 33 1; 288 | #X connect 3 17 33 2; 289 | #X connect 4 0 3 0; 290 | #X connect 4 1 5 0; 291 | #X connect 4 2 6 0; 292 | #X connect 4 3 7 0; 293 | #X connect 4 4 8 0; 294 | #X connect 4 5 9 0; 295 | #X connect 4 6 10 0; 296 | #X connect 4 7 11 0; 297 | #X connect 4 8 12 0; 298 | #X connect 4 9 13 0; 299 | #X connect 5 15 34 0; 300 | #X connect 5 16 34 1; 301 | #X connect 5 17 34 2; 302 | #X connect 6 15 35 0; 303 | #X connect 6 16 35 1; 304 | #X connect 6 17 35 2; 305 | #X connect 7 15 36 0; 306 | #X connect 7 16 36 1; 307 | #X connect 7 17 36 2; 308 | #X connect 8 15 37 0; 309 | #X connect 8 16 37 1; 310 | #X connect 8 17 37 2; 311 | #X connect 9 15 42 0; 312 | #X connect 9 16 42 1; 313 | #X connect 9 17 42 2; 314 | #X connect 10 15 41 0; 315 | #X connect 10 16 41 1; 316 | #X connect 10 17 41 2; 317 | #X connect 11 15 40 0; 318 | #X connect 11 16 40 1; 319 | #X connect 11 17 40 2; 320 | #X connect 12 15 39 0; 321 | #X connect 12 16 39 1; 322 | #X connect 12 17 39 2; 323 | #X connect 13 15 38 0; 324 | #X connect 13 16 38 1; 325 | #X connect 13 17 38 2; 326 | #X connect 14 0 15 0; 327 | #X connect 20 0 19 0; 328 | #X connect 21 0 17 0; 329 | #X connect 21 0 22 0; 330 | #X connect 22 0 23 0; 331 | #X connect 24 0 18 0; 332 | #X connect 25 0 27 0; 333 | #X connect 25 1 27 1; 334 | #X connect 33 0 25 1; 335 | #X connect 33 1 25 2; 336 | #X connect 34 0 25 1; 337 | #X connect 34 1 25 2; 338 | #X connect 35 0 25 1; 339 | #X connect 35 1 25 2; 340 | #X connect 36 0 25 1; 341 | #X connect 36 1 25 2; 342 | #X connect 37 0 25 1; 343 | #X connect 37 1 25 2; 344 | #X connect 38 0 25 1; 345 | #X connect 38 1 25 2; 346 | #X connect 39 0 25 1; 347 | #X connect 39 1 25 2; 348 | #X connect 40 0 25 1; 349 | #X connect 40 1 25 2; 350 | #X connect 41 0 25 1; 351 | #X connect 41 1 25 2; 352 | #X connect 42 0 25 1; 353 | #X connect 42 1 25 2; 354 | #X connect 45 0 25 0; 355 | -------------------------------------------------------------------------------- /sensel_examples/abs/basicvoice.pd: -------------------------------------------------------------------------------- 1 | #N canvas 918 77 717 600 12; 2 | #X obj 194 469 *~; 3 | #X obj 206 390 vcf~ 3; 4 | #X obj 238 469 *~; 5 | #X obj 77 217 / 240; 6 | #X obj 267 139 inlet; 7 | #X obj 79 179 inlet; 8 | #X text 71 152 X: pan; 9 | #X text 251 116 Y: freqency; 10 | #X obj 423 204 inlet; 11 | #X text 413 177 Z: filter freq; 12 | #X msg 135 219 120; 13 | #X obj 186 553 outlet~; 14 | #X obj 257 554 outlet~; 15 | #X obj 63 412 cos~; 16 | #X obj 136 412 cos~; 17 | #X obj 76 257 * 0.25; 18 | #X obj 414 306 line~; 19 | #X msg 414 282 \$1 10; 20 | #X obj 73 311 line~; 21 | #X msg 73 287 \$1 10; 22 | #X obj 136 381 +~ 0.75; 23 | #X obj 206 352 phasor~; 24 | #X obj 207 323 line~; 25 | #X msg 207 256 \$1 10; 26 | #X obj 94 8 loadbang; 27 | #N canvas 344 198 450 300 switch 0; 28 | #X obj 46 43 inlet; 29 | #X obj 155 63 inlet; 30 | #X obj 63 205 outlet; 31 | #X obj 154 209 outlet; 32 | #X obj 60 126 == 1; 33 | #X obj 49 90 t f f; 34 | #X obj 104 127 == 2; 35 | #X obj 59 161 spigot; 36 | #X obj 158 157 spigot; 37 | #X connect 0 0 5 0; 38 | #X connect 1 0 7 0; 39 | #X connect 1 0 8 0; 40 | #X connect 4 0 7 1; 41 | #X connect 5 0 4 0; 42 | #X connect 5 1 6 0; 43 | #X connect 6 0 8 1; 44 | #X connect 7 0 2 0; 45 | #X connect 8 0 3 0; 46 | #X restore 206 196 pd switch; 47 | #X obj 94 64 == 1; 48 | #X obj 94 92 + 1; 49 | #X obj 72 8 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 50 | ; 51 | #X obj 94 36 f \$1; 52 | #X text 136 36 1 as first arg means quantize; 53 | #X obj 364 8 loadbang; 54 | #X text 406 36 sec arg choose scale; 55 | #X obj 364 36 f \$2; 56 | #X obj 370 70 loadbang; 57 | #X text 390 118 third arg choose glide time; 58 | #X obj 370 98 f \$3; 59 | #N canvas 450 199 581 387 quantize 0; 60 | #X obj 125 181 mtof; 61 | #X obj 123 152 f2scale locrian 24; 62 | #X obj 124 217 pack 0 10; 63 | #X obj 108 28 inlet; 64 | #X obj 181 108 inlet; 65 | #X obj 123 249 outlet; 66 | #X obj 184 180 outlet; 67 | #X obj 274 153 inlet; 68 | #X text 56 306 https://forum.pdpatchrepo.info/topic/11775/creating-a-quantizer/6 69 | ; 70 | #X text 57 281 f2scale from user "weightless"; 71 | #X text 268 38 quantizes pitch to scales; 72 | #X obj 123 65 scale 0 130 2 43; 73 | #X connect 0 0 2 0; 74 | #X connect 1 0 0 0; 75 | #X connect 1 1 6 0; 76 | #X connect 2 0 5 0; 77 | #X connect 3 0 11 0; 78 | #X connect 4 0 1 1; 79 | #X connect 7 0 2 1; 80 | #X connect 11 0 1 0; 81 | #X restore 265 260 pd quantize; 82 | #X obj 454 72 r glide; 83 | #X obj 443 9 r scale; 84 | #X obj 166 8 r quantize_tog; 85 | #X obj 193 505 *~ 0.25; 86 | #X obj 259 507 *~ 0.25; 87 | #X text 319 504 attenuate; 88 | #X obj 206 227 sen-scale 0 130 40 2000; 89 | #X obj 414 236 sen-scale 0 1500 0 4000; 90 | #X connect 0 0 41 0; 91 | #X connect 1 1 2 0; 92 | #X connect 1 1 0 0; 93 | #X connect 2 0 42 0; 94 | #X connect 3 0 15 0; 95 | #X connect 4 0 25 1; 96 | #X connect 5 0 3 0; 97 | #X connect 8 0 45 0; 98 | #X connect 10 0 3 0; 99 | #X connect 13 0 0 1; 100 | #X connect 14 0 2 1; 101 | #X connect 15 0 19 0; 102 | #X connect 16 0 1 1; 103 | #X connect 17 0 16 0; 104 | #X connect 18 0 13 0; 105 | #X connect 18 0 20 0; 106 | #X connect 19 0 18 0; 107 | #X connect 20 0 14 0; 108 | #X connect 21 0 1 0; 109 | #X connect 22 0 21 0; 110 | #X connect 23 0 22 0; 111 | #X connect 24 0 29 0; 112 | #X connect 25 0 44 0; 113 | #X connect 25 1 37 0; 114 | #X connect 26 0 27 0; 115 | #X connect 27 0 25 0; 116 | #X connect 28 0 26 0; 117 | #X connect 29 0 26 0; 118 | #X connect 31 0 33 0; 119 | #X connect 33 0 37 1; 120 | #X connect 34 0 36 0; 121 | #X connect 36 0 37 2; 122 | #X connect 37 0 22 0; 123 | #X connect 38 0 36 0; 124 | #X connect 39 0 33 0; 125 | #X connect 40 0 26 0; 126 | #X connect 41 0 11 0; 127 | #X connect 42 0 12 0; 128 | #X connect 44 0 23 0; 129 | #X connect 45 0 17 0; 130 | #X coords 0 600 1 599 200 60 0; 131 | -------------------------------------------------------------------------------- /sensel_examples/abs/f2scale.pd: -------------------------------------------------------------------------------- 1 | #N canvas 572 23 521 710 10; 2 | #X obj 58 474 mod; 3 | #X obj 23 594 outlet; 4 | #X obj 23 534 +; 5 | #X obj 23 574 +; 6 | #X obj 364 684 text define -k \$0-scales; 7 | #A set major 0 2 4 5 7 9 11 \; natural_minor 0 2 3 5 7 8 10 \; harmonic_minor 8 | 0 2 3 5 7 8 11 \; melodic_minor 0 2 3 5 7 9 11 \; major_blues 0 2 3 9 | 4 7 9 \; minor_blues 0 3 5 6 7 10 \; pentatonic_major 0 2 4 7 9 \; 10 | pentatonic_minor 0 3 5 7 10 \; pentatonic_neutral 0 2 5 7 10 \; pentatonic_blues 11 | 0 4 5 6 10 \; whole_tone 0 2 4 6 8 10 \; octatonic_diminished_h-w 0 12 | 1 3 4 6 7 9 10 \; octatonic_diminished_w-h 0 2 3 5 6 8 10 11 \; Rock'n'roll 13 | 0 3 4 5 7 9 10 \; major-minor 0 2 4 5 7 8 10 \; minor-major 0 2 3 5 14 | 7 9 11 \; hungarian_major 0 3 4 6 7 9 10 \; hungarian_minor 0 2 3 6 15 | 7 8 11 \; neapolitan_major 0 1 3 5 7 9 11 \; neapolitan_minor 0 1 3 16 | 5 7 8 11 \; ionian 0 2 4 5 7 9 11 \; dorian 0 2 3 5 7 9 10 \; phrygian 17 | 0 1 3 5 7 8 10 \; lydian 0 2 4 6 7 9 11 \; mixolydian 0 2 4 5 7 9 10 18 | \; aeolian 0 2 3 5 7 8 10 \; locrian 0 1 3 5 6 8 10 \; five-note_prometheus 19 | 0 2 4 6 10 \; half-diminished_bebop 0 1 3 5 6 7 8 11 \; chromatic 0 20 | 1 2 3 4 5 6 7 8 9 10 11 \; jazz_minor 0 2 3 5 7 9 11 \; jazz_minor_inverse 21 | 0 1 3 5 7 9 10 \; synthetix_mixture_#5 0 2 4 6 8 9 10 \; pentatonic_hard 22 | 0 2 5 7 9 \; pentatonic_major_#9_b7 0 3 4 7 10 \; pentatonic_major_b2 23 | 0 1 4 7 9 \; pentatonic_major_b2_b5 0 1 4 6 9 \; pentatonic_major_b2_b6 24 | 0 1 4 7 8 \; pentatonic_major_b3 0 1 3 6 9 \; pentatonic_major_b3_b6 25 | 0 2 3 7 8 \; pentatonic_major_b5 0 2 4 6 9 \; pentatonic_major_b6 0 26 | 2 4 7 8 \; pentatonic_major_b9 0 1 4 7 9 \; pentatonic_minor_7_b5 0 27 | 3 5 6 10 \; pentatonic_minor_major_6 0 3 5 7 9 \; pentatonic_minor_with 28 | added_6 0 3 5 7 9 10 \; pentatonic_whole_tone 0 4 6 8 10 \; primary_pentatonic 29 | 0 2 4 7 9 \; altered_diminished 0 1 3 4 6 8 9 \; altered_dominant 0 30 | 1 3 4 6 8 10 \; altered_lydian 0 2 4 6 8 9 11 \; altered_mixolydian 31 | 0 2 4 5 7 8 9 11 \; altered_pentatonic 0 1 5 7 9 \; anhemitonic_hexatonic 32 | 0 2 4 6 8 10 \; augmented_hexatonic 0 3 4 7 8 11 \; auxiliary_diminished 33 | 0 2 3 5 6 8 9 11 \; diminished_b9 0 1 3 5 6 8 9 \; diminished_blues 34 | 0 1 3 4 6 7 9 10 \; diminished_locrian 0 1 3 4 6 8 9 \; diminished_whole-tone 35 | 0 1 3 4 6 8 10 \; dominant_7th 0 2 5 7 9 10 \; dominant_diminished 36 | 0 1 3 4 6 7 9 10 \; double_harmonic_major 0 1 4 5 7 8 11 \; double_harmonic_minor 37 | 0 3 4 5 6 7 8 11 \; eight-note_diminished 0 2 3 5 6 8 9 11 \; enigmatic_scale 38 | 0 1 4 6 8 10 11 \; full_minor 0 2 3 5 7 8 9 10 11 \; half-diminished 39 | 0 2 3 5 6 8 10 \; half-whole 0 1 3 4 6 7 9 10 \; harmonic_and_neapolitan_minor_mixed 40 | 0 1 2 3 5 7 8 11 \; harmonic_major 0 2 4 5 7 8 11 \; inverted_augmented 41 | 0 1 4 5 8 9 \; jeth's_mode 0 2 3 5 6 9 11 \; leading_whole-tone 0 2 42 | 4 6 7 10 11 \; major-minor_mixed 0 2 3 4 5 7 8 9 10 11 \; major_augmented 43 | 0 2 4 5 8 9 11 \; major_inverse 0 1 3 5 7 8 10 \; melodic_major 0 1 44 | 4 5 7 8 10 \; melodic_minor_#11 0 1 3 6 7 9 11 \; minor_b5 0 2 3 5 45 | 6 8 10 \; minor_hexatonic 0 2 3 5 7 10 \; minor_pentatonic_with_leading_notes 46 | 0 2 3 4 5 6 7 9 10 11 \; natural_minor 0 2 3 5 7 8 10 \; nine-note_blues 47 | 0 2 3 4 5 6 7 9 10 \; nine-note_scale 0 2 3 4 6 7 8 9 11 \; overtone 48 | 0 2 3 5 7 9 11 \; pure_minor 0 2 3 5 7 8 10 \; pyramid_hexatonix 0 49 | 2 3 5 6 9 \; suspended_pentatonic 0 2 5 7 10 \; symmetrical_decatonic 50 | 0 1 2 4 5 6 7 8 10 11 \; symetrical_diminished 0 1 3 4 6 7 9 10 \; 51 | utility_minor 0 2 3 5 7 8 10 11 \; whole-half-step_scale 0 2 3 5 6 52 | 8 9 11 \; bebop_dominant 0 2 4 5 7 9 10 11 \; bebop_half-diminished 53 | 0 1 3 5 6 7 8 11 \; bebop_major 0 2 4 5 7 8 9 11 \; bebop_minor 0 2 54 | 3 4 5 7 9 10 \; black_key_pentatonic 0 2 5 7 9 \; blues_ennaetonic 55 | 0 2 3 4 5 6 7 9 10 \; blues_heptatonic 0 3 4 5 6 7 10 \; blues_hexatonic 56 | 0 3 5 6 7 10 \; blues_major 0 2 3 4 7 9 \; blues_minor 0 3 5 6 7 10 57 | \; blues_modified 0 2 3 5 6 7 10 \; blues_nine-note 0 2 3 4 5 6 7 9 58 | 10 \; blues_nonatonic 0 2 3 4 5 6 7 9 10 \; blues_pentatonic 0 3 5 59 | 6 10 \; blues_scale_I 0 3 5 6 10 \; blues_scale_II 0 2 3 4 5 6 7 9 60 | 10 \; blues_scale_III 0 2 3 5 6 7 9 10 \; blues_scale_IV 0 3 4 5 6 61 | 7 10 11 \; blues_scale_V 0 3 4 5 6 7 9 10 11 \; dominant_bebop 0 2 62 | 4 5 7 9 10 11 \; major_bebop_I 0 2 4 5 7 8 9 11 \; major_bebop_II 0 63 | 2 4 5 7 8 9 11 \; minor_bebop 0 2 4 5 7 8 9 11 \;; 64 | #X obj 85 95 inlet; 65 | #X obj 85 275 print error; 66 | #X obj 242 95 inlet; 67 | #X obj 242 165 f \$2; 68 | #X obj 242 185 s \$0-transpose; 69 | #X obj 38 554 r \$0-transpose; 70 | #X obj 282 95 loadbang; 71 | #X obj 23 321 inlet; 72 | #X obj 23 361 i; 73 | #X obj 318 498 div; 74 | #X obj 318 518 * 12; 75 | #X obj 85 195 symbol \$1; 76 | #X obj 282 115 t b b; 77 | #X obj 85 235 sel -1; 78 | #X msg 85 255 scale not found!; 79 | #X obj 85 215 text search \$0-scales 0; 80 | #X text 229 214 search first field; 81 | #X text 33 22 quantize an incoming stream of floats to the pitch classes 82 | of a scale. Arguments: \$1 = scale name \$2 = transposition; 83 | #X text 22 302 floats; 84 | #X text 85 77 scale name or number; 85 | #X text 241 77 transposition in semitones; 86 | #X obj 280 594 outlet; 87 | #X text 280 612 scale name; 88 | #X obj 23 514 text get \$0-scales; 89 | #X obj 58 494 + 1; 90 | #X obj 23 381 t b f f; 91 | #X obj 23 474 f; 92 | #X obj 184 325 text get \$0-scales; 93 | #X obj 280 385 list split 1; 94 | #X obj 314 405 list length; 95 | #X obj 157 305 t f f; 96 | #X obj 241 365 route #; 97 | #X obj 184 345 route bang; 98 | #X obj 85 115 route symbol float; 99 | #X text 250 344 filter out bangs when index out of range; 100 | #X text 290 364 filter out comments; 101 | #X obj 314 425 t f f f; 102 | #X obj 353 564 outlet; 103 | #X text 353 582 scale length; 104 | #N canvas 0 23 285 207 print.scales 1; 105 | #X obj 53 41 inlet; 106 | #X obj 53 61 route print; 107 | #X msg 53 81 line 0 \, bang; 108 | #X obj 53 101 text sequence \$0-scales; 109 | #X obj 153 77 outlet; 110 | #X obj 53 141 print; 111 | #X obj 53 121 list trim; 112 | #X connect 0 0 1 0; 113 | #X connect 1 0 2 0; 114 | #X connect 1 1 4 0; 115 | #X connect 2 0 3 0; 116 | #X connect 3 0 6 0; 117 | #X connect 6 0 5 0; 118 | #X restore 23 341 pd print.scales; 119 | #X connect 0 0 29 0; 120 | #X connect 2 0 3 0; 121 | #X connect 3 0 1 0; 122 | #X connect 5 0 38 0; 123 | #X connect 7 0 8 0; 124 | #X connect 8 0 9 0; 125 | #X connect 10 0 3 1; 126 | #X connect 11 0 17 0; 127 | #X connect 12 0 44 0; 128 | #X connect 13 0 30 0; 129 | #X connect 14 0 15 0; 130 | #X connect 15 0 2 1; 131 | #X connect 16 0 20 0; 132 | #X connect 17 0 16 0; 133 | #X connect 17 1 8 0; 134 | #X connect 18 0 19 0; 135 | #X connect 18 1 35 0; 136 | #X connect 19 0 6 0; 137 | #X connect 20 0 18 0; 138 | #X connect 28 0 2 0; 139 | #X connect 29 0 28 1; 140 | #X connect 30 0 31 0; 141 | #X connect 30 1 0 0; 142 | #X connect 30 2 14 0; 143 | #X connect 31 0 28 0; 144 | #X connect 32 0 37 0; 145 | #X connect 33 0 26 0; 146 | #X connect 33 1 34 0; 147 | #X connect 34 0 41 0; 148 | #X connect 35 0 31 1; 149 | #X connect 35 1 32 0; 150 | #X connect 36 1 33 0; 151 | #X connect 37 1 36 0; 152 | #X connect 38 0 16 0; 153 | #X connect 38 1 35 0; 154 | #X connect 41 0 0 1; 155 | #X connect 41 1 14 1; 156 | #X connect 41 2 42 0; 157 | #X connect 44 0 13 0; 158 | -------------------------------------------------------------------------------- /sensel_examples/abs/output2~.pd: -------------------------------------------------------------------------------- 1 | #N canvas 0 23 615 578 12; 2 | #X obj 353 490 t b; 3 | #X obj 353 437 f; 4 | #X obj 353 515 f; 5 | #X msg 467 514 0; 6 | #X obj 353 467 moses 1; 7 | #X obj 467 486 t b f; 8 | #X obj 433 447 moses 1; 9 | #X obj 29 97 dbtorms; 10 | #X obj 85 170 inlet~; 11 | #X msg 299 310 \; pd dsp 1; 12 | #X obj 29 170 line~; 13 | #X obj 64 242 *~; 14 | #X obj 64 272 dac~; 15 | #X obj 29 127 pack 0 50; 16 | #X text 121 146 audio in; 17 | #X text 138 464 test if less than 1 -->; 18 | #X text 104 491 if true convert to bang -->; 19 | #X text 100 96 <-- convert from dB to linear units; 20 | #X floatatom 321 221 3 0 100 0 dB - -; 21 | #X obj 394 224 bng 15 250 50 0 empty empty mute -32 7 0 12 -262144 22 | -1 -1; 23 | #X text 118 126 <-- make a ramp to avoid clicks or zipper noise; 24 | #X obj 148 170 inlet~; 25 | #X obj 154 241 *~; 26 | #X text 373 378 MUTE logic:; 27 | #X obj 323 174 r \$0-master-lvl; 28 | #X obj 353 541 s \$0-master-lvl; 29 | #X obj 323 279 s \$0-master-out; 30 | #X obj 29 71 r \$0-master-out; 31 | #X obj 433 418 r \$0-master-out; 32 | #X text 60 10 Level control abstraction \, used in many of the Pd example 33 | patches. The "level" and "mute" controls show up on the parent \, calling 34 | patch.; 35 | #X text 66 517 previous nonzero master-lvl -->; 36 | #X text 138 421 recall previous; 37 | #X text 138 439 value of master-lvl -->; 38 | #X text 39 319 automatically start DSP -->; 39 | #X obj 85 192 hip~ 3; 40 | #X obj 147 192 hip~ 3; 41 | #X obj 394 201 bng 15 250 50 0 empty empty 100 -26 7 0 12 -262144 -1 42 | -1; 43 | #X msg 425 218 100; 44 | #X connect 0 0 2 0; 45 | #X connect 1 0 4 0; 46 | #X connect 2 0 25 0; 47 | #X connect 3 0 25 0; 48 | #X connect 4 0 0 0; 49 | #X connect 4 1 5 0; 50 | #X connect 5 0 3 0; 51 | #X connect 6 1 2 1; 52 | #X connect 7 0 13 0; 53 | #X connect 8 0 34 0; 54 | #X connect 10 0 22 0; 55 | #X connect 10 0 11 0; 56 | #X connect 11 0 12 0; 57 | #X connect 13 0 10 0; 58 | #X connect 18 0 9 0; 59 | #X connect 18 0 26 0; 60 | #X connect 19 0 1 0; 61 | #X connect 21 0 35 0; 62 | #X connect 22 0 12 1; 63 | #X connect 24 0 18 0; 64 | #X connect 27 0 7 0; 65 | #X connect 28 0 1 1; 66 | #X connect 28 0 6 0; 67 | #X connect 34 0 11 1; 68 | #X connect 35 0 22 1; 69 | #X connect 36 0 37 0; 70 | #X connect 37 0 18 0; 71 | #X coords 0 0 1 1 130 40 1 300 200; 72 | -------------------------------------------------------------------------------- /sensel_examples/abs/sen-scale.pd: -------------------------------------------------------------------------------- 1 | #N canvas 599 302 450 300 10; 2 | #X obj 55 56 inlet; 3 | #X obj 215 61 loadbang; 4 | #X obj 55 85 - \$1; 5 | #X obj 280 63 r __init; 6 | #X obj 209 92 pack \$1 \$2 \$3 \$4; 7 | #X obj 54 159 + \$3; 8 | #X obj 58 124 *; 9 | #X obj 51 202 outlet; 10 | #X obj 186 149 expr abs($f4-$f3)/abs($f2-$f1); 11 | #X text 130 206 it just has a unique name to avoid conflicts; 12 | #X text 129 224 with other abstractions called "scale."; 13 | #X text 130 188 nothing particularly special about this 'scale'; 14 | #X connect 0 0 2 0; 15 | #X connect 1 0 4 0; 16 | #X connect 2 0 6 0; 17 | #X connect 3 0 4 0; 18 | #X connect 4 0 8 0; 19 | #X connect 5 0 7 0; 20 | #X connect 6 0 5 0; 21 | #X connect 8 0 6 1; 22 | --------------------------------------------------------------------------------