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 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
- To build from source isn't too bad.
86
- Download PortAudio 1.9 and build it.
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
- Then go back to Bloopsaphone and do
98
- a `make ruby`.
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
- #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);
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
- 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)
33
+ void
34
+ bloops_ready(bloops *B, bloopsatrack *A, unsigned char init)
71
35
  {
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;
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->params.arp, 2.0) * 10.0;
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->params.aspeed, 2.0f) * 20000 + 32);
84
- if (A->params.aspeed == 1.0f)
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
- 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;
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
- bloops_set_track_at(B, NULL, i);
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
- bloops_set_track_at(bloops *B, bloopsatrack *track, int num)
110
+ bloops_track_at(bloops *B, bloopsatrack *track, int num)
148
111
  {
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
- }
112
+ B->tracks[num] = track;
178
113
  }
179
114
 
180
115
  int
181
116
  bloops_is_done(bloops *B)
182
117
  {
183
- return B->state == BLOOPS_STOP;
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 bi, t, i, si;
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 (bi = 0; bi < BLOOPS_MAX_CHANNELS; bi++)
132
+ for (t = 0; t < BLOOPS_MAX_TRACKS; t++)
197
133
  {
198
- int moreframes = 0;
199
- bloops *B = MIXER->B[bi];
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
- if (track->notes)
138
+ if (A->notes)
139
+ {
140
+ int frames = 0;
141
+ for (i = 0; i < A->nlen; i++)
210
142
  {
211
- if (A->frames == A->nextnote[0])
143
+ bloopsanote *note = &A->notes[i];
144
+ if (A->frames == frames)
212
145
  {
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));
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
- if (A->nextnote[1] <= track->nlen)
262
- moreframes++;
155
+ else if (A->frames < frames)
156
+ break;
157
+ frames += (int)(tempo2frames(B->tempo) * (4.0f / note->duration));
263
158
  }
264
- else
265
- {
159
+
160
+ if (A->frames <= frames)
266
161
  moreframes++;
267
- }
162
+ }
163
+ else
164
+ {
165
+ moreframes++;
166
+ }
268
167
 
269
- A->frames++;
168
+ A->frames++;
270
169
 
271
- if (A->state == BLOOPS_STOP)
272
- continue;
170
+ if (A->playing == BLOOPS_STOP)
171
+ continue;
273
172
 
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
- }
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
- A->atime++;
283
- if (A->alimit != 0 && A->atime >= A->alimit)
284
- {
285
- A->alimit = 0;
286
- A->period *= A->arp;
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
- 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
- }
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
- 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
- }
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
- 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;
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
- A->time++;
312
- while (A->time >= A->length[A->stage])
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->time = 0;
315
- A->stage++;
316
- if (A->stage == 3)
317
- A->state = BLOOPS_STOP;
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
- switch (A->stage) {
321
- case 0:
322
- A->volume = (float)A->time / A->length[0];
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 1:
325
- A->volume = 1.0f + (1.0f - (float)A->time / A->length[1]) * 2.0f * A->params.punch;
267
+ case BLOOPS_SINE:
268
+ sample = (float)sin(fp * 2 * PI);
326
269
  break;
327
- case 2:
328
- A->volume = 1.0f - (float)A->time / A->length[2];
270
+ case BLOOPS_NOISE:
271
+ sample = A->noise[A->phase * 32 / period];
329
272
  break;
330
273
  }
331
274
 
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)
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[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;
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
- 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];
286
+ A->filter[0] = sample;
287
+ A->filter[1] = 0.0f;
288
+ }
289
+ A->filter[0] += A->filter[1];
395
290
 
396
- A->phaser[A->phasex & 1023] = sample;
397
- sample += A->phaser[(A->phasex - A->iphase + 1024) & 1023];
398
- A->phasex = (A->phasex + 1) & 1023;
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
- ssample += sample * A->volume;
401
- }
402
- ssample = ssample / 8 * B->volume;
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
- if (ssample > 1.0f) ssample = 1.0f;
406
- if (ssample < -1.0f) ssample = -1.0f;
407
- allsample += ssample;
299
+ ssample += sample * A->volume;
408
300
  }
409
- if (moreframes == 0)
410
- B->state = BLOOPS_STOP;
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
- bloops_synth(framesPerBuffer, out);
423
- return paContinue;
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
- bloops_play(bloops *B)
334
+ bloops_prep(bloops *B)
428
335
  {
429
336
  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;
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
- 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;
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
- 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);
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
- void
465
- bloops_stop(bloops *B)
363
+ int
364
+ bloops_record(bloops *B, char *path)
466
365
  {
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;
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->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;
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
- static int bloops_open = 0;
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->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
- }
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 (--B->refcount) {
533
- return;
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 (--track->refcount) {
575
- return;
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
- }