From 0f2ae36f4442daa2d41d9314170d7685c1d639e5 Mon Sep 17 00:00:00 2001 From: Christian Frisson Date: Mon, 19 Jul 2021 11:39:53 -0400 Subject: [PATCH 1/8] Downgrade boost to 1.71.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8559780..1d88b82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ if(NOT MAPPER_LIB) message(FATAL_ERROR "libmapper library not found") endif() -find_package(Boost 1.73.0 REQUIRED) +find_package(Boost 1.71.0 REQUIRED) if(NOT Boost_FOUND) message(FATAL_ERROR "boost library not found") endif() From 433ba1b8af054370f73a35aa4bc9aeb88e031a5b Mon Sep 17 00:00:00 2001 From: mathiasbredholt Date: Mon, 22 Aug 2022 14:22:45 +0200 Subject: [PATCH 2/8] Removed queue and using mpr_sig_get_value instead of callback --- CMakeLists.txt | 6 ---- Mapper.cpp | 75 +++++++++++++++++++++++--------------------------- 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8559780..a60c7a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,12 +10,6 @@ if(NOT MAPPER_LIB) message(FATAL_ERROR "libmapper library not found") endif() -find_package(Boost 1.73.0 REQUIRED) -if(NOT Boost_FOUND) - message(FATAL_ERROR "boost library not found") -endif() -include_directories(Boost_INCLUDE_DIRS) - if (APPLE) set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}") endif() diff --git a/Mapper.cpp b/Mapper.cpp index 659fbbf..ec01d8f 100644 --- a/Mapper.cpp +++ b/Mapper.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -34,9 +33,6 @@ static mpr_dev dev; static std::atomic isReady; static std::thread* libmapperThreadHandle; -typedef std::function Task; -static boost::lockfree::queue taskQueue(128); - void libmapperThread() { // TODO(mb): Add option for specifying device name with Mapper.enable(name) dev = mpr_dev_new("SuperCollider", 0); @@ -47,19 +43,13 @@ void libmapperThread() { Print("Mapper: libmapper ready!\n"); while (dev) { mpr_dev_poll(dev, 1); - // Execute tasks - Task* f; - if (taskQueue.pop(f)) { - (*f)(); - delete f; - } } } struct MapperUnit : public Unit { int signalNameSize; char* signalName; - mpr_sig sig; + mpr_sig sig = nullptr; float sigMin = 0; float sigMax = 1; float val = 0; @@ -84,36 +74,20 @@ static void MapOut_next(MapOut* unit, int inNumSamples); static void MapperEnabler_Ctor(MapperEnabler* unit); static void MapperDisabler_Ctor(MapperDisabler* unit); -static void MapIn_signalUpdate(mpr_sig sig, mpr_sig_evt evt, mpr_id inst, - int length, mpr_type type, const void* value, - mpr_time time) { - MapIn* m = (MapIn*)mpr_obj_get_prop_as_ptr(sig, MPR_PROP_DATA, 0); - if (m) { - m->val = *reinterpret_cast(value); - } -} - static void MapperUnit_bindToSignal(MapperUnit* unit, mpr_dir direction) { // Search for existing output signal with same name mpr_list sigs = mpr_dev_get_sigs(dev, direction); sigs = mpr_list_filter(sigs, MPR_PROP_NAME, 0, 1, MPR_STR, unit->signalName, MPR_OP_EQ); - mpr_sig_handler* handler = direction == MPR_DIR_IN ? MapIn_signalUpdate : 0; - int flags = direction == MPR_DIR_IN ? MPR_SIG_UPDATE : 0; - if (sigs) { // Signal exists, bind unit to signal unit->sig = *sigs; - // Update pointer for signal update callback - mpr_obj_set_prop(unit->sig, MPR_PROP_DATA, 0, 1, MPR_PTR, unit, 0); - mpr_sig_set_cb(unit->sig, handler, flags); - // Update signal metadata if signal range has changed - // mpr_obj_set_prop(unit->sig, MPR_PROP_MIN, 0, 1, MPR_FLT, &unit->sigMin, - // 1); mpr_obj_set_prop(unit->sig, MPR_PROP_MAX, 0, 1, MPR_FLT, - // &unit->sigMax, 1); + mpr_obj_set_prop(unit->sig, MPR_PROP_MIN, 0, 1, MPR_FLT, &unit->sigMin, 1); + mpr_obj_set_prop(unit->sig, MPR_PROP_MAX, 0, 1, MPR_FLT, &unit->sigMax, 1); + mpr_obj_push(unit->sig); // Update maps containing signal // mpr_list maps = mpr_sig_get_maps(unit->sig, MPR_DIR_ANY); @@ -135,10 +109,9 @@ static void MapperUnit_bindToSignal(MapperUnit* unit, mpr_dir direction) { // } } else { // Signal doesn't exist, create new - Print("Creating signal '%s'\n", unit->signalName); + Print("Mapper: Creating signal '%s'\n", unit->signalName); unit->sig = mpr_sig_new(dev, direction, unit->signalName, 1, MPR_FLT, 0, - &unit->sigMin, &unit->sigMax, 0, handler, flags); - mpr_obj_set_prop(unit->sig, MPR_PROP_DATA, 0, 1, MPR_PTR, unit, 0); + &unit->sigMin, &unit->sigMax, 0, 0, 0); } } @@ -151,6 +124,7 @@ void MapIn_Ctor(MapIn* unit) { unit->sigMin = IN0(0); unit->sigMax = IN0(1); + // Set signal name unit->signalNameSize = IN0(2); const int signalNameAllocSize = (unit->signalNameSize + 1) * sizeof(char); @@ -167,9 +141,9 @@ void MapIn_Ctor(MapIn* unit) { } unit->signalName[unit->signalNameSize] = 0; + // Bind to signal if (dev) { - taskQueue.push( - new Task([unit]() { MapperUnit_bindToSignal(unit, MPR_DIR_IN); })); + MapperUnit_bindToSignal(unit, MPR_DIR_IN); } else { Print("MapIn: libmapper not enabled\n"); } @@ -181,7 +155,23 @@ void MapIn_Dtor(MapIn* unit) { RTFree(unit->mWorld, unit->signalName); } void MapIn_next(MapIn* unit, int inNumSamples) { float* out = OUT(0); - *out = unit->val; + + // Signal is not created yet + if (!unit->sig) { + *out = 0.f; + } + // Get signal value pointer + const float* val = + static_cast(mpr_sig_get_value(unit->sig, 0, 0)); + + // Signal doesn't have a value yet + if (!val) { + *out = 0.f; + return; + } + + // Set out value to signal value + *out = *val; } // MapOut @@ -190,6 +180,7 @@ void MapOut_Ctor(MapOut* unit) { unit->sigMin = IN0(1); unit->sigMax = IN0(2); + // Set signal name unit->signalNameSize = IN0(3); const int signalNameAllocSize = (unit->signalNameSize + 1) * sizeof(char); @@ -208,8 +199,7 @@ void MapOut_Ctor(MapOut* unit) { unit->signalName[unit->signalNameSize] = 0; if (isReady) { - taskQueue.push( - new Task([unit]() { MapperUnit_bindToSignal(unit, MPR_DIR_OUT); })); + MapperUnit_bindToSignal(unit, MPR_DIR_OUT); } else { Print("MapOut: libmapper not enabled\n"); SETCALC(Unit_next_nop); @@ -222,9 +212,14 @@ void MapOut_Ctor(MapOut* unit) { void MapOut_Dtor(MapOut* unit) { RTFree(unit->mWorld, unit->signalName); } void MapOut_next(MapOut* unit, int inNumSamples) { + // Signal is not ready yet + if (!unit->sig) { + return; + } + + // Set output signal value float val = IN0(0); - taskQueue.push( - new Task([=]() { mpr_sig_set_value(unit->sig, 0, 1, MPR_FLT, &val); })); + mpr_sig_set_value(unit->sig, 0, 1, MPR_FLT, &val); } // MapperEnabler From d8a704adddc27a250573c458ed2854a7cf4edc7c Mon Sep 17 00:00:00 2001 From: bboettcher31 Date: Thu, 22 Sep 2022 11:17:49 -0400 Subject: [PATCH 3/8] adds cmake compilation for windows machines --- CMakeLists.txt | 46 ++++++++++++++++++++++++++++++++++++++-------- README.md | 25 ++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a60c7a1..845b471 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,35 @@ get_filename_component(PROJECT ${FILENAME} NAME_WE) #automatically sets project message(STATUS "Project name is ${PROJECT}") project (${PROJECT}) -find_library(MAPPER_LIB mapper) -if(NOT MAPPER_LIB) - message(FATAL_ERROR "libmapper library not found") -endif() +if (WIN32) +# EDIT LIBMAPPER_DIR PATH BELOW BEFORE COMPILING FOR WINDOWS +set(LIBMAPPER_DIR "C:/Users/brady/Documents/Github/libmapper") +set(LIBMAPPER_BUILD_DIR "${LIBMAPPER_DIR}/build/Release") +set(LIBLO_DIR "${LIBMAPPER_DIR}/build/liblo/liblo-master") +set(LIBLO_BUILD_DIR "${LIBLO_DIR}/cmake/build/Release") +set(LIBLO_INCLUDES "${LIBLO_DIR}/cmake/build;${LIBLO_DIR}") + +set(Liblo_LIB ${LIBLO_BUILD_DIR}/liblo.lib) +set(Libmapper_LIB ${LIBMAPPER_BUILD_DIR}/libmapper.lib) +mark_as_advanced(Liblo_LIB) +mark_as_advanced(Libmapper_LIB) +add_definitions( + -D_WINSOCK_DEPRECATED_NO_WARNINGS + -DHAVE_WINSOCK2_H + -DNODEFAULTLIB +) +include_directories( + "${LIBLO_INCLUDES}" + "${LIBMAPPER_DIR}/include" +) +set(MAPPER_LIB ${Liblo_LIB} ${Libmapper_LIB}) +else() + find_library(MAPPER_LIB mapper) + if(NOT MAPPER_LIB) + message(FATAL_ERROR "libmapper library not found") + endif(NOT MAPPER_LIB) + include_directories(/usr/local/include) +endif(WIN32) if (APPLE) set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}") @@ -27,8 +52,6 @@ include_directories(${SC_PATH}/include/plugin_interface) include_directories(${SC_PATH}/include/common) include_directories(${SC_PATH}/common) -include_directories(/usr/local/include) - if (CMAKE_SYSTEM_NAME MATCHES "Linux|.*BSD|DragonFly") set(INSTALL_DESTINATION "lib/SuperCollider/plugins") if (QUARKS) @@ -120,18 +143,25 @@ endif() add_library(${PROJECT} MODULE ${FILENAME}) target_link_libraries(${PROJECT} ${MAPPER_LIB} ${Boost_libraries}) +if(WIN32) + set_target_properties(${PROJECT} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:MSVCRTD") + set_target_properties(${PROJECT} PROPERTIES LINK_FLAGS "/INCREMENTAL:NO") +endif(WIN32) + if(SUPERNOVA) add_library(${PROJECT}_supernova MODULE ${FILENAME}) target_link_libraries(${PROJECT}_supernova ${MAPPER_LIB}) set_property(TARGET ${PROJECT}_supernova PROPERTY COMPILE_DEFINITIONS SUPERNOVA) + if(NOT WIN32) install(TARGETS ${PROJECT}_supernova DESTINATION ${INSTALL_DESTINATION}/${PLUGIN_DIR}) + endif(NOT WIN32) endif() - +if(NOT WIN32) install(TARGETS ${PROJECT} DESTINATION ${INSTALL_DESTINATION}/${PLUGIN_DIR}) - install(DIRECTORY "sc/" DESTINATION "${INSTALL_DESTINATION_DISTRO}" PATTERN "*") +endif(NOT WIN32) \ No newline at end of file diff --git a/README.md b/README.md index 009d5d9..85f9de7 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,36 @@ A SuperCollider UGen for using libmapper * Build and install [libmapper](https://github.com/libmapper/libmapper) ### GNU/Linux ``` -git clone https://github.com/mathiasbredholt/MapperUGen.git +git clone https://github.com/libmapper/MapperUGen.git cd MapperUGen mkdir build && cd build cmake -DSUPERNOVA=ON .. cmake --build . --target install ``` -### macOS/Windows +### macOS ``` -git clone --recursive https://github.com/mathiasbredholt/MapperUGen.git +git clone --recursive https://github.com/libmapper/MapperUGen.git cd MapperUGen mkdir build && cd build cmake -DSUPERNOVA=ON .. cmake --build . --target install ``` + +### Windows +``` +git clone https://github.com/libmapper/MapperUGen.git +git config --global url."https://".insteadOf git:// +cd MapperUGen +mkdir build +cd build +cmake -DSUPERNOVA=ON .. +cmake --build . +``` + +#### Windows manual installation after compiling + +1. Evaluate `Platform.userExtensionDir` in supercollider and create a "Mapper" folder there +2. Copy everything inside the ./sc folder to the Mapper folder +3. Create a "plugins" folder in the Mapper directory +4. Copy the build outputs from ./build/Debug and your libmapper, liblo and zlib .dlls to the plugins folder +5. Reboot the supercollider interpreter \ No newline at end of file From 57dcb2e0360f46c07b809c104dbf19c7a60d8f5e Mon Sep 17 00:00:00 2001 From: bboettcher31 Date: Thu, 22 Sep 2022 11:24:52 -0400 Subject: [PATCH 4/8] adds a few more instructions to readme --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 85f9de7..c265167 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,17 @@ cmake --build . --target install ``` ### Windows + ``` git clone https://github.com/libmapper/MapperUGen.git -git config --global url."https://".insteadOf git:// cd MapperUGen +git config --global url."https://".insteadOf git:// +git submodule update --init --recursive +``` + +Now edit the CMakeLists.txt LIBMAPPER_DIR and LIBLO_DIR paths to match with your local libmapper paths. For libmapper installation help, consult the instructions [here](https://github.com/libmapper/libmapper/blob/main/doc/how_to_compile_and_run.md). Finally: + +``` mkdir build cd build cmake -DSUPERNOVA=ON .. From b9f2c2781111f0c1a7e376f5fd3b94ef54ced63b Mon Sep 17 00:00:00 2001 From: bboettcher31 Date: Thu, 22 Sep 2022 18:38:53 -0400 Subject: [PATCH 5/8] lets users name devices in Mapper.enable --- Mapper.cpp | 43 +++++++++++++++++++++-------- sc/HelpSource/Classes/Mapper.schelp | 3 +- sc/classes/Mapper.sc | 9 +++--- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Mapper.cpp b/Mapper.cpp index ec01d8f..0a0f6d7 100644 --- a/Mapper.cpp +++ b/Mapper.cpp @@ -33,9 +33,8 @@ static mpr_dev dev; static std::atomic isReady; static std::thread* libmapperThreadHandle; -void libmapperThread() { - // TODO(mb): Add option for specifying device name with Mapper.enable(name) - dev = mpr_dev_new("SuperCollider", 0); +void libmapperThread(char* deviceName) { + dev = mpr_dev_new(deviceName, 0); while (!mpr_dev_get_is_ready(dev)) { mpr_dev_poll(dev, 10); } @@ -46,7 +45,7 @@ void libmapperThread() { } } -struct MapperUnit : public Unit { +struct MapperSignalUnit : public Unit { int signalNameSize; char* signalName; mpr_sig sig = nullptr; @@ -55,9 +54,14 @@ struct MapperUnit : public Unit { float val = 0; }; -struct MapIn : public MapperUnit {}; -struct MapOut : public MapperUnit {}; -struct MapperEnabler : public Unit {}; +struct MapperDeviceUnit : public Unit { + int deviceNameSize; + char* deviceName; +}; + +struct MapIn : public MapperSignalUnit {}; +struct MapOut : public MapperSignalUnit {}; +struct MapperEnabler : public MapperDeviceUnit {}; struct MapperDisabler : public Unit {}; // Empty DSP function @@ -74,7 +78,7 @@ static void MapOut_next(MapOut* unit, int inNumSamples); static void MapperEnabler_Ctor(MapperEnabler* unit); static void MapperDisabler_Ctor(MapperDisabler* unit); -static void MapperUnit_bindToSignal(MapperUnit* unit, mpr_dir direction) { +static void MapperSignalUnit_bindToSignal(MapperSignalUnit* unit, mpr_dir direction) { // Search for existing output signal with same name mpr_list sigs = mpr_dev_get_sigs(dev, direction); sigs = mpr_list_filter(sigs, MPR_PROP_NAME, 0, 1, MPR_STR, unit->signalName, @@ -143,7 +147,7 @@ void MapIn_Ctor(MapIn* unit) { // Bind to signal if (dev) { - MapperUnit_bindToSignal(unit, MPR_DIR_IN); + MapperSignalUnit_bindToSignal(unit, MPR_DIR_IN); } else { Print("MapIn: libmapper not enabled\n"); } @@ -199,7 +203,7 @@ void MapOut_Ctor(MapOut* unit) { unit->signalName[unit->signalNameSize] = 0; if (isReady) { - MapperUnit_bindToSignal(unit, MPR_DIR_OUT); + MapperSignalUnit_bindToSignal(unit, MPR_DIR_OUT); } else { Print("MapOut: libmapper not enabled\n"); SETCALC(Unit_next_nop); @@ -226,8 +230,23 @@ void MapOut_next(MapOut* unit, int inNumSamples) { void MapperEnabler_Ctor(MapperEnabler* unit) { if (!dev) { - // dev = mpr_dev_new("SuperCollider", 0); - libmapperThreadHandle = new std::thread(libmapperThread); + // Set device name + unit->deviceNameSize = IN0(0); + const int deviceNameAllocSize = (unit->deviceNameSize + 1) * sizeof(char); + + void* chunk = RTAlloc(unit->mWorld, deviceNameAllocSize); + if (!chunk) { + Print("MapOut: RT memory allocation failed\n"); + SETCALC(Unit_next_nop); + return; + } + + unit->deviceName = reinterpret_cast(chunk); + for (int i = 0; i < unit->deviceNameSize; i++) { + unit->deviceName[i] = static_cast(IN0(1 + i)); + } + unit->deviceName[unit->deviceNameSize] = 0; + libmapperThreadHandle = new std::thread(libmapperThread, unit->deviceName); } else { Print("Mapper: libmapper already enabled.\n"); } diff --git a/sc/HelpSource/Classes/Mapper.schelp b/sc/HelpSource/Classes/Mapper.schelp index a8a2d29..53908ef 100644 --- a/sc/HelpSource/Classes/Mapper.schelp +++ b/sc/HelpSource/Classes/Mapper.schelp @@ -14,7 +14,8 @@ EXAMPLES:: code:: ( s.waitForBoot({ - Mapper.enable; + // Create and optionally name your libmapper device + Mapper.enable("MySuperColliderDevice"); }); ) diff --git a/sc/classes/Mapper.sc b/sc/classes/Mapper.sc index 32ca5ac..a2d7bb2 100644 --- a/sc/classes/Mapper.sc +++ b/sc/classes/Mapper.sc @@ -1,7 +1,7 @@ Mapper : UGen { - *enable { + *enable { arg name = "SuperCollider"; play { - MapperEnabler.kr; + MapperEnabler.kr(name); FreeSelf.kr(Impulse.kr(1)); } } @@ -30,8 +30,9 @@ MapOut : UGen { } MapperEnabler : UGen { - *kr { - this.new1('control'); + *kr { arg name; + var ascii = name.ascii; + this.new1('control', *[ascii.size].addAll(ascii)); ^0.0; } } From 8135f0c4e92679074f450d0dd8770a9f85b12b7c Mon Sep 17 00:00:00 2001 From: bboettcher31 Date: Thu, 22 Sep 2022 19:44:36 -0400 Subject: [PATCH 6/8] adds input signal bus function --- sc/HelpSource/Classes/Mapper.schelp | 12 +++++++++++- sc/classes/Mapper.sc | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/sc/HelpSource/Classes/Mapper.schelp b/sc/HelpSource/Classes/Mapper.schelp index a8a2d29..1f40b08 100644 --- a/sc/HelpSource/Classes/Mapper.schelp +++ b/sc/HelpSource/Classes/Mapper.schelp @@ -3,7 +3,7 @@ summary:: UGen for using libmapper with SuperCollider server categories:: UGens>Synth control DESCRIPTION:: -Creates a libmapper devices on the SuperCollider server. Input and output signals can be created with the MapIn and MapOut. The signals stay active util the libmapper device is destroyed either by rebooting the server or calling Mapper.disable. +Creates a libmapper devices on the SuperCollider server. Input and output signals can be created with the MapIn and MapOut, or a mappable Bus can be created for a signal with Mapper.makeInSignalBus(). The signals stay active util the libmapper device is destroyed either by rebooting the server or calling Mapper.disable. CLASSMETHODS:: private:: categories @@ -33,4 +33,14 @@ s.waitForBoot({ RLPF.ar(Saw.ar(50), MapIn.kr(\ffreq, 20, 20000), 0.2).dup * 0.2; }.play ) + +// Or, use makeInSignalBus to map a Bus directly to a Synth argument +( +SynthDef(\SineGenerator, { |out=0, freq=200, gain=0| + Out.ar( out, SinOsc.ar(freq, 0, gain) ) +}).add; +a = Synth(\SineGenerator); +var freqBus = Mapper.makeInSignalBus(s, "frequency", 10, 10000); +a.map(\freq, freqBus); +) :: diff --git a/sc/classes/Mapper.sc b/sc/classes/Mapper.sc index 32ca5ac..3f697a6 100644 --- a/sc/classes/Mapper.sc +++ b/sc/classes/Mapper.sc @@ -12,6 +12,13 @@ Mapper : UGen { FreeSelf.kr(Impulse.kr(1)); } } + + *makeInSignalBus { + arg server, name, min, max; + var bus = Bus.control(server); + {Out.kr(bus.index, MapIn.kr(name, min, max))}.play; + ^bus; + } } MapIn : UGen { From 8285346264a53c20093e154cb4503ad53de3b17c Mon Sep 17 00:00:00 2001 From: bboettcher31 Date: Sat, 24 Sep 2022 12:32:47 -0400 Subject: [PATCH 7/8] adds waitForBoot function and updates help --- Mapper.cpp | 27 ++++++++++++++++++ sc/HelpSource/Classes/Mapper.schelp | 44 ++++++++++++++--------------- sc/classes/Mapper.sc | 13 +++++++++ 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/Mapper.cpp b/Mapper.cpp index 0a0f6d7..ead4b15 100644 --- a/Mapper.cpp +++ b/Mapper.cpp @@ -59,10 +59,15 @@ struct MapperDeviceUnit : public Unit { char* deviceName; }; +struct MapperIsReadyUnit : public Unit { + bool shouldSendNeg = true; // Send -1 the first frame to trigger free when ready +}; + struct MapIn : public MapperSignalUnit {}; struct MapOut : public MapperSignalUnit {}; struct MapperEnabler : public MapperDeviceUnit {}; struct MapperDisabler : public Unit {}; +struct MapperIsReady : public MapperIsReadyUnit {}; // Empty DSP function static void Unit_next_nop(Unit* unit, int inNumSamples) {} @@ -78,6 +83,10 @@ static void MapOut_next(MapOut* unit, int inNumSamples); static void MapperEnabler_Ctor(MapperEnabler* unit); static void MapperDisabler_Ctor(MapperDisabler* unit); +static void MapperIsReady_Ctor(MapperIsReady* unit); +static void MapperIsReady_Dtor(MapperIsReady* unit); +static void MapperIsReady_next(MapperIsReady* unit, int inNumSamples); + static void MapperSignalUnit_bindToSignal(MapperSignalUnit* unit, mpr_dir direction) { // Search for existing output signal with same name mpr_list sigs = mpr_dev_get_sigs(dev, direction); @@ -264,10 +273,28 @@ void MapperDisabler_Ctor(MapperDisabler* unit) { SETCALC(Unit_next_nop); } +// MapperIsReady + +void MapperIsReady_Ctor(MapperIsReady* unit) { + SETCALC(MapperIsReady_next); + MapperIsReady_next(unit, 1); +} +void MapperIsReady_Dtor(MapperIsReady* unit) {} +void MapperIsReady_next(MapperIsReady* unit, int inNumSamples) { + float* out = OUT(0); + if (unit->shouldSendNeg) { + *out = -1.0f; + unit->shouldSendNeg = false; // Sent -1 once, send regular value now + } else { + *out = (isReady) ? 1.0f : -1.0f; + } +} + PluginLoad(MapperUGens) { ft = inTable; DefineDtorUnit(MapIn); DefineDtorUnit(MapOut); DefineSimpleUnit(MapperEnabler); DefineSimpleUnit(MapperDisabler); + DefineDtorUnit(MapperIsReady); } diff --git a/sc/HelpSource/Classes/Mapper.schelp b/sc/HelpSource/Classes/Mapper.schelp index 4ec0744..893efdb 100644 --- a/sc/HelpSource/Classes/Mapper.schelp +++ b/sc/HelpSource/Classes/Mapper.schelp @@ -3,7 +3,7 @@ summary:: UGen for using libmapper with SuperCollider server categories:: UGens>Synth control DESCRIPTION:: -Creates a libmapper devices on the SuperCollider server. Input and output signals can be created with the MapIn and MapOut, or a mappable Bus can be created for a signal with Mapper.makeInSignalBus(). The signals stay active util the libmapper device is destroyed either by rebooting the server or calling Mapper.disable. +Creates a libmapper devices on the SuperCollider server. Input and output signals can be created with the MapIn and MapOut, or a mappable Bus can be created for an input signal with Mapper.makeInSignalBus(). The signals stay active util the libmapper device is destroyed either by rebooting the server or calling Mapper.disable. CLASSMETHODS:: private:: categories @@ -12,36 +12,36 @@ METHOD:: enable, disable EXAMPLES:: code:: +( +// Just a rudimentary SynthDef we'll use below +SynthDef(\SineGenerator, { |out=0, freq=200, gain=0| + Out.ar( out, SinOsc.ar(freq, 0, gain) ) + }).add; +) + ( s.waitForBoot({ // Create and optionally name your libmapper device Mapper.enable("MySuperColliderDevice"); -}); -) -// wait for libmapper ready message + // Wait for libmapper to fully boot and create/map signals + Mapper.waitForBoot({ + // Send output signal from SuperCollider + { MapOut.kr(SinOsc.kr(1), \sine, -1, 1) }.play; -// Output signal -( -{ - MapOut.kr(SinOsc.kr(1), \sine, -1, 1); -}.play; -) + // Receive input signal to SuperCollider + { RLPF.ar(Saw.ar(50), MapIn.kr(\ffreq, 20, 20000), 0.2).dup * 0.2 }.play; -// Input signal -( -{ - RLPF.ar(Saw.ar(50), MapIn.kr(\ffreq, 20, 20000), 0.2).dup * 0.2; -}.play + // Or, use makeInSignalBus to map an input signal directly to a Synth argument using a Bus + a = Synth(\SineGenerator); + ~freqBus = Mapper.makeInSignalBus(s, "ffreq2", 10, 10000); + a.map(\freq, ~freqBus); + }); +}); ) -// Or, use makeInSignalBus to map a Bus directly to a Synth argument ( -SynthDef(\SineGenerator, { |out=0, freq=200, gain=0| - Out.ar( out, SinOsc.ar(freq, 0, gain) ) -}).add; -a = Synth(\SineGenerator); -var freqBus = Mapper.makeInSignalBus(s, "frequency", 10, 10000); -a.map(\freq, freqBus); +// Disable when we're done +Mapper.disable; ) :: diff --git a/sc/classes/Mapper.sc b/sc/classes/Mapper.sc index 75118f2..9776d0c 100644 --- a/sc/classes/Mapper.sc +++ b/sc/classes/Mapper.sc @@ -13,6 +13,13 @@ Mapper : UGen { } } + *waitForBoot { arg onComplete; + fork { + { FreeSelf.kr(MapperIsReady.kr) }.play.waitForFree; + onComplete.value; + }; + } + *makeInSignalBus { arg server, name, min, max; var bus = Bus.control(server); @@ -50,3 +57,9 @@ MapperDisabler : UGen { ^0.0; } } + +MapperIsReady : UGen { + *kr { + ^this.new1('control'); + } +} From 901000795ed2e24cd151e2d9ca40e5ca9c49ede7 Mon Sep 17 00:00:00 2001 From: bboettcher31 Date: Mon, 14 Nov 2022 18:15:00 -0500 Subject: [PATCH 8/8] add recursive clone bug note --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c265167..a02a8e5 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ A SuperCollider UGen for using libmapper ## Compile from source * Build and install [libmapper](https://github.com/libmapper/libmapper) + +* Note: when cloning supercollider below, if the cloning hangs just execute `git config --global url."https://".insteadOf git://` to fix the issue. It's a known issue with older versions of the supercollider sdk. + ### GNU/Linux ``` git clone https://github.com/libmapper/MapperUGen.git