viking-bloopsaphone 0.4 → 0.4.1
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/README +8 -13
- data/c/bloopsaphone.c +327 -440
- data/c/bloopsaphone.h +23 -82
- data/c/notation.c +186 -633
- data/ext/ruby/extconf.rb +3 -4
- data/ext/ruby/rubyext.c +23 -63
- data/ext/ruby/test.rb +3 -18
- data/ext/ruby/test_record.rb +24 -0
- metadata +10 -14
- data/c/threads.h +0 -46
- data/sounds/dart.blu +0 -10
- data/sounds/error.blu +0 -13
- data/sounds/ice.blu +0 -5
- data/sounds/jump.blu +0 -8
- data/sounds/pogo.blu +0 -19
- data/sounds/stun.blu +0 -6
data/README
CHANGED
@@ -17,6 +17,9 @@
|
|
17
17
|
a rather light cross-platform audio lib.
|
18
18
|
<http://www.portaudio.com/>
|
19
19
|
|
20
|
+
it also records to a wav file using
|
21
|
+
libsndfile.
|
22
|
+
|
20
23
|
right now i'm only including ruby
|
21
24
|
bindings. you are welcome to contribute
|
22
25
|
code to hook up to other languages,
|
@@ -82,20 +85,12 @@
|
|
82
85
|
|
83
86
|
aptitude install portaudio19-dev
|
84
87
|
|
85
|
-
|
86
|
-
|
87
|
-
<http://www.portaudio.com/archives/pa_stable_v19_20071207.tar.gz>
|
88
|
-
|
89
|
-
Like this:
|
90
|
-
|
91
|
-
$ tar xzvf pa_stable_v19_20071207.tar.gz
|
92
|
-
$ cd portaudio
|
93
|
-
$ ./configure
|
94
|
-
$ make
|
95
|
-
$ sudo make install
|
88
|
+
Under MacPorts, you may need to add
|
89
|
+
/opt/local to your make settings:
|
96
90
|
|
97
|
-
|
98
|
-
|
91
|
+
make CFLAGS="-I/opt/local/include" \
|
92
|
+
LDFLAGS="-L/opt/local/lib" \
|
93
|
+
ruby
|
99
94
|
|
100
95
|
~
|
101
96
|
|
data/c/bloopsaphone.c
CHANGED
@@ -2,50 +2,27 @@
|
|
2
2
|
// bloopsaphone.c
|
3
3
|
// the chiptune maker for portaudio
|
4
4
|
// (with bindings for ruby)
|
5
|
-
//
|
5
|
+
//
|
6
6
|
// (c) 2009 why the lucky stiff
|
7
7
|
// See COPYING for the license
|
8
8
|
//
|
9
9
|
#include <stdio.h>
|
10
10
|
#include <stdlib.h>
|
11
|
-
#include <stddef.h>
|
12
11
|
#include <string.h>
|
13
12
|
#include <time.h>
|
14
13
|
#include <math.h>
|
15
14
|
#include <portaudio.h>
|
15
|
+
#include <sndfile.h>
|
16
16
|
#include <unistd.h>
|
17
17
|
#include "bloopsaphone.h"
|
18
|
-
#include "threads.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
18
|
|
26
19
|
#define SAMPLE_RATE 44100
|
20
|
+
#define FRAMES_PER_BUFFER 512
|
27
21
|
#define rnd(n) (rand() % (n + 1))
|
28
22
|
#define tempo2frames(tempo) ((float)SAMPLE_RATE / (tempo / 60.0f))
|
29
23
|
#define PI 3.14159265f
|
30
24
|
|
31
|
-
|
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);
|
25
|
+
static int bloops_open = 0;
|
49
26
|
|
50
27
|
float
|
51
28
|
frnd(float range)
|
@@ -53,88 +30,74 @@ frnd(float range)
|
|
53
30
|
return (float)rnd(10000) / 10000 * range;
|
54
31
|
}
|
55
32
|
|
56
|
-
|
57
|
-
|
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)
|
33
|
+
void
|
34
|
+
bloops_ready(bloops *B, bloopsatrack *A, unsigned char init)
|
71
35
|
{
|
72
|
-
A->period = 100.0 / (A->
|
73
|
-
A->maxperiod = 100.0 / (A->
|
74
|
-
A->slide = 1.0 - pow((double)A->
|
75
|
-
A->dslide = -pow((double)A->
|
76
|
-
A->square = 0.5f - A->
|
77
|
-
A->sweep = -A->
|
78
|
-
if (A->
|
79
|
-
A->arp = 1.0 - pow((double)A->
|
36
|
+
A->period = 100.0 / (A->P->freq * A->P->freq + 0.001);
|
37
|
+
A->maxperiod = 100.0 / (A->P->limit * A->P->limit + 0.001);
|
38
|
+
A->slide = 1.0 - pow((double)A->P->slide, 3.0) * 0.01;
|
39
|
+
A->dslide = -pow((double)A->P->dslide, 3.0) * 0.000001;
|
40
|
+
A->square = 0.5f - A->P->square * 0.5f;
|
41
|
+
A->sweep = -A->P->sweep * 0.00005f;
|
42
|
+
if (A->P->arp >= 0.0f)
|
43
|
+
A->arp = 1.0 - pow((double)A->P->arp, 2.0) * 0.9;
|
80
44
|
else
|
81
|
-
A->arp = 1.0 + pow((double)A->
|
45
|
+
A->arp = 1.0 + pow((double)A->P->arp, 2.0) * 10.0;
|
82
46
|
A->atime = 0;
|
83
|
-
A->alimit = (int)(pow(1.0f - A->
|
84
|
-
if (A->
|
47
|
+
A->alimit = (int)(pow(1.0f - A->P->aspeed, 2.0f) * 20000 + 32);
|
48
|
+
if (A->P->aspeed == 1.0f)
|
85
49
|
A->alimit = 0;
|
86
|
-
}
|
87
50
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
51
|
+
if (init)
|
52
|
+
{
|
53
|
+
int i = 0;
|
54
|
+
A->phase = 0;
|
55
|
+
A->filter[0] = 0.0f;
|
56
|
+
A->filter[1] = 0.0f;
|
57
|
+
A->filter[2] = pow(A->P->lpf, 3.0f) * 0.1f;
|
58
|
+
A->filter[3] = 1.0f + A->P->lsweep * 0.0001f;
|
59
|
+
A->filter[4] = 5.0f / (1.0f + pow(A->P->resonance, 2.0f) * 20.0f) * (0.01f + A->filter[2]);
|
60
|
+
if (A->filter[4] > 0.8f) A->filter[4] = 0.8f;
|
61
|
+
A->filter[5] = 0.0f;
|
62
|
+
A->filter[6] = pow(A->P->hpf, 2.0f) * 0.1f;
|
63
|
+
A->filter[7] = 1.0 + A->P->hsweep * 0.0003f;
|
64
|
+
|
65
|
+
A->vibe = 0.0f;
|
66
|
+
A->vspeed = pow(A->P->vspeed, 2.0f) * 0.01f;
|
67
|
+
A->vdelay = A->P->vibe * 0.5f;
|
68
|
+
|
69
|
+
A->volume = 0.0f;
|
70
|
+
A->stage = 0;
|
71
|
+
A->time = 0;
|
72
|
+
A->length[0] = (int)(A->P->attack * A->P->attack * 100000.0f);
|
73
|
+
A->length[1] = (int)(A->P->sustain * A->P->sustain * 100000.0f);
|
74
|
+
A->length[2] = (int)(A->P->decay * A->P->decay * 100000.0f);
|
75
|
+
|
76
|
+
A->fphase = pow(A->P->phase, 2.0f) * 1020.0f;
|
77
|
+
if (A->P->phase < 0.0f) A->fphase = -A->fphase;
|
78
|
+
A->dphase = pow(A->P->psweep, 2.0f) * 1.0f;
|
79
|
+
if (A->P->psweep < 0.0f) A->dphase = -A->dphase;
|
80
|
+
A->iphase = abs((int)A->fphase);
|
81
|
+
A->phasex = 0;
|
82
|
+
|
83
|
+
memset(A->phaser, 0, 1024 * sizeof(float));
|
84
|
+
for (i = 0; i < 32; i++)
|
85
|
+
A->noise[i] = frnd(2.0f) - 1.0f;
|
86
|
+
|
87
|
+
A->repeat = 0;
|
88
|
+
A->limit = (int)(pow(1.0f - A->P->repeat, 2.0f) * 20000 + 32);
|
89
|
+
if (A->P->repeat == 0.0f)
|
90
|
+
A->limit = 0;
|
91
|
+
A->playing = BLOOPS_PLAY;
|
92
|
+
}
|
129
93
|
}
|
130
94
|
|
131
95
|
void
|
132
96
|
bloops_clear(bloops *B)
|
133
97
|
{
|
134
98
|
int i;
|
135
|
-
for (i = 0; i < BLOOPS_MAX_TRACKS; i++)
|
136
|
-
|
137
|
-
}
|
99
|
+
for (i = 0; i < BLOOPS_MAX_TRACKS; i++)
|
100
|
+
B->tracks[i] = NULL;
|
138
101
|
}
|
139
102
|
|
140
103
|
void
|
@@ -144,272 +107,207 @@ bloops_tempo(bloops *B, int tempo)
|
|
144
107
|
}
|
145
108
|
|
146
109
|
void
|
147
|
-
|
110
|
+
bloops_track_at(bloops *B, bloopsatrack *track, int num)
|
148
111
|
{
|
149
|
-
|
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
|
-
}
|
112
|
+
B->tracks[num] = track;
|
178
113
|
}
|
179
114
|
|
180
115
|
int
|
181
116
|
bloops_is_done(bloops *B)
|
182
117
|
{
|
183
|
-
return B->
|
118
|
+
return B->play == BLOOPS_STOP;
|
184
119
|
}
|
185
120
|
|
186
121
|
static void
|
187
|
-
bloops_synth(int length, float* buffer)
|
122
|
+
bloops_synth(bloops *B, int length, float* buffer)
|
188
123
|
{
|
189
|
-
int
|
124
|
+
int t, i, si;
|
190
125
|
|
191
126
|
while (length--)
|
192
127
|
{
|
193
128
|
int samplecount = 0;
|
129
|
+
int moreframes = 0;
|
194
130
|
float allsample = 0.0f;
|
195
131
|
|
196
|
-
for (
|
132
|
+
for (t = 0; t < BLOOPS_MAX_TRACKS; t++)
|
197
133
|
{
|
198
|
-
|
199
|
-
|
200
|
-
if (B == NULL)
|
134
|
+
bloopsatrack *A = B->tracks[t];
|
135
|
+
if (A == NULL)
|
201
136
|
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
137
|
|
209
|
-
|
138
|
+
if (A->notes)
|
139
|
+
{
|
140
|
+
int frames = 0;
|
141
|
+
for (i = 0; i < A->nlen; i++)
|
210
142
|
{
|
211
|
-
|
143
|
+
bloopsanote *note = &A->notes[i];
|
144
|
+
if (A->frames == frames)
|
212
145
|
{
|
213
|
-
|
214
|
-
{
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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));
|
146
|
+
float freq = bloops_note_freq(note->tone, (int)note->octave);
|
147
|
+
if (freq == 0.0f) {
|
148
|
+
A->period = 0.0f;
|
149
|
+
A->playing = BLOOPS_STOP;
|
150
|
+
} else {
|
151
|
+
bloops_ready(B, A, 1);
|
152
|
+
A->period = 100.0 / (freq * freq + 0.001);
|
257
153
|
}
|
258
|
-
A->nextnote[1]++;
|
259
154
|
}
|
260
|
-
|
261
|
-
|
262
|
-
|
155
|
+
else if (A->frames < frames)
|
156
|
+
break;
|
157
|
+
frames += (int)(tempo2frames(B->tempo) * (4.0f / note->duration));
|
263
158
|
}
|
264
|
-
|
265
|
-
|
159
|
+
|
160
|
+
if (A->frames <= frames)
|
266
161
|
moreframes++;
|
267
|
-
|
162
|
+
}
|
163
|
+
else
|
164
|
+
{
|
165
|
+
moreframes++;
|
166
|
+
}
|
268
167
|
|
269
|
-
|
168
|
+
A->frames++;
|
270
169
|
|
271
|
-
|
272
|
-
|
170
|
+
if (A->playing == BLOOPS_STOP)
|
171
|
+
continue;
|
273
172
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
173
|
+
samplecount++;
|
174
|
+
A->repeat++;
|
175
|
+
if (A->limit != 0 && A->repeat >= A->limit)
|
176
|
+
{
|
177
|
+
A->repeat = 0;
|
178
|
+
bloops_ready(B, A, 0);
|
179
|
+
}
|
281
180
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
181
|
+
A->atime++;
|
182
|
+
if (A->alimit != 0 && A->atime >= A->alimit)
|
183
|
+
{
|
184
|
+
A->alimit = 0;
|
185
|
+
A->period *= A->arp;
|
186
|
+
}
|
288
187
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
188
|
+
A->slide += A->dslide;
|
189
|
+
A->period *= A->slide;
|
190
|
+
if (A->period > A->maxperiod)
|
191
|
+
{
|
192
|
+
A->period = A->maxperiod;
|
193
|
+
if (A->P->limit > 0.0f)
|
194
|
+
A->playing = BLOOPS_STOP;
|
195
|
+
}
|
297
196
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
197
|
+
float rfperiod = A->period;
|
198
|
+
if (A->vdelay > 0.0f)
|
199
|
+
{
|
200
|
+
A->vibe += A->vspeed;
|
201
|
+
rfperiod = A->period * (1.0 + sin(A->vibe) * A->vdelay);
|
202
|
+
}
|
203
|
+
|
204
|
+
int period = (int)rfperiod;
|
205
|
+
if (period < 8) period = 8;
|
206
|
+
A->square += A->sweep;
|
207
|
+
if(A->square < 0.0f) A->square = 0.0f;
|
208
|
+
if(A->square > 0.5f) A->square = 0.5f;
|
304
209
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
210
|
+
A->time++;
|
211
|
+
if (A->time > A->length[A->stage])
|
212
|
+
{
|
213
|
+
A->time = 0;
|
214
|
+
A->stage++;
|
215
|
+
if (A->stage == 3)
|
216
|
+
A->playing = BLOOPS_STOP;
|
217
|
+
}
|
218
|
+
|
219
|
+
switch (A->stage) {
|
220
|
+
case 0:
|
221
|
+
A->volume = (float)A->time / A->length[0];
|
222
|
+
break;
|
223
|
+
case 1:
|
224
|
+
A->volume = 1.0f + pow(1.0f - (float)A->time / A->length[1], 1.0f) * 2.0f * A->P->punch;
|
225
|
+
break;
|
226
|
+
case 2:
|
227
|
+
A->volume = 1.0f - (float)A->time / A->length[2];
|
228
|
+
break;
|
229
|
+
}
|
230
|
+
|
231
|
+
A->fphase += A->dphase;
|
232
|
+
A->iphase = abs((int)A->fphase);
|
233
|
+
if (A->iphase > 1023) A->iphase = 1023;
|
310
234
|
|
311
|
-
|
312
|
-
|
235
|
+
if (A->filter[7] != 0.0f)
|
236
|
+
{
|
237
|
+
A->filter[6] *= A->filter[7];
|
238
|
+
if (A->filter[6] < 0.00001f) A->filter[6] = 0.00001f;
|
239
|
+
if (A->filter[6] > 0.1f) A->filter[6] = 0.1f;
|
240
|
+
}
|
241
|
+
|
242
|
+
float ssample = 0.0f;
|
243
|
+
for (si = 0; si < 8; si++)
|
244
|
+
{
|
245
|
+
float sample = 0.0f;
|
246
|
+
A->phase++;
|
247
|
+
if (A->phase >= period)
|
313
248
|
{
|
314
|
-
A->
|
315
|
-
A->
|
316
|
-
|
317
|
-
|
249
|
+
A->phase %= period;
|
250
|
+
if (A->P->type == BLOOPS_NOISE)
|
251
|
+
for (i = 0; i < 32; i++)
|
252
|
+
A->noise[i] = frnd(2.0f) - 1.0f;
|
318
253
|
}
|
319
254
|
|
320
|
-
|
321
|
-
|
322
|
-
|
255
|
+
float fp = (float)A->phase / period;
|
256
|
+
switch (A->P->type)
|
257
|
+
{
|
258
|
+
case BLOOPS_SQUARE:
|
259
|
+
if (fp < A->square)
|
260
|
+
sample = 0.5f;
|
261
|
+
else
|
262
|
+
sample = -0.5f;
|
263
|
+
break;
|
264
|
+
case BLOOPS_SAWTOOTH:
|
265
|
+
sample = 1.0f - fp * 2;
|
323
266
|
break;
|
324
|
-
case
|
325
|
-
|
267
|
+
case BLOOPS_SINE:
|
268
|
+
sample = (float)sin(fp * 2 * PI);
|
326
269
|
break;
|
327
|
-
case
|
328
|
-
|
270
|
+
case BLOOPS_NOISE:
|
271
|
+
sample = A->noise[A->phase * 32 / period];
|
329
272
|
break;
|
330
273
|
}
|
331
274
|
|
332
|
-
|
333
|
-
A->
|
334
|
-
if (A->
|
335
|
-
|
336
|
-
if (A->
|
275
|
+
float pp = A->filter[0];
|
276
|
+
A->filter[2] *= A->filter[3];
|
277
|
+
if (A->filter[2] < 0.0f) A->filter[2] = 0.0f;
|
278
|
+
if (A->filter[2] > 0.1f) A->filter[2] = 0.1f;
|
279
|
+
if (A->P->lpf != 1.0f)
|
337
280
|
{
|
338
|
-
A->filter[
|
339
|
-
|
340
|
-
if (A->filter[6] > 0.1f) A->filter[6] = 0.1f;
|
281
|
+
A->filter[1] += (sample - A->filter[0]) * A->filter[2];
|
282
|
+
A->filter[1] -= A->filter[1] * A->filter[4];
|
341
283
|
}
|
342
|
-
|
343
|
-
float ssample = 0.0f;
|
344
|
-
for (si = 0; si < 8; si++)
|
284
|
+
else
|
345
285
|
{
|
346
|
-
|
347
|
-
A->
|
348
|
-
|
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];
|
286
|
+
A->filter[0] = sample;
|
287
|
+
A->filter[1] = 0.0f;
|
288
|
+
}
|
289
|
+
A->filter[0] += A->filter[1];
|
395
290
|
|
396
|
-
|
397
|
-
|
398
|
-
|
291
|
+
A->filter[5] += A->filter[0] - pp;
|
292
|
+
A->filter[5] -= A->filter[5] * A->filter[6];
|
293
|
+
sample = A->filter[5];
|
399
294
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
ssample *= 2.0f * A->params.volume;
|
295
|
+
A->phaser[A->phasex & 1023] = sample;
|
296
|
+
sample += A->phaser[(A->phasex - A->iphase + 1024) & 1023];
|
297
|
+
A->phasex = (A->phasex + 1) & 1023;
|
404
298
|
|
405
|
-
|
406
|
-
if (ssample < -1.0f) ssample = -1.0f;
|
407
|
-
allsample += ssample;
|
299
|
+
ssample += sample * A->volume;
|
408
300
|
}
|
409
|
-
|
410
|
-
|
301
|
+
ssample = ssample / 8 * B->volume;
|
302
|
+
ssample *= 2.0f * A->P->volume;
|
303
|
+
|
304
|
+
if (ssample > 1.0f) ssample = 1.0f;
|
305
|
+
if (ssample < -1.0f) ssample = -1.0f;
|
306
|
+
allsample += ssample;
|
411
307
|
}
|
412
308
|
|
309
|
+
if (moreframes == 0)
|
310
|
+
B->play = BLOOPS_STOP;
|
413
311
|
*buffer++ = allsample;
|
414
312
|
}
|
415
313
|
}
|
@@ -418,179 +316,168 @@ static int bloops_port_callback(const void *inputBuffer, void *outputBuffer,
|
|
418
316
|
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo,
|
419
317
|
PaStreamCallbackFlags statusFlags, void *data)
|
420
318
|
{
|
319
|
+
int i;
|
421
320
|
float *out = (float*)outputBuffer;
|
422
|
-
|
423
|
-
|
321
|
+
bloops *B = (bloops *)data;
|
322
|
+
|
323
|
+
if (B->play == BLOOPS_PLAY) {
|
324
|
+
bloops_synth(B, framesPerBuffer, out);
|
325
|
+
}
|
326
|
+
else
|
327
|
+
for(i = 0; i < framesPerBuffer; i++)
|
328
|
+
*out++ = 0.0f;
|
329
|
+
|
330
|
+
return 0;
|
424
331
|
}
|
425
332
|
|
426
333
|
void
|
427
|
-
|
334
|
+
bloops_prep(bloops *B)
|
428
335
|
{
|
429
336
|
int i;
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
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;
|
337
|
+
for (i = 0; i < BLOOPS_MAX_TRACKS; i++)
|
338
|
+
if (B->tracks[i] != NULL) {
|
339
|
+
bloops_ready(B, B->tracks[i], 1);
|
340
|
+
B->tracks[i]->frames = 0;
|
441
341
|
}
|
442
|
-
|
342
|
+
B->play = BLOOPS_PLAY;
|
343
|
+
}
|
443
344
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
345
|
+
void
|
346
|
+
bloops_play(bloops *B)
|
347
|
+
{
|
348
|
+
bloops_prep(B);
|
349
|
+
|
350
|
+
if (B->stream == NULL) {
|
351
|
+
if (!bloops_open++)
|
352
|
+
{
|
353
|
+
srand(time(NULL));
|
354
|
+
Pa_Initialize();
|
453
355
|
}
|
454
|
-
}
|
455
356
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
SAMPLE_RATE, 512, bloops_port_callback, B);
|
460
|
-
Pa_StartStream(MIXER->stream);
|
357
|
+
Pa_OpenDefaultStream(&B->stream, 0, 1, paFloat32,
|
358
|
+
SAMPLE_RATE, FRAMES_PER_BUFFER, bloops_port_callback, B);
|
359
|
+
Pa_StartStream(B->stream);
|
461
360
|
}
|
462
361
|
}
|
463
362
|
|
464
|
-
|
465
|
-
|
363
|
+
int
|
364
|
+
bloops_record(bloops *B, char *path)
|
466
365
|
{
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
{
|
475
|
-
|
476
|
-
|
477
|
-
|
366
|
+
// setup sndfile
|
367
|
+
SF_INFO info;
|
368
|
+
info.samplerate = SAMPLE_RATE;
|
369
|
+
info.channels = 1;
|
370
|
+
info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
|
371
|
+
|
372
|
+
SNDFILE *sndfile = sf_open(path, SFM_WRITE, &info);
|
373
|
+
if (sndfile) {
|
374
|
+
bloops_prep(B);
|
375
|
+
|
376
|
+
float *buffer = (float *)malloc(sizeof(float)*FRAMES_PER_BUFFER);
|
377
|
+
while(!bloops_is_done(B)) {
|
378
|
+
bloops_synth(B, FRAMES_PER_BUFFER, buffer);
|
379
|
+
sf_write_float(sndfile, buffer, FRAMES_PER_BUFFER);
|
380
|
+
}
|
381
|
+
sf_close(sndfile);
|
382
|
+
free(buffer);
|
383
|
+
return 0;
|
478
384
|
}
|
385
|
+
return 1;
|
479
386
|
}
|
480
387
|
|
481
388
|
bloopsaphone *
|
482
389
|
bloops_square()
|
483
390
|
{
|
484
391
|
bloopsaphone *P = (bloopsaphone *)calloc(sizeof(bloopsaphone), 1);
|
485
|
-
P->
|
486
|
-
P->
|
487
|
-
P->
|
488
|
-
P->
|
489
|
-
P->
|
490
|
-
P->
|
491
|
-
P->params.lpf = 1.0f;
|
392
|
+
P->type = BLOOPS_SQUARE;
|
393
|
+
P->volume = 0.5f;
|
394
|
+
P->sustain = 0.3f;
|
395
|
+
P->decay = 0.4f;
|
396
|
+
P->freq = 0.3f;
|
397
|
+
P->lpf = 1.0f;
|
492
398
|
return P;
|
493
399
|
}
|
494
400
|
|
495
|
-
|
401
|
+
bloopsaphone *
|
402
|
+
bloops_load(char* filename)
|
403
|
+
{
|
404
|
+
bloopsaphone *P = NULL;
|
405
|
+
FILE* file = fopen(filename, "rb");
|
406
|
+
if (!file) return NULL;
|
407
|
+
|
408
|
+
int version = 0;
|
409
|
+
fread(&version, 1, sizeof(int), file);
|
410
|
+
if (version != 102)
|
411
|
+
return NULL;
|
412
|
+
|
413
|
+
P = (bloopsaphone *)malloc(sizeof(bloopsaphone));
|
414
|
+
fread(&P->type, 1, sizeof(int), file);
|
415
|
+
|
416
|
+
P->volume = 0.5f;
|
417
|
+
fread(&P->volume, 1, sizeof(float), file);
|
418
|
+
fread(&P->freq, 1, sizeof(float), file);
|
419
|
+
fread(&P->limit, 1, sizeof(float), file);
|
420
|
+
fread(&P->slide, 1, sizeof(float), file);
|
421
|
+
fread(&P->dslide, 1, sizeof(float), file);
|
422
|
+
fread(&P->square, 1, sizeof(float), file);
|
423
|
+
fread(&P->sweep, 1, sizeof(float), file);
|
424
|
+
|
425
|
+
fread(&P->vibe, 1, sizeof(float), file);
|
426
|
+
fread(&P->vspeed, 1, sizeof(float), file);
|
427
|
+
fread(&P->vdelay, 1, sizeof(float), file);
|
428
|
+
|
429
|
+
fread(&P->attack, 1, sizeof(float), file);
|
430
|
+
fread(&P->sustain, 1, sizeof(float), file);
|
431
|
+
fread(&P->decay, 1, sizeof(float), file);
|
432
|
+
fread(&P->punch, 1, sizeof(float), file);
|
433
|
+
|
434
|
+
fread(&P->resonance, 1, sizeof(float), file);
|
435
|
+
fread(&P->lpf, 1, sizeof(float), file);
|
436
|
+
fread(&P->lsweep, 1, sizeof(float), file);
|
437
|
+
fread(&P->hpf, 1, sizeof(float), file);
|
438
|
+
fread(&P->hsweep, 1, sizeof(float), file);
|
439
|
+
|
440
|
+
fread(&P->phase, 1, sizeof(float), file);
|
441
|
+
fread(&P->psweep, 1, sizeof(float), file);
|
442
|
+
|
443
|
+
fread(&P->repeat, 1, sizeof(float), file);
|
444
|
+
fread(&P->arp, 1, sizeof(float), file);
|
445
|
+
fread(&P->aspeed, 1, sizeof(float), file);
|
446
|
+
|
447
|
+
fclose(file);
|
448
|
+
return P;
|
449
|
+
}
|
496
450
|
|
497
451
|
bloops *
|
498
|
-
bloops_new()
|
452
|
+
bloops_new(char *path)
|
499
453
|
{
|
500
|
-
int i;
|
501
454
|
bloops *B = (bloops *)malloc(sizeof(bloops));
|
502
|
-
B->refcount = 1;
|
503
455
|
B->volume = 0.10f;
|
504
456
|
B->tempo = 120;
|
505
|
-
B->
|
506
|
-
|
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
|
-
}
|
457
|
+
B->play = BLOOPS_STOP;
|
458
|
+
bloops_clear(B);
|
519
459
|
|
520
460
|
return B;
|
521
461
|
}
|
522
462
|
|
523
|
-
void
|
524
|
-
bloops_ref(bloops *B)
|
525
|
-
{
|
526
|
-
B->refcount++;
|
527
|
-
}
|
528
|
-
|
529
463
|
void
|
530
464
|
bloops_destroy(bloops *B)
|
531
465
|
{
|
532
|
-
if (
|
533
|
-
|
466
|
+
if (B->stream != NULL) {
|
467
|
+
Pa_StopStream(B->stream);
|
468
|
+
Pa_CloseStream(B->stream);
|
534
469
|
}
|
535
470
|
|
536
|
-
bloops_remove(B);
|
537
471
|
free((void *)B);
|
538
472
|
|
539
473
|
if (!--bloops_open)
|
540
|
-
{
|
541
474
|
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
475
|
}
|
570
476
|
|
571
477
|
void
|
572
478
|
bloops_track_destroy(bloopsatrack *track)
|
573
479
|
{
|
574
|
-
if (
|
575
|
-
|
576
|
-
}
|
577
|
-
if (track->notes != NULL) {
|
578
|
-
bloops_notes_destroy(track->notes, track->nlen);
|
579
|
-
}
|
480
|
+
if (track->notes != NULL)
|
481
|
+
free(track->notes);
|
580
482
|
free(track);
|
581
483
|
}
|
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
|
-
}
|