bloops 0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/c/bloopsaphone.c ADDED
@@ -0,0 +1,596 @@
1
+ //
2
+ // bloopsaphone.c
3
+ // the chiptune maker for portaudio
4
+ // (with bindings for ruby)
5
+ //
6
+ // (c) 2009 why the lucky stiff
7
+ // See COPYING for the license
8
+ //
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <stddef.h>
12
+ #include <string.h>
13
+ #include <time.h>
14
+ #include <math.h>
15
+ #include <portaudio.h>
16
+ #include <unistd.h>
17
+ #include "bloopsaphone.h"
18
+ #include "bloopsaphone-internal.h"
19
+
20
+ #ifdef PaStream
21
+ #error ** Looks like you're linking against PortAudio 1.8!
22
+ #error ** Bloopsaphone needs PortAudio 1.9 or greater.
23
+ #error ** On Ubuntu, try: aptitude install portaudio19-dev.
24
+ #endif
25
+
26
+ #define SAMPLE_RATE 44100
27
+ #define rnd(n) (rand() % (n + 1))
28
+ #define tempo2frames(tempo) ((float)SAMPLE_RATE / (tempo / 60.0f))
29
+ #define PI 3.14159265f
30
+
31
+ #define FX(F, V) ({ \
32
+ if (F->mod == '+') V += F->val; \
33
+ else if (F->mod == '-') V -= F->val; \
34
+ else V = F->val; \
35
+ if (V > 1.0f) \
36
+ V = 1.0f; \
37
+ else if (V < 0.0f) \
38
+ V = 0.0f; \
39
+ })
40
+
41
+ static bloopsalock LOCK;
42
+ static bloopsmix *MIXER = NULL;
43
+
44
+ static void bloops_synth(int, float *);
45
+ static int bloops_port_callback(const void *, void *,
46
+ unsigned long, const PaStreamCallbackTimeInfo *,
47
+ PaStreamCallbackFlags, void *);
48
+ static void bloops_set_track_at(bloops *B, bloopsatrack *track, int num);
49
+
50
+ float
51
+ frnd(float range)
52
+ {
53
+ return (float)rnd(10000) / 10000 * range;
54
+ }
55
+
56
+ static void
57
+ bloops_remove(bloops *B)
58
+ {
59
+ int i;
60
+ if (MIXER == NULL) return;
61
+ for (i = 0; i < BLOOPS_MAX_CHANNELS; i++) {
62
+ if (MIXER->B[i] == B) {
63
+ MIXER->B[i] = NULL;
64
+ bloops_destroy(B);
65
+ }
66
+ }
67
+ }
68
+
69
+ static void
70
+ bloops_reset_voice(bloopsavoice *A)
71
+ {
72
+ A->period = 100.0 / (A->params.freq * A->params.freq + 0.001);
73
+ A->maxperiod = 100.0 / (A->params.limit * A->params.limit + 0.001);
74
+ A->slide = 1.0 - pow((double)A->params.slide, 3.0) * 0.01;
75
+ A->dslide = -pow((double)A->params.dslide, 3.0) * 0.000001;
76
+ A->square = 0.5f - A->params.square * 0.5f;
77
+ A->sweep = -A->params.sweep * 0.00005f;
78
+ if (A->params.arp >= 0.0f)
79
+ A->arp = 1.0 - pow((double)A->params.arp, 2.0) * 0.9;
80
+ else
81
+ A->arp = 1.0 + pow((double)A->params.arp, 2.0) * 10.0;
82
+ A->atime = 0;
83
+ A->alimit = (int)(pow(1.0f - A->params.aspeed, 2.0f) * 20000 + 32);
84
+ if (A->params.aspeed == 1.0f)
85
+ A->alimit = 0;
86
+ }
87
+
88
+ static void
89
+ bloops_start_voice(bloopsavoice *A) {
90
+ int i = 0;
91
+ A->phase = 0;
92
+ A->filter[0] = 0.0f;
93
+ A->filter[1] = 0.0f;
94
+ A->filter[2] = pow(A->params.lpf, 3.0f) * 0.1f;
95
+ A->filter[3] = 1.0f + A->params.lsweep * 0.0001f;
96
+ A->filter[4] = 5.0f / (1.0f + pow(A->params.resonance, 2.0f) * 20.0f) * (0.01f + A->filter[2]);
97
+ if (A->filter[4] > 0.8f) A->filter[4] = 0.8f;
98
+ A->filter[5] = 0.0f;
99
+ A->filter[6] = pow(A->params.hpf, 2.0f) * 0.1f;
100
+ A->filter[7] = 1.0 + A->params.hsweep * 0.0003f;
101
+
102
+ A->vibe = 0.0f;
103
+ A->vspeed = pow(A->params.vspeed, 2.0f) * 0.01f;
104
+ A->vdelay = A->params.vibe * 0.5f;
105
+
106
+ A->volume = 0.0f;
107
+ A->stage = 0;
108
+ A->time = 0;
109
+ A->length[0] = (int)(A->params.attack * A->params.attack * 100000.0f);
110
+ A->length[1] = (int)(A->params.sustain * A->params.sustain * 100000.0f);
111
+ A->length[2] = (int)(A->params.decay * A->params.decay * 100000.0f);
112
+
113
+ A->fphase = pow(A->params.phase, 2.0f) * 1020.0f;
114
+ if (A->params.phase < 0.0f) A->fphase = -A->fphase;
115
+ A->dphase = pow(A->params.psweep, 2.0f) * 1.0f;
116
+ if (A->params.psweep < 0.0f) A->dphase = -A->dphase;
117
+ A->iphase = abs((int)A->fphase);
118
+ A->phasex = 0;
119
+
120
+ memset(A->phaser, 0, 1024 * sizeof(float));
121
+ for (i = 0; i < 32; i++)
122
+ A->noise[i] = frnd(2.0f) - 1.0f;
123
+
124
+ A->repeat = 0;
125
+ A->limit = (int)(pow(1.0f - A->params.repeat, 2.0f) * 20000 + 32);
126
+ if (A->params.repeat == 0.0f)
127
+ A->limit = 0;
128
+ A->state = BLOOPS_PLAY;
129
+ }
130
+
131
+ void
132
+ bloops_clear(bloops *B)
133
+ {
134
+ int i;
135
+ for (i = 0; i < BLOOPS_MAX_TRACKS; i++) {
136
+ bloops_set_track_at(B, NULL, i);
137
+ }
138
+ }
139
+
140
+ void
141
+ bloops_tempo(bloops *B, int tempo)
142
+ {
143
+ B->tempo = tempo;
144
+ }
145
+
146
+ void
147
+ bloops_set_track_at(bloops *B, bloopsatrack *track, int num)
148
+ {
149
+ bloopsavoice *voice;
150
+ bloopsatrack *old_track;
151
+ voice = &B->voices[num];
152
+ old_track = voice->track;
153
+ voice->track = track;
154
+ if (track != NULL) {
155
+ bloops_track_ref(track);
156
+ }
157
+ if (old_track != NULL) {
158
+ bloops_track_destroy(old_track);
159
+ }
160
+ voice->state = BLOOPS_STOP;
161
+ if (track != NULL) {
162
+ memcpy(&voice->params, &track->params, sizeof(bloopsaparams));
163
+ }
164
+ voice->frames = 0;
165
+ voice->nextnote[0] = 0;
166
+ voice->nextnote[1] = 0;
167
+ }
168
+
169
+ void
170
+ _bloops_track_add(bloops *B, bloopsatrack *track) {
171
+ int i;
172
+ for (i = 0; i < BLOOPS_MAX_TRACKS; i++) {
173
+ if (B->voices[i].track == NULL) {
174
+ bloops_set_track_at(B, track, i);
175
+ break;
176
+ }
177
+ }
178
+ }
179
+
180
+ int
181
+ bloops_is_done(bloops *B)
182
+ {
183
+ return B->state == BLOOPS_STOP;
184
+ }
185
+
186
+ static void
187
+ bloops_synth(int length, float* buffer)
188
+ {
189
+ int bi, t, i, si;
190
+
191
+ while (length--)
192
+ {
193
+ int samplecount = 0;
194
+ float allsample = 0.0f;
195
+
196
+ for (bi = 0; bi < BLOOPS_MAX_CHANNELS; bi++)
197
+ {
198
+ int moreframes = 0;
199
+ bloops *B = MIXER->B[bi];
200
+ if (B == NULL)
201
+ continue;
202
+ for (t = 0; t < BLOOPS_MAX_TRACKS; t++)
203
+ {
204
+ bloopsavoice *A = &B->voices[t];
205
+ bloopsatrack *track = A->track;
206
+ if (track == NULL)
207
+ continue;
208
+
209
+ if (track->notes)
210
+ {
211
+ if (A->frames == A->nextnote[0])
212
+ {
213
+ if (A->nextnote[1] < track->nlen)
214
+ {
215
+ bloopsanote *note = &track->notes[A->nextnote[1]];
216
+ float freq = A->params.freq;
217
+ if (note->tone != 'n')
218
+ freq = bloops_note_freq(note->tone, (int)note->octave);
219
+ if (freq == 0.0f) {
220
+ A->period = 0.0f;
221
+ A->state = BLOOPS_STOP;
222
+ } else {
223
+ bloopsanote *note = &track->notes[A->nextnote[1]];
224
+ bloopsafx *fx = note->FX;
225
+ while (fx) {
226
+ switch (fx->cmd) {
227
+ case BLOOPS_FX_VOLUME: FX(fx, A->params.volume); break;
228
+ case BLOOPS_FX_PUNCH: FX(fx, A->params.punch); break;
229
+ case BLOOPS_FX_ATTACK: FX(fx, A->params.attack); break;
230
+ case BLOOPS_FX_SUSTAIN: FX(fx, A->params.sustain); break;
231
+ case BLOOPS_FX_DECAY: FX(fx, A->params.decay); break;
232
+ case BLOOPS_FX_SQUARE: FX(fx, A->params.square); break;
233
+ case BLOOPS_FX_SWEEP: FX(fx, A->params.sweep); break;
234
+ case BLOOPS_FX_VIBE: FX(fx, A->params.vibe); break;
235
+ case BLOOPS_FX_VSPEED: FX(fx, A->params.vspeed); break;
236
+ case BLOOPS_FX_VDELAY: FX(fx, A->params.vdelay); break;
237
+ case BLOOPS_FX_LPF: FX(fx, A->params.lpf); break;
238
+ case BLOOPS_FX_LSWEEP: FX(fx, A->params.lsweep); break;
239
+ case BLOOPS_FX_RESONANCE: FX(fx, A->params.resonance); break;
240
+ case BLOOPS_FX_HPF: FX(fx, A->params.hpf); break;
241
+ case BLOOPS_FX_HSWEEP: FX(fx, A->params.hsweep); break;
242
+ case BLOOPS_FX_ARP: FX(fx, A->params.arp); break;
243
+ case BLOOPS_FX_ASPEED: FX(fx, A->params.aspeed); break;
244
+ case BLOOPS_FX_PHASE: FX(fx, A->params.phase); break;
245
+ case BLOOPS_FX_PSWEEP: FX(fx, A->params.psweep); break;
246
+ case BLOOPS_FX_REPEAT: FX(fx, A->params.repeat); break;
247
+ }
248
+ fx = fx->next;
249
+ }
250
+
251
+ bloops_reset_voice(A);
252
+ bloops_start_voice(A);
253
+ A->period = 100.0 / (freq * freq + 0.001);
254
+ }
255
+
256
+ A->nextnote[0] += (int)(tempo2frames(B->tempo) * (4.0f / note->duration));
257
+ }
258
+ A->nextnote[1]++;
259
+ }
260
+
261
+ if (A->nextnote[1] <= track->nlen)
262
+ moreframes++;
263
+ }
264
+ else
265
+ {
266
+ moreframes++;
267
+ }
268
+
269
+ A->frames++;
270
+
271
+ if (A->state == BLOOPS_STOP)
272
+ continue;
273
+
274
+ samplecount++;
275
+ A->repeat++;
276
+ if (A->limit != 0 && A->repeat >= A->limit)
277
+ {
278
+ A->repeat = 0;
279
+ bloops_reset_voice(A);
280
+ }
281
+
282
+ A->atime++;
283
+ if (A->alimit != 0 && A->atime >= A->alimit)
284
+ {
285
+ A->alimit = 0;
286
+ A->period *= A->arp;
287
+ }
288
+
289
+ A->slide += A->dslide;
290
+ A->period *= A->slide;
291
+ if (A->period > A->maxperiod)
292
+ {
293
+ A->period = A->maxperiod;
294
+ if (A->params.limit > 0.0f)
295
+ A->state = BLOOPS_STOP;
296
+ }
297
+
298
+ float rfperiod = A->period;
299
+ if (A->vdelay > 0.0f)
300
+ {
301
+ A->vibe += A->vspeed;
302
+ rfperiod = A->period * (1.0 + sin(A->vibe) * A->vdelay);
303
+ }
304
+
305
+ int period = (int)rfperiod;
306
+ if (period < 8) period = 8;
307
+ A->square += A->sweep;
308
+ if(A->square < 0.0f) A->square = 0.0f;
309
+ if(A->square > 0.5f) A->square = 0.5f;
310
+
311
+ A->time++;
312
+ while (A->time >= A->length[A->stage])
313
+ {
314
+ A->time = 0;
315
+ A->stage++;
316
+ if (A->stage == 3)
317
+ A->state = BLOOPS_STOP;
318
+ }
319
+
320
+ switch (A->stage) {
321
+ case 0:
322
+ A->volume = (float)A->time / A->length[0];
323
+ break;
324
+ case 1:
325
+ A->volume = 1.0f + (1.0f - (float)A->time / A->length[1]) * 2.0f * A->params.punch;
326
+ break;
327
+ case 2:
328
+ A->volume = 1.0f - (float)A->time / A->length[2];
329
+ break;
330
+ }
331
+
332
+ A->fphase += A->dphase;
333
+ A->iphase = abs((int)A->fphase);
334
+ if (A->iphase > 1023) A->iphase = 1023;
335
+
336
+ if (A->filter[7] != 0.0f)
337
+ {
338
+ A->filter[6] *= A->filter[7];
339
+ if (A->filter[6] < 0.00001f) A->filter[6] = 0.00001f;
340
+ if (A->filter[6] > 0.1f) A->filter[6] = 0.1f;
341
+ }
342
+
343
+ float ssample = 0.0f;
344
+ for (si = 0; si < 8; si++)
345
+ {
346
+ float sample = 0.0f;
347
+ A->phase++;
348
+ if (A->phase >= period)
349
+ {
350
+ A->phase %= period;
351
+ if (A->params.type == BLOOPS_NOISE)
352
+ for (i = 0; i < 32; i++)
353
+ A->noise[i] = frnd(2.0f) - 1.0f;
354
+ }
355
+
356
+ float fp = (float)A->phase / period;
357
+ switch (A->params.type)
358
+ {
359
+ case BLOOPS_SQUARE:
360
+ if (fp < A->square)
361
+ sample = 0.5f;
362
+ else
363
+ sample = -0.5f;
364
+ break;
365
+ case BLOOPS_SAWTOOTH:
366
+ sample = 1.0f - fp * 2;
367
+ break;
368
+ case BLOOPS_SINE:
369
+ sample = (float)sin(fp * 2 * PI);
370
+ break;
371
+ case BLOOPS_NOISE:
372
+ sample = A->noise[A->phase * 32 / period];
373
+ break;
374
+ }
375
+
376
+ float pp = A->filter[0];
377
+ A->filter[2] *= A->filter[3];
378
+ if (A->filter[2] < 0.0f) A->filter[2] = 0.0f;
379
+ if (A->filter[2] > 0.1f) A->filter[2] = 0.1f;
380
+ if (A->params.lpf != 1.0f)
381
+ {
382
+ A->filter[1] += (sample - A->filter[0]) * A->filter[2];
383
+ A->filter[1] -= A->filter[1] * A->filter[4];
384
+ }
385
+ else
386
+ {
387
+ A->filter[0] = sample;
388
+ A->filter[1] = 0.0f;
389
+ }
390
+ A->filter[0] += A->filter[1];
391
+
392
+ A->filter[5] += A->filter[0] - pp;
393
+ A->filter[5] -= A->filter[5] * A->filter[6];
394
+ sample = A->filter[5];
395
+
396
+ A->phaser[A->phasex & 1023] = sample;
397
+ sample += A->phaser[(A->phasex - A->iphase + 1024) & 1023];
398
+ A->phasex = (A->phasex + 1) & 1023;
399
+
400
+ ssample += sample * A->volume;
401
+ }
402
+ ssample = ssample / 8 * B->volume;
403
+ ssample *= 2.0f * A->params.volume;
404
+
405
+ if (ssample > 1.0f) ssample = 1.0f;
406
+ if (ssample < -1.0f) ssample = -1.0f;
407
+ allsample += ssample;
408
+ }
409
+ if (moreframes == 0)
410
+ B->state = BLOOPS_STOP;
411
+ }
412
+
413
+ *buffer++ = allsample;
414
+ }
415
+ }
416
+
417
+ static int bloops_port_callback(const void *inputBuffer, void *outputBuffer,
418
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo,
419
+ PaStreamCallbackFlags statusFlags, void *data)
420
+ {
421
+ float *out = (float*)outputBuffer;
422
+ bloops_synth(framesPerBuffer, out);
423
+ return paContinue;
424
+ }
425
+
426
+ void
427
+ bloops_play(bloops *B)
428
+ {
429
+ int i;
430
+
431
+ for (i = 0; i < BLOOPS_MAX_TRACKS; i++) {
432
+ bloopsavoice *A;
433
+ A = &B->voices[i];
434
+ if (A->track != NULL) {
435
+ memcpy(&A->params, &A->track->params, sizeof(bloopsaparams));
436
+ bloops_reset_voice(A);
437
+ bloops_start_voice(A);
438
+ A->frames = 0;
439
+ A->nextnote[0] = 0;
440
+ A->nextnote[1] = 0;
441
+ }
442
+ }
443
+
444
+ bloops_remove(B);
445
+ for (i = 0; i < BLOOPS_MAX_CHANNELS; i++) {
446
+ if (MIXER->B[i] == NULL || MIXER->B[i]->state == BLOOPS_STOP) {
447
+ bloops_ref(B);
448
+ if (MIXER->B[i] != NULL) {
449
+ bloops_destroy(MIXER->B[i]);
450
+ }
451
+ MIXER->B[i] = B;
452
+ break;
453
+ }
454
+ }
455
+
456
+ B->state = BLOOPS_PLAY;
457
+ if (MIXER->stream == NULL) {
458
+ Pa_OpenDefaultStream(&MIXER->stream, 0, 1, paFloat32,
459
+ SAMPLE_RATE, 512, bloops_port_callback, B);
460
+ Pa_StartStream(MIXER->stream);
461
+ }
462
+ }
463
+
464
+ void
465
+ bloops_stop(bloops *B)
466
+ {
467
+ int i, stopall = 1;
468
+ B->state = BLOOPS_STOP;
469
+ for (i = 0; i < BLOOPS_MAX_CHANNELS; i++)
470
+ if (MIXER->B[i] != NULL && MIXER->B[i]->state != BLOOPS_STOP)
471
+ stopall = 0;
472
+
473
+ if (stopall)
474
+ {
475
+ Pa_StopStream(MIXER->stream);
476
+ Pa_CloseStream(MIXER->stream);
477
+ MIXER->stream = NULL;
478
+ }
479
+ }
480
+
481
+ bloopsaphone *
482
+ bloops_square()
483
+ {
484
+ bloopsaphone *P = (bloopsaphone *)calloc(sizeof(bloopsaphone), 1);
485
+ P->refcount = 1;
486
+ P->params.type = BLOOPS_SQUARE;
487
+ P->params.volume = 0.5f;
488
+ P->params.sustain = 0.3f;
489
+ P->params.decay = 0.4f;
490
+ P->params.freq = 0.3f;
491
+ P->params.lpf = 1.0f;
492
+ return P;
493
+ }
494
+
495
+ static int bloops_open = 0;
496
+
497
+ bloops *
498
+ bloops_new()
499
+ {
500
+ int i;
501
+ bloops *B = (bloops *)malloc(sizeof(bloops));
502
+ B->refcount = 1;
503
+ B->volume = 0.10f;
504
+ B->tempo = 120;
505
+ B->state = BLOOPS_STOP;
506
+ for (i = 0; i < BLOOPS_MAX_TRACKS; i++) {
507
+ B->voices[i].track = NULL;
508
+ }
509
+
510
+ if (MIXER == NULL)
511
+ MIXER = (bloopsmix *)calloc(sizeof(bloopsmix), 1);
512
+
513
+ if (!bloops_open++)
514
+ {
515
+ srand(time(NULL));
516
+ bloops_lock_init(&LOCK);
517
+ Pa_Initialize();
518
+ }
519
+
520
+ return B;
521
+ }
522
+
523
+ void
524
+ bloops_ref(bloops *B)
525
+ {
526
+ B->refcount++;
527
+ }
528
+
529
+ void
530
+ bloops_destroy(bloops *B)
531
+ {
532
+ if (--B->refcount) {
533
+ return;
534
+ }
535
+
536
+ bloops_remove(B);
537
+ free((void *)B);
538
+
539
+ if (!--bloops_open)
540
+ {
541
+ Pa_Terminate();
542
+ bloops_lock_finalize(&LOCK);
543
+ if (MIXER != NULL)
544
+ free(MIXER);
545
+ MIXER = NULL;
546
+ }
547
+ }
548
+
549
+ static void bloops_notes_destroy(bloopsanote *notes, int nlen)
550
+ {
551
+ bloopsafx *fx, *n;
552
+ int i;
553
+
554
+ for (i = 0; i < nlen; i++) {
555
+ n = fx = notes[i].FX;
556
+ while ((fx = n)) {
557
+ n = fx->next;
558
+ free(fx);
559
+ }
560
+ }
561
+
562
+ free(notes);
563
+ }
564
+
565
+ void
566
+ bloops_track_ref(bloopsatrack *track)
567
+ {
568
+ track->refcount++;
569
+ }
570
+
571
+ void
572
+ bloops_track_destroy(bloopsatrack *track)
573
+ {
574
+ if (--track->refcount) {
575
+ return;
576
+ }
577
+ if (track->notes != NULL) {
578
+ bloops_notes_destroy(track->notes, track->nlen);
579
+ }
580
+ free(track);
581
+ }
582
+
583
+ void bloops_sound_copy(bloopsaphone *dest, bloopsaphone const *src) {
584
+ memcpy(&dest->params, &src->params, sizeof(bloopsaparams));
585
+ }
586
+
587
+ void bloops_sound_ref(bloopsaphone *sound) {
588
+ sound->refcount++;
589
+ }
590
+
591
+ void bloops_sound_destroy(bloopsaphone *sound) {
592
+ if (--sound->refcount) {
593
+ return;
594
+ }
595
+ free(sound);
596
+ }