11noindex: true
22desc: MIDI Multi Channel Pre-Delay Live Flagger
3- version: 0.7
3+ version: 0.8
44author: Ben 'Talagan' Babut
55
6- options:gmem=MIDIMultiChannelPredelay
6+ slider1:introduced_lag=0<0,1000>Introduced Lag
7+ slider2:queue_size=0<0,1000>Queue Size
78
9+ options:gmem=MIDIMultiChannelPredelay
810
911// This plugin flags live events in GMEM so that another plugin in the normal FX Chain
1012// can check if incoming MIDI Events are live events or not.
@@ -32,12 +34,14 @@ g_last_play_state = play_state;
3234
3335MAGIC_NUMBER = 0xF5AF5BB0;
3436
35- EVENT_START_ADDR = 0 ;
37+ EVENT_START_ADDR = 1 ;
3638STORED_EVENT_SIZE = 6;
3739
3840g_block_num = 0;
3941b_now = 0;
40- b_cursor = 0;
42+
43+ introduced_lag = 0;
44+ queue_size = 0;
4145
4246@block
4347
@@ -47,6 +51,38 @@ function getUID()
4751 get_host_placement(cp, flags);
4852);
4953
54+ function gmem_p()
55+ local(res)
56+ (
57+ res = atomic_setifequal(gmem[0], 0, 1);
58+ (res == 0);
59+ );
60+
61+ function gmem_v()
62+ (
63+ atomic_set(gmem[0],0);
64+ );
65+
66+ function gmem_wait(timeout)
67+ local(t1, t2, elapsed)
68+ (
69+ (timeout <=0)?(timeout = 1.0);
70+
71+ t1 = time_precise();
72+ elapsed = 0;
73+ should_loop = 1;
74+
75+ while(!gmem_p() && should_loop == 1)
76+ (
77+ t2 = time_precise();
78+ elapsed = (t2 - t1);
79+ should_loop = (elapsed < timeout);
80+ );
81+
82+ introduced_lag += elapsed;
83+ should_loop;
84+ );
85+
5086function slotIsReusable(slot_address)
5187 local(mg, st, id, ts, bn)
5288(
@@ -60,19 +96,35 @@ function slotIsReusable(slot_address)
6096 (ts + 0.1 < b_now); // Too old, obsolete, probably a leftover of another plugin
6197);
6298
99+
100+ function findFirstReusableSlot()
101+ local(c)
102+ (
103+ c = EVENT_START_ADDR;
104+ while(!slotIsReusable(c)) (
105+ c += STORED_EVENT_SIZE;
106+ );
107+ c;
108+ );
109+
63110function cleanupMemory()
64- local(last)
111+ local(last, c, bn, id )
65112(
66- last = b_cursor;
113+ gmem_wait(0.01);
114+
115+ c = EVENT_START_ADDR;
116+ last = EVENT_START_ADDR;
67117
68118 // Advance till we meet something which is not a slot
69- while(gmem[b_cursor ] == MAGIC_NUMBER) (
70- last = b_cursor ;
71- b_cursor += STORED_EVENT_SIZE;
119+ while(gmem[c ] == MAGIC_NUMBER) (
120+ last = c ;
121+ c += STORED_EVENT_SIZE;
72122 );
73123
124+ queue_size = c - EVENT_START_ADDR;
125+
74126 // Now rewind-erase the end of the queue
75- while(slotIsReusable(last) && (last >= 0 )) (
127+ while(slotIsReusable(last) && (last >= EVENT_START_ADDR )) (
76128 gmem[last] = 0;
77129 gmem[last+1] = 0;
78130 gmem[last+2] = 0;
@@ -83,7 +135,7 @@ function cleanupMemory()
83135 );
84136
85137 // Only invalidate events in the rest of the queue if they belong to us and are not valid anymore.
86- while(last >= 0 ) (
138+ while(last >= EVENT_START_ADDR ) (
87139
88140 id = gmem[last+1];
89141 bn = gmem[last+3];
@@ -93,23 +145,17 @@ function cleanupMemory()
93145 );
94146 last -= STORED_EVENT_SIZE;
95147 );
96- );
97-
98- function findNextFreeSlotAddress()
99- local()
100- (
101- while(!slotIsReusable(b_cursor)) (
102- b_cursor += STORED_EVENT_SIZE;
103- );
104148
105- b_cursor ;
149+ gmem_v() ;
106150);
107151
108152function flagEvent(offset, msg1, msg2, msg3)
109153 local(slot_address)
110154(
155+ gmem_wait(0.01);
156+
111157 // Calculate address to store next event
112- slot_address = findNextFreeSlotAddress ();
158+ slot_address = findFirstReusableSlot ();
113159
114160 // Store UID / Offsetof the event at this address
115161 gmem[slot_address] = MAGIC_NUMBER;
@@ -118,8 +164,9 @@ function flagEvent(offset, msg1, msg2, msg3)
118164 gmem[slot_address+3] = g_block_num;
119165 gmem[slot_address+4] = (msg1 << 16) | (msg2 << 8) | msg3;
120166 gmem[slot_address+5] = offset;
121- );
122167
168+ gmem_v();
169+ );
123170
124171function receiveEvents()
125172 local(offset,msg1,msg2,msg3)
@@ -137,7 +184,6 @@ function receiveEvents()
137184//----------------------
138185
139186b_now = time_precise();
140- b_cursor = 0;
141187
142188// Resync the counter on play changes
143189
0 commit comments