2222#include < mapper/mapper.h>
2323
2424#include < atomic>
25- #include < boost/lockfree/queue.hpp>
2625#include < functional>
2726#include < queue>
2827#include < thread>
@@ -34,41 +33,41 @@ static mpr_dev dev;
3433static std::atomic<bool > isReady;
3534static std::thread* libmapperThreadHandle;
3635
37- typedef std::function<void ()> Task;
38- static boost::lockfree::queue<Task*> taskQueue (128 );
39-
40- void libmapperThread () {
41- // TODO(mb): Add option for specifying device name with Mapper.enable(name)
42- dev = mpr_dev_new (" SuperCollider" , 0 );
36+ void libmapperThread (char * deviceName) {
37+ dev = mpr_dev_new (deviceName, 0 );
4338 while (!mpr_dev_get_is_ready (dev)) {
4439 mpr_dev_poll (dev, 10 );
4540 }
4641 isReady = true ;
4742 Print (" Mapper: libmapper ready!\n " );
4843 while (dev) {
4944 mpr_dev_poll (dev, 1 );
50- // Execute tasks
51- Task* f;
52- if (taskQueue.pop (f)) {
53- (*f)();
54- delete f;
55- }
5645 }
5746}
5847
59- struct MapperUnit : public Unit {
48+ struct MapperSignalUnit : public Unit {
6049 int signalNameSize;
6150 char * signalName;
62- mpr_sig sig;
51+ mpr_sig sig = nullptr ;
6352 float sigMin = 0 ;
6453 float sigMax = 1 ;
6554 float val = 0 ;
6655};
6756
68- struct MapIn : public MapperUnit {};
69- struct MapOut : public MapperUnit {};
70- struct MapperEnabler : public Unit {};
57+ struct MapperDeviceUnit : public Unit {
58+ int deviceNameSize;
59+ char * deviceName;
60+ };
61+
62+ struct MapperIsReadyUnit : public Unit {
63+ bool shouldSendNeg = true ; // Send -1 the first frame to trigger free when ready
64+ };
65+
66+ struct MapIn : public MapperSignalUnit {};
67+ struct MapOut : public MapperSignalUnit {};
68+ struct MapperEnabler : public MapperDeviceUnit {};
7169struct MapperDisabler : public Unit {};
70+ struct MapperIsReady : public MapperIsReadyUnit {};
7271
7372// Empty DSP function
7473static void Unit_next_nop (Unit* unit, int inNumSamples) {}
@@ -84,36 +83,24 @@ static void MapOut_next(MapOut* unit, int inNumSamples);
8483static void MapperEnabler_Ctor (MapperEnabler* unit);
8584static void MapperDisabler_Ctor (MapperDisabler* unit);
8685
87- static void MapIn_signalUpdate (mpr_sig sig, mpr_sig_evt evt, mpr_id inst,
88- int length, mpr_type type, const void * value,
89- mpr_time time) {
90- MapIn* m = (MapIn*)mpr_obj_get_prop_as_ptr (sig, MPR_PROP_DATA , 0 );
91- if (m) {
92- m->val = *reinterpret_cast <const float *>(value);
93- }
94- }
86+ static void MapperIsReady_Ctor (MapperIsReady* unit);
87+ static void MapperIsReady_Dtor (MapperIsReady* unit);
88+ static void MapperIsReady_next (MapperIsReady* unit, int inNumSamples);
9589
96- static void MapperUnit_bindToSignal (MapperUnit * unit, mpr_dir direction) {
90+ static void MapperSignalUnit_bindToSignal (MapperSignalUnit * unit, mpr_dir direction) {
9791 // Search for existing output signal with same name
9892 mpr_list sigs = mpr_dev_get_sigs (dev, direction);
9993 sigs = mpr_list_filter (sigs, MPR_PROP_NAME , 0 , 1 , MPR_STR , unit->signalName ,
10094 MPR_OP_EQ );
10195
102- mpr_sig_handler* handler = direction == MPR_DIR_IN ? MapIn_signalUpdate : 0 ;
103- int flags = direction == MPR_DIR_IN ? MPR_SIG_UPDATE : 0 ;
104-
10596 if (sigs) {
10697 // Signal exists, bind unit to signal
10798 unit->sig = *sigs;
10899
109- // Update pointer for signal update callback
110- mpr_obj_set_prop (unit->sig , MPR_PROP_DATA , 0 , 1 , MPR_PTR , unit, 0 );
111- mpr_sig_set_cb (unit->sig , handler, flags);
112-
113100 // Update signal metadata if signal range has changed
114- // mpr_obj_set_prop(unit->sig, MPR_PROP_MIN, 0, 1, MPR_FLT, &unit->sigMin,
115- // 1); mpr_obj_set_prop(unit->sig, MPR_PROP_MAX, 0, 1, MPR_FLT,
116- // & unit->sigMax, 1 );
101+ mpr_obj_set_prop (unit->sig , MPR_PROP_MIN , 0 , 1 , MPR_FLT , &unit->sigMin , 1 );
102+ mpr_obj_set_prop (unit->sig , MPR_PROP_MAX , 0 , 1 , MPR_FLT , &unit-> sigMax , 1 );
103+ mpr_obj_push ( unit->sig );
117104
118105 // Update maps containing signal
119106 // mpr_list maps = mpr_sig_get_maps(unit->sig, MPR_DIR_ANY);
@@ -135,10 +122,9 @@ static void MapperUnit_bindToSignal(MapperUnit* unit, mpr_dir direction) {
135122 // }
136123 } else {
137124 // Signal doesn't exist, create new
138- Print (" Creating signal '%s'\n " , unit->signalName );
125+ Print (" Mapper: Creating signal '%s'\n " , unit->signalName );
139126 unit->sig = mpr_sig_new (dev, direction, unit->signalName , 1 , MPR_FLT , 0 ,
140- &unit->sigMin , &unit->sigMax , 0 , handler, flags);
141- mpr_obj_set_prop (unit->sig , MPR_PROP_DATA , 0 , 1 , MPR_PTR , unit, 0 );
127+ &unit->sigMin , &unit->sigMax , 0 , 0 , 0 );
142128 }
143129}
144130
@@ -151,6 +137,7 @@ void MapIn_Ctor(MapIn* unit) {
151137 unit->sigMin = IN0 (0 );
152138 unit->sigMax = IN0 (1 );
153139
140+ // Set signal name
154141 unit->signalNameSize = IN0 (2 );
155142 const int signalNameAllocSize = (unit->signalNameSize + 1 ) * sizeof (char );
156143
@@ -167,9 +154,9 @@ void MapIn_Ctor(MapIn* unit) {
167154 }
168155 unit->signalName [unit->signalNameSize ] = 0 ;
169156
157+ // Bind to signal
170158 if (dev) {
171- taskQueue.push (
172- new Task ([unit]() { MapperUnit_bindToSignal (unit, MPR_DIR_IN ); }));
159+ MapperSignalUnit_bindToSignal (unit, MPR_DIR_IN );
173160 } else {
174161 Print (" MapIn: libmapper not enabled\n " );
175162 }
@@ -181,7 +168,23 @@ void MapIn_Dtor(MapIn* unit) { RTFree(unit->mWorld, unit->signalName); }
181168
182169void MapIn_next (MapIn* unit, int inNumSamples) {
183170 float * out = OUT (0 );
184- *out = unit->val ;
171+
172+ // Signal is not created yet
173+ if (!unit->sig ) {
174+ *out = 0 .f ;
175+ }
176+ // Get signal value pointer
177+ const float * val =
178+ static_cast <const float *>(mpr_sig_get_value (unit->sig , 0 , 0 ));
179+
180+ // Signal doesn't have a value yet
181+ if (!val) {
182+ *out = 0 .f ;
183+ return ;
184+ }
185+
186+ // Set out value to signal value
187+ *out = *val;
185188}
186189
187190// MapOut
@@ -190,6 +193,7 @@ void MapOut_Ctor(MapOut* unit) {
190193 unit->sigMin = IN0 (1 );
191194 unit->sigMax = IN0 (2 );
192195
196+ // Set signal name
193197 unit->signalNameSize = IN0 (3 );
194198 const int signalNameAllocSize = (unit->signalNameSize + 1 ) * sizeof (char );
195199
@@ -208,8 +212,7 @@ void MapOut_Ctor(MapOut* unit) {
208212 unit->signalName [unit->signalNameSize ] = 0 ;
209213
210214 if (isReady) {
211- taskQueue.push (
212- new Task ([unit]() { MapperUnit_bindToSignal (unit, MPR_DIR_OUT ); }));
215+ MapperSignalUnit_bindToSignal (unit, MPR_DIR_OUT );
213216 } else {
214217 Print (" MapOut: libmapper not enabled\n " );
215218 SETCALC (Unit_next_nop);
@@ -222,17 +225,37 @@ void MapOut_Ctor(MapOut* unit) {
222225void MapOut_Dtor (MapOut* unit) { RTFree (unit->mWorld , unit->signalName ); }
223226
224227void MapOut_next (MapOut* unit, int inNumSamples) {
228+ // Signal is not ready yet
229+ if (!unit->sig ) {
230+ return ;
231+ }
232+
233+ // Set output signal value
225234 float val = IN0 (0 );
226- taskQueue.push (
227- new Task ([=]() { mpr_sig_set_value (unit->sig , 0 , 1 , MPR_FLT , &val); }));
235+ mpr_sig_set_value (unit->sig , 0 , 1 , MPR_FLT , &val);
228236}
229237
230238// MapperEnabler
231239
232240void MapperEnabler_Ctor (MapperEnabler* unit) {
233241 if (!dev) {
234- // dev = mpr_dev_new("SuperCollider", 0);
235- libmapperThreadHandle = new std::thread (libmapperThread);
242+ // Set device name
243+ unit->deviceNameSize = IN0 (0 );
244+ const int deviceNameAllocSize = (unit->deviceNameSize + 1 ) * sizeof (char );
245+
246+ void * chunk = RTAlloc (unit->mWorld , deviceNameAllocSize);
247+ if (!chunk) {
248+ Print (" MapOut: RT memory allocation failed\n " );
249+ SETCALC (Unit_next_nop);
250+ return ;
251+ }
252+
253+ unit->deviceName = reinterpret_cast <char *>(chunk);
254+ for (int i = 0 ; i < unit->deviceNameSize ; i++) {
255+ unit->deviceName [i] = static_cast <char >(IN0 (1 + i));
256+ }
257+ unit->deviceName [unit->deviceNameSize ] = 0 ;
258+ libmapperThreadHandle = new std::thread (libmapperThread, unit->deviceName );
236259 } else {
237260 Print (" Mapper: libmapper already enabled.\n " );
238261 }
@@ -250,10 +273,28 @@ void MapperDisabler_Ctor(MapperDisabler* unit) {
250273 SETCALC (Unit_next_nop);
251274}
252275
276+ // MapperIsReady
277+
278+ void MapperIsReady_Ctor (MapperIsReady* unit) {
279+ SETCALC (MapperIsReady_next);
280+ MapperIsReady_next (unit, 1 );
281+ }
282+ void MapperIsReady_Dtor (MapperIsReady* unit) {}
283+ void MapperIsReady_next (MapperIsReady* unit, int inNumSamples) {
284+ float * out = OUT (0 );
285+ if (unit->shouldSendNeg ) {
286+ *out = -1 .0f ;
287+ unit->shouldSendNeg = false ; // Sent -1 once, send regular value now
288+ } else {
289+ *out = (isReady) ? 1 .0f : -1 .0f ;
290+ }
291+ }
292+
253293PluginLoad (MapperUGens) {
254294 ft = inTable;
255295 DefineDtorUnit (MapIn);
256296 DefineDtorUnit (MapOut);
257297 DefineSimpleUnit (MapperEnabler);
258298 DefineSimpleUnit (MapperDisabler);
299+ DefineDtorUnit (MapperIsReady);
259300}
0 commit comments