1 // fourKlives.c
2 // weed plugin to generate parametric audio
3 // (c) G. Finch (salsaman) 2012
4 //
5 // released under the GNU GPL 3 or later
6 // see file COPYING or www.gnu.org for details
7
8 //#define DEBUG
9
10 ///////////////////////////////////////////////////////////////////
11
12 static int package_version = 1; // version of this package
13
14 //////////////////////////////////////////////////////////////////
15
16 #define NEED_AUDIO
17
18 #ifndef NEED_LOCAL_WEED_PLUGIN
19 #include <weed/weed-plugin.h>
20 #include <weed/weed-utils.h> // optional
21 #include <weed/weed-plugin-utils.h> // optional
22 #else
23 #include "../../libweed/weed-plugin.h"
24 #include "../../libweed/weed-utils.h" // optional
25 #include "../../libweed/weed-plugin-utils.h" // optional
26 #endif
27
28 #include "weed-plugin-utils.c"
29
30 /////////////////////////////////////////////////////////////
31
32 /*
33 The implementation of Syna functions
34
35 - Marq + Antti
36 */
37
38 // ported to LiVES by salsaman@gmail.com
39
40 //#define MONO
41
42 #include <math.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/types.h>
47 #include <dirent.h>
48 #include "syna.h"
49
50 #define MAX_TUNES 1024
51 #define MAX_TUNELEN 1024
52 #define TUNE_DIR "data/fourKlives/songs/"
53
54 static char *tunes[MAX_TUNES];
55
set_tempo(_sdata * sdata,int tempo)56 static void set_tempo(_sdata *sdata, int tempo) {
57 sdata->update = sdata->new_update = 6 * sdata->global / (tempo * 10 / 25);
58 // ekolen=update*3;
59 }
60
61
set_base_freq(_sdata * sdata,int freq)62 static void set_base_freq(_sdata *sdata, int freq) {
63 //base_freq=(freq<<13)/BFREQ;
64 sdata->base_freq = BFREQ + freq;
65 if (sdata->base_freq <= 0) sdata->base_freq = 1;
66 }
67
68
syna_init(_sdata * sdata,int freq)69 static int syna_init(_sdata *sdata, int freq) {
70 register int n, i;
71 sdata->module = NULL;
72 sdata->base_freq = BFREQ;
73 sdata->maxtracks = 0;
74
75 for (n = 0; n < WAVES; n++) {
76 sdata->aalto[n] = NULL;
77 }
78
79 for (n = 0; n < INSTR; n++) {
80 sdata->echo[n] = NULL;
81 sdata->instr[n] = NULL;
82 sdata->pi[n] = 0;
83 }
84
85 sdata->slen = freq / BFREQ;
86 sdata->global = freq;
87 sdata->counter = 0;
88
89 /* Generate lower octaves from 6 */
90 for (n = 4; n >= 0; n--)
91 for (i = 0; i < 12; i++)
92 notei[n * 12 + i] = notei[(n + 1) * 12 + i] / 2;
93
94 /* Generate the waveforms */
95 for (n = 0; n < WAVES; n++) {
96 if (n != KOHINA) {
97 sdata->aalto[n] = weed_malloc(sdata->slen * sizeof(float));
98 if (sdata->aalto[n] == NULL) {
99 return WEED_ERROR_MEMORY_ALLOCATION;
100 }
101 weed_memset(sdata->aalto[n], 0, sdata->slen * sizeof(float));
102 }
103 }
104
105 for (n = 0; n < sdata->slen; n++) {
106 sdata->aalto[KANTTI][n] = (n < sdata->slen / 2) ? -1.0 : 1.0;
107 sdata->aalto[SINI][n] = sin(n * 2.0 * M_PI / (float)sdata->slen);
108 sdata->aalto[SAHA][n] = -1.0 + fmod(1.0 + 2.0 * n / (float)sdata->slen, 2.0);
109 }
110
111 /* Noise needs to be longer */
112 sdata->aalto[KOHINA] = weed_malloc(sdata->global * sizeof(float));
113 if (sdata->aalto[KOHINA] == NULL) {
114 return WEED_ERROR_MEMORY_ALLOCATION;
115 }
116
117 for (n = 0; n < sdata->global; n++)
118 sdata->aalto[KOHINA][n] = (rand() % 2000 - 1000) / (float)1000.0;
119
120 /* Set starting values */
121 for (n = 0; n < INSTR; n++) {
122 sdata->live_row[n] = 0;
123 sdata->new_live_row[n] = 0;
124
125 sdata->off[n] = -1;
126 sdata->plus[n] = 0;
127 sdata->trak[n][0] = END;
128 sdata->ti[n] = -1;
129 sdata->eko[n] = 0;
130 sdata->pan[n] = (n & 1) ? 128 - 64 : 128 + 64;
131 #ifdef MONO
132 sdata->pan[n] = 128;
133 #endif
134 sdata->pola[n] = 0;
135 sdata->vol[n] = 255;
136 sdata->prev[n] = 0;
137 sdata->slide[n] = 0;
138 }
139 return WEED_SUCCESS;
140 }
141
142
143 #ifndef TINY
syna_load(_sdata * sdata,const char * tune)144 static int syna_load(_sdata *sdata, const char *tune) {
145 FILE *f;
146 long length;
147
148 int retval;
149
150 /* Read the file and call syna_get */
151 f = fopen(tune, "rb");
152 if (f == NULL) return WEED_ERROR_REINIT_NEEDED;
153 fseek(f, 0, SEEK_END);
154 length = ftell(f);
155 fseek(f, 0, SEEK_SET);
156 sdata->module = weed_malloc(length + 1);
157 retval = fread(sdata->module, 1, length, f);
158 sdata->module[length] = 0; /* String ends in zero */
159 fclose(f);
160
161 if (retval < length) return WEED_ERROR_REINIT_NEEDED;
162
163 return (syna_get(sdata));
164 }
165 #endif
166
167
syna_get(_sdata * sdata)168 static int syna_get(_sdata *sdata) {
169 static char *rows[MAXR], *key, *tnp;
170 int tmp, a, d, s, r, mod, sweep, wave, patt, track, note, wave_mod;
171
172 register int i, j, n;
173
174 #ifndef TINY
175 cleanup(sdata->module); /* You better have a clean module in intros... */
176 #endif
177
178 /* Extract rows */
179 for (n = 0; n < MAXR; n++) {
180 rows[n] = strtok((n) ? NULL : sdata->module, "\n");
181 if (rows[n] == NULL)
182 break;
183 }
184
185 /* Extract data from rows */
186 for (i = 0; i < n; i++) {
187 if (rows[i][0] == '#')
188 continue;
189
190 key = strtok(rows[i], ":");
191
192 if (key) {
193 if (!strcmp(key, "bpm")) {
194 tmp = atoi(strtok(NULL, ":")) * 10 / 25;
195 sdata->song_bpm = tmp;
196 sdata->new_update = sdata->update = 6 * sdata->global / tmp;
197 sdata->ekolen = sdata->update * 3;
198 }
199 if (key[0] == 'i') {
200 /* Get instrument number and wave form */
201 tmp = atoi(&key[1]);
202 if (tmp < INSTR) {
203 if (sdata->echo[tmp] != NULL) weed_free(sdata->echo[tmp]);
204 sdata->echo[tmp] = weed_malloc(sdata->ekolen * sizeof(int));
205 if (sdata->echo[tmp] == NULL) {
206 return WEED_ERROR_MEMORY_ALLOCATION;
207 }
208 weed_memset(sdata->echo[tmp], 0, sdata->ekolen * sizeof(int));
209 }
210
211 tnp = strtok(NULL, ",");
212
213 wave = 0;
214
215 if (!strcmp(tnp, "kantti") || !strcmp(tnp, "square"))
216 wave = 0;
217 else if (!strcmp(tnp, "sini") || !strcmp(tnp, "sin"))
218 wave = 1;
219 else if (!strcmp(tnp, "saha") || !strcmp(tnp, "saw"))
220 wave = 2;
221 else if (!strcmp(tnp, "kohina") || !strcmp(tnp, "noise"))
222 wave = 3;
223
224 /* Get ADSR */
225 a = atoi(strtok(NULL, ","));
226 d = atoi(strtok(NULL, ","));
227 s = atoi(strtok(NULL, ","));
228 r = atoi(strtok(NULL, ","));
229
230 if (tmp < INSTR) {
231 sdata->len[tmp] = a + d + s + r + 1;
232 sdata->instr[tmp] = weed_malloc(sdata->len[tmp] * sizeof(int));
233 if (sdata->echo[tmp] == NULL) {
234 return WEED_ERROR_MEMORY_ALLOCATION;
235 }
236 weed_memset(sdata->instr[tmp], 0, sdata->len[tmp]*sizeof(int));
237 }
238
239 mod = atoi(strtok(NULL, ","));
240 if ((tnp = strtok(NULL, ",")))
241 sweep = atoi(tnp);
242 else
243 sweep = 0;
244 if ((tnp = strtok(NULL, ",")))
245 if (tmp < INSTR) sdata->pan[tmp] = (float)atoi(tnp) * 255 / 100;
246 if ((tnp = strtok(NULL, ",")))
247 if (tmp < INSTR) sdata->pola[tmp] = atoi(tnp) * 255 / 100;
248
249 wave_mod = 1;
250
251 if ((tnp = strtok(NULL, ","))) {
252 if (!strcmp(tnp, "kantti") || !strcmp(tnp, "square"))
253 wave_mod = 0;
254 else if (!strcmp(tnp, "sini") || !strcmp(tnp, "sin"))
255 wave_mod = 1;
256 else if (!strcmp(tnp, "saha") || !strcmp(tnp, "saw"))
257 wave_mod = 2;
258 else if (!strcmp(tnp, "kohina") || !strcmp(tnp, "noise"))
259 wave_mod = 3;
260 }
261
262 if (tmp < INSTR) adsr(sdata, a, d, s, r, mod, sweep, tmp, wave, wave_mod);
263 }
264
265 if (key[0] == 'p') { /* Handle pattern */
266 patt = atoi(&key[1]);
267 j = 0;
268 while (1) {
269 tnp = strtok(NULL, ",");
270 if (tnp != NULL) {
271 note = 0;
272 for (tmp = 0; notes[tmp][0] != '0'; tmp++)
273 if (!strcmp(notes[tmp], tnp))
274 note = notei[tmp];
275 sdata->ptn[patt][j] = note;
276 if (note == VOL || note == SLIDE) {
277 j++;
278 sdata->ptn[patt][j] = atoi(strtok(NULL, ","));
279 }
280
281 j++;
282 } else {
283 sdata->ptn[patt][j] = END;
284 break;
285 }
286 }
287 }
288
289 if (key[0] == 't') { /* Handle track */
290 track = atoi(&key[1]);
291 j = 0;
292 while (1) {
293 tnp = strtok(NULL, ",");
294 if (tnp != NULL) {
295 if (!strcmp(tnp, "loop"))
296 sdata->trak[track][j] = LOOP;
297 else {
298 patt = atoi(&tnp[1]);
299 sdata->trak[track][j] = patt;
300 }
301 if (j > sdata->maxtracks) sdata->maxtracks = j;
302 j++;
303 } else {
304 sdata->trak[track][j] = END;
305 break;
306 }
307 }
308 }
309 }
310 }
311
312 return WEED_SUCCESS;
313 }
314
315 #if 0
316 // added by Antti Silvast for setting all live the rows
317 static void set_live_rows(_sdata *sdata, int *the_rows) {
318 register int i;
319
320 for (i = 0; i < INSTR; i++) {
321 sdata->new_live_row[i] = the_rows[i];
322 //pi[i]=0;
323 }
324 }
325 #endif
326
327 // added by Antti Silvast for setting just one live row
set_live_row(_sdata * sdata,int channel,int the_row)328 static void set_live_row(_sdata *sdata, int channel, int the_row) {
329 sdata->new_live_row[channel] = the_row;
330 }
331
332
syna_play(_sdata * sdata,float ** dest,int length,int channels,int interleave)333 static void syna_play(_sdata *sdata, float **dest, int length, int channels, int interleave) {
334 int note, li; // li is the "live i"
335 int left, right, smp;
336 int ceko, c1eko;
337
338 register int i, n;
339
340 ceko = sdata->counter % sdata->ekolen;
341
342 for (n = 0; n < length; n++, sdata->counter++) {
343 c1eko = ceko + 1;
344 if (c1eko == sdata->ekolen)
345 c1eko = 0;
346
347 /* New row */
348 if (sdata->counter > sdata->update) {
349 sdata->counter = 0;
350 sdata->update = sdata->new_update;
351 for (i = 1; sdata->trak[i][0] != END; i++) {
352 li = sdata->live_row[i];
353 //li=i;
354 if (li == END)
355 continue;
356 sdata->pi[i]++;
357
358 if (li == -1 || sdata->ptn[sdata->trak[i][li]][sdata->pi[i]] == END) {
359 li = sdata->live_row[i] = sdata->new_live_row[i];
360 //ti[i]++;
361 /*
362 if(trak[i][li]==LOOP)
363 li=0;
364 if(trak[i][li]==END)
365 li=END;
366 */
367 sdata->pi[i] = 0;
368 }
369 //printf("%d=%d ",i,trak[i][li]);
370
371 if (li != END) {
372 if ((note = sdata->ptn[sdata->trak[i][li]][sdata->pi[i]])) {
373 switch (note) {
374 case STOP:
375 sdata->off[i] = -1;
376 break;
377 case ECHON:
378 sdata->eko[i] = 1;
379 break;
380 case ECHOFF:
381 sdata->eko[i] = 0;
382 break;
383 case VOL:
384 sdata->pi[i]++;
385 sdata->vol[i] = sdata->ptn[sdata->trak[i][li]][sdata->pi[i]] * 255 / 100;
386 break;
387 case SLIDE:
388 sdata->pi[i]++;
389 sdata->slide[i] = sdata->ptn[sdata->trak[i][li]][sdata->pi[i]] * 164 / 1000;
390 break;
391 default:
392 sdata->plus[i] = note << 13;
393 //plus[i]/=BFREQ;
394 sdata->off[i] = 0;
395 }
396 }
397 }
398 }
399
400 //printf("\n");
401 }
402
403 #define MARQ_ARM_OPT
404
405 #ifndef MARQ_ARM_OPT
406 /* Sum the instruments */
407 left = right = 0;
408 for (i = 1; sdata->trak[i][0] != END; i++) {
409 smp = sdata->echo[i][(sdata->counter + 1) % sdata->ekolen];
410
411 sdata->echo[i][sdata->counter % sdata->ekolen] = sdata->echo[i][(sdata->counter + 1) % sdata->ekolen] * 6 / 10;
412 if (sdata->off[i] >= 0) {
413 smp += sdata->instr[i][sdata->off[i] >> 13];
414
415 if (sdata->eko[i])
416 sdata->echo[i][sdata->counter % sdata->ekolen] = smp * 2 / 10;
417
418 sdata->off[i] += (sdata->plus[i] + sdata->base_speed);
419 sdata->plus[i] += sdata->slide[i];
420 if ((sdata->off[i] >> 13) >= sdata->len[i] || sdata->off[i] < 0)
421 sdata->off[i] = -1;
422 }
423
424 if (sdata->pola[i])
425 smp = (smp * (255 ^ sdata->pola[i]) >> 8) + (sdata->prev[i] * sdata->pola[i] >> 8);
426 sdata->prev[i] = smp;
427
428 smp = smp * sdata->vol[i] >> 8;
429 left += (255 ^ sdata->pan[i]) * smp >> 8;
430 right += sdata->pan[i] * smp >> 8;
431 }
432
433 if (left < -98301)
434 left = -98301;
435 if (left > 98301)
436 left = 98301;
437 dest[0][n] = (float)left / 98301.;
438
439 if (channels == 2) {
440 if (right < -98301)
441 right = -98301;
442 if (right > 98301)
443 right = 98301;
444 dest[1][n] = (float)right / 98301.;
445 }
446 #else
447 // sum the instruments
448 left = right = 0;
449 for (i = 1; sdata->trak[i][0] != END; i++) {
450 smp = sdata->echo[i][c1eko];
451
452 //fprintf(stderr,"ok %d\n",smp);
453
454 sdata->echo[i][ceko] = smp * 19 >> 5;
455
456 if (sdata->off[i] >= 0) {
457 smp += sdata->instr[i][sdata->off[i] >> 13];
458 //fprintf(stderr,"ok2 %d\n",smp);
459
460 if (sdata->eko[i])
461 sdata->echo[i][ceko] = smp * 13 >> 6;
462
463 sdata->off[i] += (sdata->plus[i] / sdata->base_freq);
464 sdata->plus[i] += sdata->slide[i] * sdata->base_freq;
465 if ((sdata->off[i] >> 13) >= sdata->len[i] || sdata->off[i] < 0)
466 sdata->off[i] = -1;
467 }
468
469 if (sdata->pola[i])
470 smp = (smp * (255 ^ sdata->pola[i]) >> 8) + (sdata->prev[i] * sdata->pola[i] >> 8);
471 sdata->prev[i] = smp;
472 //fprintf(stderr,"ok23 %d\n",smp);
473
474 smp = smp * sdata->vol[i] >> 8;
475 //fprintf(stderr,"ok24 %d\n",smp);
476 left += (255 ^ sdata->pan[i]) * smp >> 8;
477 if (channels == 2)
478 right += sdata->pan[i] * smp >> 8;
479 }
480
481 if (left < -98301)
482 left = -98301;
483 else if (left > 98301)
484 left = 98301;
485 dest[0][n] = (float)(left * 21 >> 6) / 32767.;
486
487
488 if (channels == 2) {
489 if (right < -98301)
490 right = -98301;
491 else if (right > 98301)
492 right = 98301;
493 dest[1][n] = (float)(right * 21 >> 6) / 32767.;
494 }
495
496 //fprintf(stderr,"vals %d and %d, %f and %f\n",left,right,(float)(left*21>>6)/32767.,(float)(right*21>>6)/32767.);
497
498 ceko++;
499 if (ceko == sdata->ekolen)
500 ceko = 0;
501 }
502 #endif
503 }
504
505
506
507 /* Make ADSR to instruments */
adsr(_sdata * sdata,int a,int d,int s,int r,int mod,int swp,int ins,int wave,int wave_mod)508 static void adsr(_sdata *sdata, int a, int d, int s, int r, int mod, int swp, int ins, int wave, int wave_mod) {
509 int n, modulo = sdata->slen, id = 0;
510 float i = 0, vol = 0.0, dv, oh = 0.0, op, ip = 1, sweep;
511
512 if (!a) a = 1;
513 if (!r) r = 1;
514
515 if (wave == KOHINA)
516 modulo = sdata->global;
517
518 if (mod) /* We modulate! */
519 if (wave_mod == 1)
520 op = mod / 100.0 * 2.0 * M_PI / (float)sdata->slen;
521 else
522 op = (float)mod / 100.0;
523 else
524 op = 0;
525
526 sweep = (float)swp / 1000.0 / (float)sdata->slen;
527
528 dv = 32767.0 / (float)a;
529 for (n = 0; n < a; n++, i += ip, ip += sweep, vol += dv, oh += op)
530 if (wave_mod != 1)
531 sdata->instr[ins][id++] = vol * sdata->aalto[wave][((int)i) % modulo] * ((mod) ? sdata->aalto[wave_mod][((
532 int)oh) % modulo] : 1.0);
533 else
534 sdata->instr[ins][id++] = vol * sdata->aalto[wave][((int)i) % modulo] * ((mod) ? sin(oh) : 1.0);
535
536 for (n = 0; n < d; n++, i += ip, ip += sweep, vol -= dv, oh += op)
537 if (wave_mod != 1)
538 sdata->instr[ins][id++] = vol * sdata->aalto[wave][((int)i) % modulo] * ((mod) ? sdata->aalto[wave_mod][((
539 int)oh) % modulo] : 1.0);
540 else
541 sdata->instr[ins][id++] = vol * sdata->aalto[wave][((int)i) % modulo] * ((mod) ? sin(oh) : 1.0);
542
543
544 for (n = 0; n < s; n++, i += ip, ip += sweep, oh += op)
545 if (wave_mod != 1)
546 sdata->instr[ins][id++] = vol * sdata->aalto[wave][((int)i) % modulo] * ((mod) ? sdata->aalto[wave_mod][((
547 int)oh) % modulo] : 1.0);
548 else
549 sdata->instr[ins][id++] = vol * sdata->aalto[wave][((int)i) % modulo] * ((mod) ? sin(oh) : 1.0);
550
551 dv = vol / (float)r;
552
553 for (n = 0; n < r; n++, i += ip, ip += sweep, vol -= dv, oh += op)
554 if (wave_mod != 1)
555 sdata->instr[ins][id++] = vol * sdata->aalto[wave][((int)i) % modulo] * ((mod) ? sdata->aalto[wave_mod][((
556 int)oh) % modulo] : 1.0);
557 else
558 sdata->instr[ins][id++] = vol * sdata->aalto[wave][((int)i) % modulo] * ((mod) ? sin(oh) : 1.0);
559 }
560
561
562 /* Fix the fscking Windoze/DOS newlines */
563 #ifndef TINY
cleanup(char * s)564 void cleanup(char *s) {
565 char *d = strdup(s);
566 for (; *d; d++)
567 if (*d != '\r' && *d != ' ') *s++ = *d;
568 *s = 0;
569 }
570 #endif
571
572
syna_deinit(_sdata * sdata)573 static void syna_deinit(_sdata *sdata) {
574 int n;
575
576 if (!sdata) return;
577
578 for (n = 0; n < WAVES; n++) {
579 if (sdata->aalto[n]) weed_free(sdata->aalto[n]);
580 }
581 for (n = 0; n < INSTR; n++) {
582 if (sdata->echo[n]) weed_free(sdata->echo[n]);
583 }
584 if (sdata->module) weed_free(sdata->module);
585 }
586
587
588 /////////////////////////////////////////////
589
fourk_deinit(weed_plant_t * inst)590 static weed_error_t fourk_deinit(weed_plant_t *inst) {
591 _sdata *sdata = weed_get_voidptr_value(inst, "plugin_internal", NULL);
592 if (sdata) {
593 syna_deinit(sdata);
594 weed_free(sdata);
595 weed_set_voidptr_value(inst, "plugin_internal", NULL);
596 }
597 return WEED_SUCCESS;
598 }
599
600
fourk_init(weed_plant_t * inst)601 static weed_error_t fourk_init(weed_plant_t *inst) {
602 int retval;
603 int rate;
604
605 _sdata *sdata;
606
607 weed_plant_t *out_channel = weed_get_plantptr_value(inst, WEED_LEAF_OUT_CHANNELS, NULL);
608 weed_plant_t **in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
609
610 char tune[MAX_TUNELEN];
611
612 snprintf(tune, MAX_TUNELEN - 4, "%s%s", TUNE_DIR, tunes[weed_get_int_value(in_params[0], WEED_LEAF_VALUE, NULL)]);
613
614 weed_free(in_params);
615
616 sdata = (_sdata *)weed_malloc(sizeof(_sdata));
617
618 if (sdata == NULL) return WEED_ERROR_MEMORY_ALLOCATION;
619
620 weed_set_voidptr_value(inst, "plugin_internal", sdata);
621
622 rate = weed_get_int_value(out_channel, WEED_LEAF_AUDIO_RATE, NULL);
623
624 if ((retval = syna_init(sdata, rate)) != WEED_SUCCESS) {
625 #ifdef DEBUG
626 fprintf(stderr, "4k init failed\n");
627 #endif
628 fourk_deinit(inst);
629 return retval;
630 }
631
632 #ifdef DEBUG
633 fprintf(stderr, "4k: loading tune %s\n", tune);
634 #endif
635
636 if ((retval = syna_load(sdata, tune)) != WEED_SUCCESS) {
637
638 sprintf(tune + strlen(tune), "%s", ".txt");
639
640 #ifdef DEBUG
641 fprintf(stderr, "4k: loading tune %s\n", tune);
642 #endif
643
644 if ((retval = syna_load(sdata, tune)) != WEED_SUCCESS) {
645
646 fourk_deinit(inst);
647 #ifdef DEBUG
648 fprintf(stderr, "4k load failed\n");
649 #endif
650 return retval;
651 }
652 }
653
654 //set_tempo(sdata,136.); // bpm: maybe 8. to 263. ?
655 //set_base_freq(sdata,272.); // 145. to 400.
656
657 return WEED_SUCCESS;
658 }
659
660
fourk_process(weed_plant_t * inst,weed_timecode_t timestamp)661 static weed_error_t fourk_process(weed_plant_t *inst, weed_timecode_t timestamp) {
662 int chans, nsamps, inter;
663
664 weed_plant_t **in_params = weed_get_plantptr_array(inst, WEED_LEAF_IN_PARAMETERS, NULL);
665 weed_plant_t *out_channel = weed_get_plantptr_value(inst, WEED_LEAF_OUT_CHANNELS, NULL);
666
667 float **dst = (float **)weed_get_voidptr_array(out_channel, WEED_LEAF_AUDIO_DATA, NULL);
668
669 double tempo = weed_get_double_value(in_params[1], WEED_LEAF_VALUE, NULL);
670 double bfreq = weed_get_double_value(in_params[2], WEED_LEAF_VALUE, NULL);
671
672 _sdata *sdata = weed_get_voidptr_value(inst, "plugin_internal", NULL);
673
674 register int i;
675
676 weed_free(in_params);
677
678 if (!dst) return WEED_SUCCESS;
679
680 chans = weed_get_int_value(out_channel, WEED_LEAF_AUDIO_CHANNELS, NULL);
681 nsamps = weed_get_int_value(out_channel, WEED_LEAF_AUDIO_DATA_LENGTH, NULL);
682 //rate=weed_get_int_value(out_channel,WEED_LEAF_AUDIO_RATE,NULL);
683
684 for (i = 0; i < NCHANNELS; i++) {
685 set_live_row(sdata, i, (rand() % (sdata->maxtracks * 1000 - 1)) / 1000.f + 1.); // 2nd val can be 2 (?) to npat (?)
686 }
687
688 set_tempo(sdata, tempo * 255. + 8.); // bpm: maybe 8. to 263. ?
689 set_base_freq(sdata, bfreq * 255. - 128.); // 145. to 400.
690
691 syna_play(sdata, dst, nsamps, chans, inter); // dlen is number of samps....does interleaved
692 weed_free(dst);
693 return WEED_SUCCESS;
694 }
695
696
697 WEED_SETUP_START(200, 200) {
698 DIR *dir = NULL;
699 struct dirent *dirent;
700 size_t dlen;
701 int tcount = 0;
702 char desc[512];
703
704 weed_plant_t *out_chantmpls[2];
705 weed_plant_t *in_params[NCHANNELS + 4]; // tune name + channel rows + tempo + base_freq + NULL
706 weed_plant_t *filter_class;
707
708 register int i;
709
710 // make list of tunes
711 // scan entries in the ./data/fourklives/songs directory
712 dir = opendir(TUNE_DIR);
713 if (dir == NULL) return NULL;
714
715 while (1) {
716 if (tcount == MAX_TUNES - 1) break;
717 dirent = readdir(dir);
718 if (dirent == NULL) break;
719 dlen = strlen(dirent->d_name);
720 if (!strncmp(dirent->d_name, "..", dlen)) continue;
721 if (dlen > 4 && !strcmp(dirent->d_name + dlen - 4, ".txt")) dlen -= 4;
722 tunes[tcount++] = strndup(dirent->d_name, dlen);
723 }
724
725 closedir(dir);
726
727 tunes[tcount] = NULL;
728
729 in_params[0] = weed_string_list_init("tune_name", "_Tune", 0, (const char **const)tunes);
730 weed_set_int_value(in_params[0], WEED_LEAF_FLAGS, WEED_PARAMETER_REINIT_ON_VALUE_CHANGE);
731
732 in_params[1] = weed_float_init("tempo", "_Tempo", .5, 0., 1.);
733 in_params[2] = weed_float_init("bfreq", "Base _Frequency", .5, 0., 1.);
734
735 for (i = 3; i < NCHANNELS + 3; i++) {
736 // TODO - unique name
737 in_params[i] = weed_float_init("cparam", "cparam", .5, 0., 1.);
738 }
739
740 in_params[i] = NULL;
741
742 out_chantmpls[0] = weed_audio_channel_template_init("out channel 0", 0);
743 out_chantmpls[1] = NULL;
744
745 filter_class = weed_filter_class_init("fourKlives", "salsaman, anti and marq", 1, 0, NULL,
746 fourk_init, fourk_process, fourk_deinit, NULL, out_chantmpls, in_params, NULL);
747
748 weed_plugin_info_add_filter_class(plugin_info, filter_class);
749
750 snprintf(desc, 512, "fourK is a mini tracker player, which plays tunes from\ntext files\n");
751
752 weed_set_string_value(filter_class, WEED_LEAF_DESCRIPTION, desc);
753 weed_plugin_set_package_version(plugin_info, package_version);
754 }
755 WEED_SETUP_END;
756
757
758 WEED_DESETUP_START {
759 register int i;
760 for (i = 0; tunes[i] != NULL; i++) weed_free(tunes[i]);
761 }
762 WEED_DESETUP_END;
763