1 /*
2 	SuperCollider real time audio synthesis system
3     Copyright (c) 2002 James McCartney. All rights reserved.
4 	http://www.audiosynth.com
5 
6 
7 	Emil Post Tag Sytem UGens
8 	by Julian Rohrhuber
9 
10 
11     This program is free software; you can redistribute it and/or modify
12     it under the terms of the GNU General Public License as published by
13     the Free Software Foundation; either version 2 of the License, or
14     (at your option) any later version.
15 
16     This program is distributed in the hope that it will be useful,
17     but WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19     GNU General Public License for more details.
20 
21     You should have received a copy of the GNU General Public License
22     along with this program; if not, write to the Free Software
23     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
24 */
25 
26 #include "SC_PlugIn.h"
27 #include <stdio.h>
28 
29 #ifndef MAXFLOAT
30 # include <float.h>
31 # define MAXFLOAT FLT_MAX
32 #endif
33 
34 static InterfaceTable *ft;
35 
36 #define MAXCHANNELS 32
37 
38 
39 struct DbufTag : public Unit
40 {
41 	float m_fbufnum;
42 	SndBuf *m_buf;
43 	int *m_rule_offsets;
44 	int *m_rule_lengths;
45 	int32 m_axiom_size; // all these int32 could be uint32, but sc_wrap would need support for this.
46 	int32 m_read_pos;
47 	int32 m_write_pos;
48 	int m_numRules;
49 };
50 
51 struct Dtag : public Unit
52 {
53 	int *m_rule_offsets;
54 	int *m_rule_lengths;
55 	float *m_tape;
56 	int32 m_tape_size;
57 	int32 m_axiom_size;
58 	int32 m_read_pos;
59 	int32 m_write_pos;
60 	int m_numRules;
61 };
62 
63 
64 extern "C"
65 {
66 void DbufTag_Ctor(DbufTag *unit);
67 void DbufTag_Dtor(DbufTag *unit);
68 void DbufTag_next(DbufTag *unit, int inNumSamples);
69 
70 void Dtag_Ctor(Dtag *unit);
71 void Dtag_Dtor(Dtag *unit);
72 void Dtag_next(Dtag *unit, int inNumSamples);
73 
74 }
75 
76 /////////////////////////////////////////////////////////////
77 
78 
79 #define CHECK_BUF \
80 	if (!bufData) { \
81                 unit->mDone = true; \
82 		ClearUnitOutputs(unit, inNumSamples); \
83 		return; \
84 	}
85 
86 
87 /////////////////////////////////////////////////////////////
88 
89 enum {
90 	dtag_tape_param,
91 	dtag_deletion_number,
92 	dtag_recycle,
93 	dtag_mode,
94 	dtag_axiom_size,
95 	dtag_num_rules,
96 	dtag_argoffset
97 };
98 
99 
100 
DbufTag_initInputs(DbufTag * unit,int argOffset,int size)101 void DbufTag_initInputs(DbufTag *unit, int argOffset, int size)
102 {
103 	int memsize = size * sizeof(int);
104 
105 	unit->m_rule_lengths = (int*)RTAlloc(unit->mWorld, memsize);
106 	memset(unit->m_rule_lengths, 0, memsize);
107 
108 	unit->m_rule_offsets = (int*)RTAlloc(unit->mWorld, memsize);
109 	memset(unit->m_rule_offsets, 0, memsize);
110 
111 
112 	for(int i=0; i < size; i++) {
113 		unit->m_rule_lengths[i] = (int) IN0(i + argOffset); // drop first n args
114 	}
115 
116 	// calculate positions
117 	int position = argOffset + size;
118 	for(int i=0; i < size; i++) {
119 		unit->m_rule_offsets[i] = position;
120 		position += unit->m_rule_lengths[i];
121 		// printf("m_rule_offsets[%d]: %d\n", i, unit->m_rule_offsets[i]);
122 	}
123 }
124 
125 
DbufTag_reset(DbufTag * unit,int recycle,int inNumSamples)126 void DbufTag_reset(DbufTag *unit, int recycle, int inNumSamples)
127 {
128 	GET_BUF
129 	CHECK_BUF
130 	RESETINPUT(dtag_deletion_number); // reset deletion number
131 
132 	// if axiom size exceeds buffer, omit part of the axiom.
133 	if(unit->m_axiom_size > (int) bufFrames) {
134 		 unit->m_axiom_size = (int) bufFrames;
135 	}
136 
137 	if(recycle == 0) {
138 		// recycle = 0 - write axiom to buffer again.
139 		unit->m_read_pos = 0;
140 		unit->m_write_pos = (int32) unit->m_axiom_size;
141 
142 		if(unit->m_write_pos >= bufFrames) {
143 				unit->m_write_pos = unit->m_write_pos % bufFrames;
144 		}
145 		// write axiom to tape
146 		for(int i = 0; i < unit->m_write_pos; i++) {
147 			bufData[i] = (float) DEMANDINPUT_A(dtag_argoffset + i, inNumSamples);
148 			// printf("axiom[%d] = %d\n", i, (int) bufData[i]);
149 		}
150 	} else if (recycle < 0) {
151 		// recycle < 0 - write_pos is left where it is, read_pos is offset by recycle value
152 			unit->m_read_pos = unit->m_write_pos + recycle;
153 			if(unit->m_read_pos < 0) {
154 				unit->m_read_pos = unit->m_read_pos % bufFrames;
155 			}
156 
157 		} else {
158 			// recycle > 0 - read_pos is left where it is, write_pos is offset by recycle value
159 			unit->m_write_pos = unit->m_read_pos + recycle;
160 			if(unit->m_write_pos >= bufFrames) {
161 				unit->m_write_pos = unit->m_write_pos % bufFrames;
162 			}
163 			//printf("new write: %d, read: %d\n", unit->m_write_pos, unit->m_read_pos);
164 		}
165 }
166 
167 
DbufTag_end(DbufTag * unit,int which_case,int inNumSamples)168 void DbufTag_end(DbufTag *unit, int which_case, int inNumSamples) {
169 
170 	int recycle = (int) DEMANDINPUT_A(dtag_recycle, inNumSamples);
171 	int mode = (int) IN0(dtag_mode);
172 
173 	if(which_case == 0) {
174 		DbufTag_reset(unit, recycle, inNumSamples);
175 		if(mode == 4) {
176 			printf("tag system was reset externally.\n");
177 			if(recycle) { printf("recycling. axiom length: %d\n", recycle); }
178 		}
179 		return;
180 	}
181 
182 	if((mode == 0) || (mode == which_case)) {
183 		if(recycle) {
184 			DbufTag_reset(unit, recycle, inNumSamples);
185 		} else {
186 			OUT0(0) = NAN;
187 		}
188 		return;
189 	}
190 	if(mode >= 4) {
191 		printf("tag system halt: ");
192 		if(which_case == 1) {
193 			printf("divergence too large (buffer filled up).\n");
194 		} else {
195 			printf("terminated (string empty)\n");
196 		}
197 
198 		if(recycle) {
199 
200 			printf("recycling. axiom length: %d\n", recycle);
201 			//printf("new axiom:\n"); // todo.
202 			DbufTag_reset(unit, recycle, inNumSamples);
203 
204 			GET_BUF
205 			printf("new axiom (index %d..%d): ", unit->m_read_pos, unit->m_write_pos);
206 			int32 n = unit->m_write_pos - unit->m_read_pos;
207 			if(n < 0) { n = sc_wrap(n, 0, bufFrames - 1); }
208 			for(int32 i=0; i < n; i++) {
209 					int32 j = sc_wrap(unit->m_read_pos + i, 0, bufFrames - 1);
210 					printf("%d ", (int)bufData[j]);
211 			}
212 			printf("\n");
213 
214 		} else {
215 			OUT0(0) = NAN;
216 		}
217 		return;
218 	}
219 	OUT0(0) = NAN;
220 }
221 
222 
DbufTag_Ctor(DbufTag * unit)223 void DbufTag_Ctor(DbufTag *unit)
224 {
225 	SETCALC(DbufTag_next);
226 	unit->m_fbufnum = -1e9f;
227 	unit->m_axiom_size = (int) IN0(dtag_axiom_size);
228 	unit->m_numRules = (int) IN0(dtag_num_rules);
229 
230 	DbufTag_initInputs(unit, dtag_argoffset + unit->m_axiom_size, unit->m_numRules);
231 	DbufTag_reset(unit, 0, 1);
232 
233 	OUT0(0) = 0.f;
234 }
235 
236 
DbufTag_Dtor(DbufTag * unit)237 void DbufTag_Dtor(DbufTag *unit)
238 {
239 	RTFree(unit->mWorld, unit->m_rule_lengths);
240 	RTFree(unit->mWorld, unit->m_rule_offsets);
241 }
242 
243 
DbufTag_next(DbufTag * unit,int inNumSamples)244 void DbufTag_next(DbufTag *unit, int inNumSamples)
245 {
246 
247 	GET_BUF
248 	CHECK_BUF
249 
250 
251 	int rule_length;
252 	int cur_rule_pos, next_rule_pos;
253 	int32 write_pos = unit->m_write_pos;
254 	int32 read_pos = unit->m_read_pos;
255 
256 	float value = bufData[read_pos];
257 	int ruleIndex = (int) value;
258 
259 	// verbose print mode
260 	if(!(IN0(dtag_mode) < 5.f)) {
261 		int max = bufFrames;
262 		if(max > 32) { max = 32; }
263 		for(int i=0; i<max; i++) {
264 			if(i == write_pos) { printf(">"); } else if (i == read_pos) { printf("|"); } else { printf(" "); }
265 			printf("%d", (int) bufData[i]);
266 
267 		}
268 		printf("\n");
269 		printf("apply rule %d\n", ruleIndex);
270 
271 	}
272 
273 	//printf("writepos: %d readpos: %d rule_length: %d\n", unit->m_write_pos, unit->m_read_pos, rule_length);
274 
275 	if (!inNumSamples) {
276 		DbufTag_end(unit, 0, inNumSamples);
277 		return;
278 	}
279 
280 	int v = (int) DEMANDINPUT_A(dtag_deletion_number, inNumSamples);
281 
282 	if(ruleIndex >= unit-> m_numRules || (ruleIndex < 0)) {
283 		// printf("no rule found for value %d\n", ruleIndex);
284 		OUT0(0) = NAN;  // no rule found
285 		return;
286 	} else {
287 
288 		OUT0(0) = value;
289 
290 		cur_rule_pos = unit->m_rule_offsets[ruleIndex];
291 		rule_length = unit->m_rule_lengths[ruleIndex];
292 
293 		for(int i=0; i < rule_length; i++) {
294 			// copy production rule.
295 			bufData[write_pos] = DEMANDINPUT_A(cur_rule_pos + i, inNumSamples);
296 			write_pos += 1;
297 			if(write_pos == read_pos) {
298 				DbufTag_end(unit, 1, inNumSamples);
299 				return;
300 			}
301 			if(write_pos == bufFrames) {
302 				write_pos = 0;
303 			}
304 		}
305 
306 		for(int j=0; j < v; j++) {
307 			read_pos += 1;
308 			if(write_pos == read_pos) {
309 				DbufTag_end(unit, 2, inNumSamples);
310 				return;
311 			}
312 			if(read_pos == bufFrames) {
313 				read_pos = 0;
314 			}
315 		}
316 		unit->m_write_pos = write_pos;
317 		unit->m_read_pos = read_pos;
318 	}
319 
320 }
321 
322 
323 ///////////////////////////////////////////////////////
324 
325 
Dtag_initInputs(Dtag * unit,int argOffset,int size)326 void Dtag_initInputs(Dtag *unit, int argOffset, int size)
327 {
328 
329 	unit->m_tape_size = (int32) IN0(dtag_tape_param);
330 
331 	// make sure axiom isn't longer than the tape.
332 	if(unit->m_axiom_size > (int) unit->m_tape_size) {
333 		 unit->m_axiom_size = (int) unit->m_tape_size;
334 	}
335 
336 	// allocate tape
337 	int32 memtapesize = (int32) unit->m_tape_size * sizeof(int);
338 	unit->m_tape = (float*)RTAlloc(unit->mWorld, memtapesize);
339 	memset(unit->m_tape, 0, memtapesize);
340 
341 
342 	// allocate offsets and lengths
343 	int memsize = size * sizeof(int);
344 
345 	unit->m_rule_lengths = (int*)RTAlloc(unit->mWorld, memsize);
346 	memset(unit->m_rule_lengths, 0, memsize);
347 
348 	unit->m_rule_offsets = (int*)RTAlloc(unit->mWorld, memsize);
349 	memset(unit->m_rule_offsets, 0, memsize);
350 
351 
352 	for(int i=0; i < size; i++) {
353 		unit->m_rule_lengths[i] = (int) IN0(i + argOffset); // drop first n args
354 	}
355 
356 	// calculate positions
357 	int position = argOffset + size;
358 	for(int i=0; i < size; i++) {
359 		unit->m_rule_offsets[i] = position;
360 		position += unit->m_rule_lengths[i];
361 		// printf("m_rule_offsets[%d]: %d\n", i, unit->m_rule_offsets[i]);
362 	}
363 }
364 
365 
Dtag_reset(Dtag * unit,int recycle,int inNumSamples)366 void Dtag_reset(Dtag *unit, int recycle, int inNumSamples)
367 {
368 
369 	RESETINPUT(dtag_deletion_number); // reset deletion number
370 	// other than in DbufTag,  m_axiom_size doesn't have to be checked again here, since buffer is fix.
371 	if(recycle == 0) {
372 		// recycle = 0 - write axiom to buffer again.
373 		unit->m_read_pos = 0;
374 		unit->m_write_pos = (int32) unit->m_axiom_size;
375 
376 		// write axiom to tape
377 		for(int i = 0; i < unit->m_axiom_size; i++) {
378 			unit->m_tape[i] = DEMANDINPUT_A(dtag_argoffset + i, inNumSamples);
379 		//	printf("axiom[%d] = %d\n", i, unit->m_tape[i]);
380 		}
381 	} else if (recycle < 0) {
382 			// recycle < 0 - write_pos is left where it is, read_pos is offset by recycle value
383 			if(unit->m_write_pos >= unit->m_tape_size) {
384 				unit->m_write_pos = unit->m_write_pos % unit->m_tape_size;
385 			}
386 			unit->m_read_pos = unit->m_write_pos + recycle;
387 			if(unit->m_read_pos < 0) {
388 				unit->m_read_pos = sc_wrap(unit->m_read_pos, 0, unit->m_tape_size - 1);
389 			}
390 		} else {
391 			// recycle > 0 - read_pos is left where it is, write_pos is offset by recycle value
392 			if(unit->m_read_pos >= unit->m_tape_size) {
393 				unit->m_read_pos = unit->m_read_pos % unit->m_tape_size;
394 			}
395 			unit->m_write_pos = unit->m_read_pos + recycle;
396 			if(unit->m_write_pos >= unit->m_tape_size) {
397 				unit->m_write_pos = unit->m_write_pos % unit->m_tape_size;
398 			}
399 
400 		}
401 	}
402 
403 
Dtag_end(Dtag * unit,int which_case,int inNumSamples)404 void Dtag_end(Dtag *unit, int which_case, int inNumSamples) {
405 
406 	int recycle = (int) DEMANDINPUT_A(dtag_recycle, inNumSamples);
407 	int mode = (int) IN0(dtag_mode);
408 
409 	if(which_case == 0) {
410 		Dtag_reset(unit, recycle, inNumSamples);
411 		if(mode == 4) {
412 			printf("tag system was reset.\n");
413 			if(recycle) { printf("recycling. axiom length: %d\n", recycle); }
414 		}
415 		return;
416 	}
417 
418 	if((mode == 0) || (mode == which_case)) {
419 		if(recycle) {
420 			Dtag_reset(unit, recycle, inNumSamples);
421 		} else {
422 			OUT0(0) = NAN;
423 		}
424 		return;
425 	}
426 	if(mode >= 4) {
427 		printf("tag system halt: ");
428 		if(which_case == 1) {
429 			printf("divergence too large (buffer filled up).\n");
430 		} else {
431 			printf("terminated (string empty)\n");
432 		}
433 
434 		if(recycle) {
435 			printf("recycling. axiom length: %d\n", recycle);
436 
437 			Dtag_reset(unit, recycle, inNumSamples);
438 
439 			printf("new axiom (index %d..%d): ", unit->m_read_pos, unit->m_write_pos);
440 			int32 n = unit->m_write_pos - unit->m_read_pos;
441 			if(n < 0) { n = sc_wrap(n, 0, unit->m_tape_size - 1); }
442 			for(int32 i=0; i < n; i++) {
443 					int32 j = sc_wrap(unit->m_read_pos + i, 0, unit->m_tape_size - 1);
444 					printf("%d ", (int)unit->m_tape[j]);
445 			}
446 			printf("\n");
447 
448 		} else {
449 			OUT0(0) = NAN;
450 		}
451 		return;
452 	}
453 	OUT0(0) = NAN;
454 }
455 
456 
Dtag_Ctor(Dtag * unit)457 void Dtag_Ctor(Dtag *unit)
458 {
459 
460 	SETCALC(Dtag_next);
461 
462 	unit->m_axiom_size = (int) IN0(dtag_axiom_size);
463 	unit->m_numRules = (int) IN0(dtag_num_rules);
464 
465 	// initialise and reset
466 	Dtag_initInputs(unit, dtag_argoffset + unit->m_axiom_size, unit->m_numRules);
467 	Dtag_reset(unit, 0, 1);
468 
469 	OUT0(0) = 0.f;
470 }
471 
472 
Dtag_Dtor(Dtag * unit)473 void Dtag_Dtor(Dtag *unit)
474 {
475 	RTFree(unit->mWorld, unit->m_rule_lengths);
476 	RTFree(unit->mWorld, unit->m_rule_offsets);
477 	RTFree(unit->mWorld, unit->m_tape);
478 }
479 
Dtag_next(Dtag * unit,int inNumSamples)480 void Dtag_next(Dtag *unit, int inNumSamples)
481 {
482 
483 	int rule_length;
484 	int cur_rule_pos, next_rule_pos;
485 
486 	int32 write_pos = unit->m_write_pos;
487 	int32 read_pos = unit->m_read_pos;
488 	int32 tape_size = unit->m_tape_size;
489 	float *tape = unit->m_tape;
490 	float tapeVal = tape[read_pos];
491 	int ruleIndex = (int) tapeVal;
492 
493 
494 		// verbose print mode
495 	if(!(IN0(dtag_mode) < 5.f)) {
496 		int max = (int) unit->m_tape_size;
497 		if(max > 32) { max = 32; }
498 		for(int i=0; i<max; i++) {
499 			if(i == write_pos) { printf(">"); } else if (i == read_pos) { printf("|"); } else { printf(" "); }
500 			printf("%d", (int) unit->m_tape[i]);
501 
502 		}
503 		printf("\n");
504 		printf("apply rule %d\n", ruleIndex);
505 	}
506 
507 
508 
509 	if (!inNumSamples) {
510 		Dtag_end(unit, 0, 1);
511 		return;
512 	}
513 
514 	int v = (int) DEMANDINPUT_A(dtag_deletion_number, inNumSamples);
515 
516 	//printf("ruleIndex: %d rulesize: %d\n", ruleIndex, unit->m_numRules);
517 	if(ruleIndex >= unit->m_numRules || (ruleIndex < 0)) {
518 		// printf("no rule found for value %d rulesize: %d\n", ruleIndex, unit->m_numRules);
519 		OUT0(0) = NAN;  // no rule found
520 		return;
521 	} else {
522 		OUT0(0) = tapeVal;
523 		cur_rule_pos = unit->m_rule_offsets[ruleIndex];
524 		rule_length = unit->m_rule_lengths[ruleIndex];
525 
526 		for(int i=0; i < rule_length; i++) {
527 			tape[write_pos] = DEMANDINPUT_A(cur_rule_pos + i, inNumSamples);
528 			write_pos += 1;
529 			if(write_pos == read_pos) {
530 				Dtag_end(unit, 1, inNumSamples);
531 				return;
532 			}
533 			if(write_pos == tape_size) {
534 				write_pos = 0;
535 			}
536 		}
537 		for(int j=0; j < v; j++) {
538 			read_pos += 1;
539 			if(write_pos == read_pos) {
540 				Dtag_end(unit, 2, inNumSamples);
541 				return;
542 			}
543 			if(read_pos == tape_size) {
544 				read_pos = 0;
545 			}
546 		}
547 		unit->m_write_pos = write_pos;
548 		unit->m_read_pos = read_pos;
549 	}
550 
551 }
552 
553 
554 
555 
556 
557 
558 struct Dfsm : public Unit
559 {
560 	//int m_repeats;
561 	int m_num_sizes;
562 	int m_num_states;
563 	int m_state_offset;
564 	int *m_nextstate_indices;
565 	int *m_nextstate_sizes;
566 	int m_current_state;
567 	int m_current_state_offset;
568 	float m_count;
569 	int m_end;
570 };
571 
572 
573 extern "C"
574 {
575 void Dfsm_Ctor(Dfsm *unit);
576 void Dfsm_Dtor(Dfsm *unit);
577 void Dfsm_next(Dfsm *unit, int inNumSamples);
578 
579 };
580 
581 
582 
583 //////////////////////////////////////////////////////////////////////////////////////////////////
584 
Dfsm_reset(Dfsm * unit)585 void Dfsm_reset(Dfsm *unit) {
586 		unit->m_current_state = 0;
587 		unit->m_end = 0;
588 		unit->m_count = 0.f;
589 		for(int i = 0; i < unit->m_num_states; i++) {
590 			// // printf("reset input[%d]\n", unit->m_state_offset + i);
591 			RESETINPUT(unit->m_state_offset + i);
592 		}
593 }
594 
Dfsm_next(Dfsm * unit,int inNumSamples)595 void Dfsm_next(Dfsm *unit, int inNumSamples)
596 {
597 	int current_state_offset, state_offset;
598 	int choice;
599 	int index_index;
600 	int next_index;
601 	float outval;
602 
603 	// // printf("\n\n\n ------- \n");
604 
605 	////////////////////// reset /////////////////////////
606 	// current_state is the internal state, including exit / enty pair.
607 	// i.e. first rule is pair [exit, entrance]
608 
609 	if (!inNumSamples) {
610 		Dfsm_reset(unit);
611 		// printf("resetting\n");
612 	}
613 
614 	// get some member state
615 	state_offset = unit->m_state_offset;
616 	current_state_offset = unit->m_current_state_offset;
617 
618 	////////////////////// embedding mode /////////////////////////
619 	if(unit->m_count > 0.f) {
620 		outval = DEMANDINPUT_A(current_state_offset, inNumSamples); // this will have to switch behaviour, depending on slotRepeats
621 		if(sc_isnan(outval)) {
622 
623 			if(unit->m_end) {
624 					// exit state last value. end.
625 					OUT0(0) = NAN;
626 					unit->m_end = 0;
627 					unit->m_count = 0.f;
628 					// // printf("output: NAN to end stream\n");
629 					return;
630 			} else {
631 
632 				// other state last value
633 				// // printf("(1) resetting input %d\n", current_state_offset);
634 				RESETINPUT(current_state_offset);
635 			};
636 
637 		} else {
638 			// embed current value of current state
639 			// // printf("outval: %f\n", outval);
640 			OUT0(0) = outval;
641 			unit->m_count --;
642 			return;
643 		}
644 	}
645 
646 	////////////////////// init count /////////////////////////
647 
648 	// get new count
649 	unit->m_count = DEMANDINPUT_A(0, inNumSamples) - 1.f; // offset: first value is embedded below.
650 
651 	if(sc_isnan(unit->m_count)) {  // terminate and reset
652 					RESETINPUT(0);
653 					OUT0(0) = NAN;
654 					unit->m_end = 0;
655 					unit->m_count = 0.f;
656 					// // printf("output: NAN to end stream\n");
657 					return;
658 	};
659 
660 
661 
662 	////////////////////// finding next state /////////////////////////
663 
664 
665 
666 	if(unit->m_current_state >= unit->m_num_states) {
667 		unit->m_current_state_offset = state_offset;
668 		outval = DEMANDINPUT_A(unit->m_current_state_offset, inNumSamples); // get first state, which is the packed termination state
669 		OUT0(0) = outval;
670 		// // printf("going to exit state (1): %d end\n", unit->m_current_state);
671 		// // printf("output: %f\n", outval);
672 		unit->m_end = 1;
673 		return;
674 	}
675 
676 	// how many nextstates ?
677 	float size = (float) unit->m_nextstate_sizes[unit->m_current_state];
678 
679 	// get random value and generate random offset (0..size)
680 	float rand = DEMANDINPUT_A(1, inNumSamples);
681 	choice = (int) sc_max(0.f, rand * size - 0.5f);
682 
683 	// look up the nextstate index
684 	index_index = unit->m_nextstate_indices[unit->m_current_state] + choice; // we'll need to limit this /0..1/
685 
686 	// get the next state index from the input, add one for offset: first rule is pair [exit, entrance]
687 	next_index = IN0(index_index) + 1;
688 	unit->m_current_state= next_index;
689 
690 	current_state_offset = state_offset + next_index;
691 
692 	// exit
693 	if(next_index >= unit->m_num_states) {
694 		current_state_offset = state_offset; // get first state, which is the packed termination state
695 		// // printf("going to exit state (2): %d end\n", next_index);
696 		unit->m_end = 1;
697 	}
698 
699 
700 	// get first value
701 	outval = DEMANDINPUT_A(current_state_offset, inNumSamples);
702 	if(sc_isnan(outval)) {
703 			// // printf("(1) resetting input %d\n", current_state_offset);
704 			if(unit->m_end) {
705 				outval = NAN;
706 			} else {
707 				RESETINPUT(current_state_offset);
708 				outval = DEMANDINPUT_A(current_state_offset, inNumSamples);
709 			}
710 	}
711 	OUT0(0) = outval;
712 
713 	// set member state
714 	unit->m_current_state_offset = current_state_offset;
715 
716 	 // printf("indexindex: %d choice: %d, previndex: %d nextindex: %d outval index: %d\n", index_index, choice, unit->m_current_state, next_index, state_offset + next_index);
717 	// // printf("outval: %f\n", outval);
718 }
719 
720 
721 
Dfsm_Ctor(Dfsm * unit)722 void Dfsm_Ctor(Dfsm *unit)
723 {
724 	SETCALC(Dfsm_next);
725 
726 	int numStates = (int)IN0(2);
727 	unit->m_num_states = numStates;
728 
729 	// keep state size information
730 	int memNumSize = numStates * sizeof(int);
731 	unit->m_nextstate_sizes = (int*)RTAlloc(unit->mWorld, memNumSize);
732 	memset(unit->m_nextstate_sizes, 0, memNumSize);
733 
734 	for(int i = 0; i <  numStates; i++) {
735 		unit->m_nextstate_sizes[i] = (int) IN0(3 + i);
736 	}
737 
738 
739 	// keep state index information
740 	unit->m_state_offset = 3 + numStates;
741 	int nextOffset = unit->m_state_offset + numStates;
742 
743 	int memNumIndices = numStates * sizeof(int);
744 	unit->m_nextstate_indices = (int*)RTAlloc(unit->mWorld, memNumIndices);
745 	memset(unit->m_nextstate_indices, 0, memNumIndices);
746 
747 	for(int i = 0; i <  numStates; i++) {
748 		unit->m_nextstate_indices[i] = nextOffset;
749 		nextOffset = nextOffset + unit->m_nextstate_sizes[i];
750 	}
751 
752 	// reset
753 	unit->m_current_state = 0;
754 	unit->m_end = 0;
755 	unit->m_count = 0.f;
756 	OUT0(0) = 0.f;
757 }
758 
759 
Dfsm_Dtor(Dfsm * unit)760 void Dfsm_Dtor(Dfsm *unit)
761 {
762 	RTFree(unit->mWorld, unit->m_nextstate_indices);
763 	RTFree(unit->mWorld, unit->m_nextstate_sizes);
764 }
765 
766 
767 //////////////////////////////////////////////////////
768 
769 
770 
PluginLoad(TagSystem)771 PluginLoad(TagSystem)
772 {
773 	ft = inTable;
774 	DefineDtorUnit(DbufTag);
775 	DefineDtorUnit(Dtag);
776 	DefineDtorUnit(Dfsm);
777 
778 }
779