bloopsaphone 0.4
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/COPYING +27 -0
- data/README +164 -0
- data/c/bloopsaphone.c +443 -0
- data/c/bloopsaphone.h +94 -0
- data/c/notation.c +1209 -0
- data/ext/ruby/extconf.rb +13 -0
- data/ext/ruby/rubyext.c +282 -0
- data/ext/ruby/test.rb +26 -0
- data/ext/ruby/test_load.rb +25 -0
- data/sounds/dart.blu +10 -0
- data/sounds/error.blu +13 -0
- data/sounds/ice.blu +5 -0
- data/sounds/jump.blu +8 -0
- data/sounds/pogo.blu +19 -0
- data/sounds/stun.blu +6 -0
- metadata +70 -0
data/COPYING
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
:$: BLOOPSAPHONE :$:
|
3
|
+
Copyright (c) 2009 why the lucky stiff
|
4
|
+
Based on sfxr (c) 2007 Tomas Pettersson
|
5
|
+
(Also released under the MIT license)
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person
|
8
|
+
obtaining a copy of this software and associated documentation
|
9
|
+
files (the "Software"), to deal in the Software without restriction,
|
10
|
+
including without limitation the rights to use, copy, modify, merge,
|
11
|
+
publish, distribute, sublicense, and/or sell copies of the Software,
|
12
|
+
and to permit persons to whom the Software is furnished to do so,
|
13
|
+
subject to the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
19
|
+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
20
|
+
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
21
|
+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
22
|
+
SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
23
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
24
|
+
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
25
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26
|
+
SOFTWARE.
|
27
|
+
|
data/README
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
|
2
|
+
|~~ |~~
|
3
|
+
| |
|
4
|
+
:$: bloopsaphone :$:
|
5
|
+
`''''''''''''''''`
|
6
|
+
|
7
|
+
for writing chiptune-style songs
|
8
|
+
in c or ruby. you know: the sounds
|
9
|
+
of ataris, gameboys and the like.
|
10
|
+
|
11
|
+
~
|
12
|
+
|
13
|
+
-$- ABOUT
|
14
|
+
|
15
|
+
this is a small c library for sending
|
16
|
+
chiptunes through portaudio, which is
|
17
|
+
a rather light cross-platform audio lib.
|
18
|
+
<http://www.portaudio.com/>
|
19
|
+
|
20
|
+
right now i'm only including ruby
|
21
|
+
bindings. you are welcome to contribute
|
22
|
+
code to hook up to other languages,
|
23
|
+
though.
|
24
|
+
|
25
|
+
i wrote this for h-ety h.
|
26
|
+
<http://hacketyhack.net/>
|
27
|
+
|
28
|
+
i don't have binaries ready for this yet,
|
29
|
+
so if you're on windows or os x, you may
|
30
|
+
have to wait until HH comes out at ART
|
31
|
+
AND CODE. the tribulations you face.
|
32
|
+
|
33
|
+
~
|
34
|
+
|
35
|
+
-$- THE BLOOPSAPHONE THEME SONG
|
36
|
+
(in ruby)
|
37
|
+
|
38
|
+
require 'bloops'
|
39
|
+
|
40
|
+
# the bloops o' phone
|
41
|
+
b = Bloops.new
|
42
|
+
b.tempo = 320
|
43
|
+
|
44
|
+
# melodious
|
45
|
+
s1 = b.sound Bloops::SQUARE
|
46
|
+
s1.punch = 0.5
|
47
|
+
s1.sustain = 0.4
|
48
|
+
s1.decay = 0.2
|
49
|
+
s1.arp = 0.4
|
50
|
+
s1.aspeed = 0.6
|
51
|
+
s1.repeat = 0.6
|
52
|
+
s1.phase = 0.2
|
53
|
+
s1.psweep = 0.2
|
54
|
+
|
55
|
+
# beats
|
56
|
+
s2 = b.sound Bloops::NOISE
|
57
|
+
s2.punch = 0.5
|
58
|
+
s2.sustain = 0.2
|
59
|
+
s2.decay = 0.4
|
60
|
+
s2.slide = -0.4
|
61
|
+
s2.phase = 0.2
|
62
|
+
s2.psweep = 0.2
|
63
|
+
|
64
|
+
# the tracks
|
65
|
+
b.tune s1, "f#5 c6 e4 b6 g5 d6 4 f#5 e5 c5 b6 c6 d6 4 "
|
66
|
+
b.tune s2, "4 c6 4 b5 4 4 e4 4 c6 4 b5 4 4 e4"
|
67
|
+
|
68
|
+
# and away we go
|
69
|
+
b.play
|
70
|
+
sleep 1 while !b.stopped?
|
71
|
+
|
72
|
+
~
|
73
|
+
|
74
|
+
-$- BUILDING FOR RUBY
|
75
|
+
|
76
|
+
If Ruby is in your path and PortAudio 1.9
|
77
|
+
or greater is installed:
|
78
|
+
|
79
|
+
make ruby
|
80
|
+
|
81
|
+
To install PortAudio 1.9 under Ubuntu:
|
82
|
+
|
83
|
+
aptitude install portaudio19-dev
|
84
|
+
|
85
|
+
Under MacPorts, you may need to add
|
86
|
+
/opt/local to your make settings:
|
87
|
+
|
88
|
+
make CFLAGS="-I/opt/local/include" \
|
89
|
+
LDFLAGS="-L/opt/local/lib" \
|
90
|
+
ruby
|
91
|
+
|
92
|
+
~
|
93
|
+
|
94
|
+
-$- THE IDEALS,
|
95
|
+
|
96
|
+
-1- ASYNCHRONOUS.
|
97
|
+
You send it a song and it plays in
|
98
|
+
the background. You'll get an event
|
99
|
+
when it finishes.
|
100
|
+
|
101
|
+
-2- SMALL.
|
102
|
+
This is just a toy, I don't want it
|
103
|
+
to be very big and comprehensive.
|
104
|
+
Just to play little tunes with a
|
105
|
+
nostalgic arcade sound rather than
|
106
|
+
the CASIO-stylings of most MIDI.
|
107
|
+
|
108
|
+
-3- CUSTOM NOTATION.
|
109
|
+
Someone told me about Nokring, iMelody,
|
110
|
+
numbered musical notation and I did
|
111
|
+
some reading. They're little languages
|
112
|
+
for texting yourself a ringtone.
|
113
|
+
|
114
|
+
<http://en.wikipedia.org/wiki/Ring_Tone_Transfer_Language>
|
115
|
+
<http://homepage.mac.com/alvinmok/ericsson/emelody.html>
|
116
|
+
|
117
|
+
Bloopsaphone uses a variation on RTTTL.
|
118
|
+
|
119
|
+
Instead of commas, I use whitespace.
|
120
|
+
A rest is simply a number. A plus sign
|
121
|
+
moves everything up an octave. A minus
|
122
|
+
down an octave.
|
123
|
+
|
124
|
+
The Simpsons' Theme, for instance, would be:
|
125
|
+
|
126
|
+
32 + C E F# 8:A G E C - 8:A 8:F# 8:F# 8:F# 2:G
|
127
|
+
|
128
|
+
Which translates into:
|
129
|
+
|
130
|
+
* a 1/32nd note rest.
|
131
|
+
* change one octave up.
|
132
|
+
* C quarter note.
|
133
|
+
* E quarter note.
|
134
|
+
* F# quarter note.
|
135
|
+
* A eighth note.
|
136
|
+
* G quarter.
|
137
|
+
* E quarter.
|
138
|
+
* C one-quarter note.
|
139
|
+
* change one octave down.
|
140
|
+
* A eighth.
|
141
|
+
* Three F# eighths.
|
142
|
+
* G half note.
|
143
|
+
|
144
|
+
The colons are optional. They are there because you
|
145
|
+
can place an octave number after each note. Somehow
|
146
|
+
"8B6" (an eighth note of B at the sixth octave) looks
|
147
|
+
more confusing than "8:B6". I guess I figured that
|
148
|
+
the timing "8" is conceptually separate from the
|
149
|
+
actual tone "B6", even though they both comprise
|
150
|
+
the note itself.
|
151
|
+
|
152
|
+
-4- SERIALIZE SOUNDS.
|
153
|
+
To accomodate passing instruments between
|
154
|
+
ruby and c, bloopsaphone comes with a tiny
|
155
|
+
file format for describing sounds.
|
156
|
+
|
157
|
+
You can find examples of these in the sounds/
|
158
|
+
folder in this distro. Possible sound types
|
159
|
+
are 'square', 'sawtooth', 'sine' and 'noise'.
|
160
|
+
All other settings go from 0.0 to 1.0.
|
161
|
+
|
162
|
+
The 'freq' setting is only used if the sound
|
163
|
+
is played without a tune.
|
164
|
+
|
data/c/bloopsaphone.c
ADDED
@@ -0,0 +1,443 @@
|
|
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 <string.h>
|
12
|
+
#include <time.h>
|
13
|
+
#include <math.h>
|
14
|
+
#include <portaudio.h>
|
15
|
+
#include <unistd.h>
|
16
|
+
#include "bloopsaphone.h"
|
17
|
+
|
18
|
+
#define SAMPLE_RATE 44100
|
19
|
+
#define rnd(n) (rand() % (n + 1))
|
20
|
+
#define tempo2frames(tempo) ((float)SAMPLE_RATE / (tempo / 60.0f))
|
21
|
+
#define PI 3.14159265f
|
22
|
+
|
23
|
+
float
|
24
|
+
frnd(float range)
|
25
|
+
{
|
26
|
+
return (float)rnd(10000) / 10000 * range;
|
27
|
+
}
|
28
|
+
|
29
|
+
void
|
30
|
+
bloops_ready(bloops *B, bloopsatrack *A, unsigned char init)
|
31
|
+
{
|
32
|
+
A->period = 100.0 / (A->P->freq * A->P->freq + 0.001);
|
33
|
+
A->maxperiod = 100.0 / (A->P->limit * A->P->limit + 0.001);
|
34
|
+
A->slide = 1.0 - pow((double)A->P->slide, 3.0) * 0.01;
|
35
|
+
A->dslide = -pow((double)A->P->dslide, 3.0) * 0.000001;
|
36
|
+
A->square = 0.5f - A->P->square * 0.5f;
|
37
|
+
A->sweep = -A->P->sweep * 0.00005f;
|
38
|
+
if (A->P->arp >= 0.0f)
|
39
|
+
A->arp = 1.0 - pow((double)A->P->arp, 2.0) * 0.9;
|
40
|
+
else
|
41
|
+
A->arp = 1.0 + pow((double)A->P->arp, 2.0) * 10.0;
|
42
|
+
A->atime = 0;
|
43
|
+
A->alimit = (int)(pow(1.0f - A->P->aspeed, 2.0f) * 20000 + 32);
|
44
|
+
if (A->P->aspeed == 1.0f)
|
45
|
+
A->alimit = 0;
|
46
|
+
|
47
|
+
if (init)
|
48
|
+
{
|
49
|
+
int i = 0;
|
50
|
+
A->phase = 0;
|
51
|
+
A->filter[0] = 0.0f;
|
52
|
+
A->filter[1] = 0.0f;
|
53
|
+
A->filter[2] = pow(A->P->lpf, 3.0f) * 0.1f;
|
54
|
+
A->filter[3] = 1.0f + A->P->lsweep * 0.0001f;
|
55
|
+
A->filter[4] = 5.0f / (1.0f + pow(A->P->resonance, 2.0f) * 20.0f) * (0.01f + A->filter[2]);
|
56
|
+
if (A->filter[4] > 0.8f) A->filter[4] = 0.8f;
|
57
|
+
A->filter[5] = 0.0f;
|
58
|
+
A->filter[6] = pow(A->P->hpf, 2.0f) * 0.1f;
|
59
|
+
A->filter[7] = 1.0 + A->P->hsweep * 0.0003f;
|
60
|
+
|
61
|
+
A->vibe = 0.0f;
|
62
|
+
A->vspeed = pow(A->P->vspeed, 2.0f) * 0.01f;
|
63
|
+
A->vdelay = A->P->vibe * 0.5f;
|
64
|
+
|
65
|
+
A->volume = 0.0f;
|
66
|
+
A->stage = 0;
|
67
|
+
A->time = 0;
|
68
|
+
A->length[0] = (int)(A->P->attack * A->P->attack * 100000.0f);
|
69
|
+
A->length[1] = (int)(A->P->sustain * A->P->sustain * 100000.0f);
|
70
|
+
A->length[2] = (int)(A->P->decay * A->P->decay * 100000.0f);
|
71
|
+
|
72
|
+
A->fphase = pow(A->P->phase, 2.0f) * 1020.0f;
|
73
|
+
if (A->P->phase < 0.0f) A->fphase = -A->fphase;
|
74
|
+
A->dphase = pow(A->P->psweep, 2.0f) * 1.0f;
|
75
|
+
if (A->P->psweep < 0.0f) A->dphase = -A->dphase;
|
76
|
+
A->iphase = abs((int)A->fphase);
|
77
|
+
A->phasex = 0;
|
78
|
+
|
79
|
+
memset(A->phaser, 0, 1024 * sizeof(float));
|
80
|
+
for (i = 0; i < 32; i++)
|
81
|
+
A->noise[i] = frnd(2.0f) - 1.0f;
|
82
|
+
|
83
|
+
A->repeat = 0;
|
84
|
+
A->limit = (int)(pow(1.0f - A->P->repeat, 2.0f) * 20000 + 32);
|
85
|
+
if (A->P->repeat == 0.0f)
|
86
|
+
A->limit = 0;
|
87
|
+
A->playing = BLOOPS_PLAY;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
void
|
92
|
+
bloops_clear(bloops *B)
|
93
|
+
{
|
94
|
+
int i;
|
95
|
+
for (i = 0; i < BLOOPS_MAX_TRACKS; i++)
|
96
|
+
B->tracks[i] = NULL;
|
97
|
+
}
|
98
|
+
|
99
|
+
void
|
100
|
+
bloops_tempo(bloops *B, int tempo)
|
101
|
+
{
|
102
|
+
B->tempo = tempo;
|
103
|
+
}
|
104
|
+
|
105
|
+
void
|
106
|
+
bloops_track_at(bloops *B, bloopsatrack *track, int num)
|
107
|
+
{
|
108
|
+
B->tracks[num] = track;
|
109
|
+
}
|
110
|
+
|
111
|
+
void
|
112
|
+
bloops_play(bloops *B)
|
113
|
+
{
|
114
|
+
int i;
|
115
|
+
for (i = 0; i < BLOOPS_MAX_TRACKS; i++)
|
116
|
+
if (B->tracks[i] != NULL) {
|
117
|
+
bloops_ready(B, B->tracks[i], 1);
|
118
|
+
B->tracks[i]->frames = 0;
|
119
|
+
}
|
120
|
+
B->play = BLOOPS_PLAY;
|
121
|
+
}
|
122
|
+
|
123
|
+
int
|
124
|
+
bloops_is_done(bloops *B)
|
125
|
+
{
|
126
|
+
return B->play == BLOOPS_STOP;
|
127
|
+
}
|
128
|
+
|
129
|
+
static void
|
130
|
+
bloops_synth(bloops *B, int length, float* buffer)
|
131
|
+
{
|
132
|
+
int t, i, si;
|
133
|
+
|
134
|
+
while (length--)
|
135
|
+
{
|
136
|
+
int samplecount = 0;
|
137
|
+
int moreframes = 0;
|
138
|
+
float allsample = 0.0f;
|
139
|
+
|
140
|
+
for (t = 0; t < BLOOPS_MAX_TRACKS; t++)
|
141
|
+
{
|
142
|
+
bloopsatrack *A = B->tracks[t];
|
143
|
+
if (A == NULL)
|
144
|
+
continue;
|
145
|
+
|
146
|
+
if (A->notes)
|
147
|
+
{
|
148
|
+
int frames = 0;
|
149
|
+
for (i = 0; i < A->nlen; i++)
|
150
|
+
{
|
151
|
+
bloopsanote *note = &A->notes[i];
|
152
|
+
if (A->frames == frames)
|
153
|
+
{
|
154
|
+
float freq = bloops_note_freq(note->tone, (int)note->octave);
|
155
|
+
if (freq == 0.0f) {
|
156
|
+
A->period = 0.0f;
|
157
|
+
A->playing = BLOOPS_STOP;
|
158
|
+
} else {
|
159
|
+
bloops_ready(B, A, 1);
|
160
|
+
A->period = 100.0 / (freq * freq + 0.001);
|
161
|
+
}
|
162
|
+
}
|
163
|
+
else if (A->frames < frames)
|
164
|
+
break;
|
165
|
+
frames += (int)(tempo2frames(B->tempo) * (4.0f / note->duration));
|
166
|
+
}
|
167
|
+
|
168
|
+
if (A->frames <= frames)
|
169
|
+
moreframes++;
|
170
|
+
}
|
171
|
+
else
|
172
|
+
{
|
173
|
+
moreframes++;
|
174
|
+
}
|
175
|
+
|
176
|
+
A->frames++;
|
177
|
+
|
178
|
+
if (A->playing == BLOOPS_STOP)
|
179
|
+
continue;
|
180
|
+
|
181
|
+
samplecount++;
|
182
|
+
A->repeat++;
|
183
|
+
if (A->limit != 0 && A->repeat >= A->limit)
|
184
|
+
{
|
185
|
+
A->repeat = 0;
|
186
|
+
bloops_ready(B, A, 0);
|
187
|
+
}
|
188
|
+
|
189
|
+
A->atime++;
|
190
|
+
if (A->alimit != 0 && A->atime >= A->alimit)
|
191
|
+
{
|
192
|
+
A->alimit = 0;
|
193
|
+
A->period *= A->arp;
|
194
|
+
}
|
195
|
+
|
196
|
+
A->slide += A->dslide;
|
197
|
+
A->period *= A->slide;
|
198
|
+
if (A->period > A->maxperiod)
|
199
|
+
{
|
200
|
+
A->period = A->maxperiod;
|
201
|
+
if (A->P->limit > 0.0f)
|
202
|
+
A->playing = BLOOPS_STOP;
|
203
|
+
}
|
204
|
+
|
205
|
+
float rfperiod = A->period;
|
206
|
+
if (A->vdelay > 0.0f)
|
207
|
+
{
|
208
|
+
A->vibe += A->vspeed;
|
209
|
+
rfperiod = A->period * (1.0 + sin(A->vibe) * A->vdelay);
|
210
|
+
}
|
211
|
+
|
212
|
+
int period = (int)rfperiod;
|
213
|
+
if (period < 8) period = 8;
|
214
|
+
A->square += A->sweep;
|
215
|
+
if(A->square < 0.0f) A->square = 0.0f;
|
216
|
+
if(A->square > 0.5f) A->square = 0.5f;
|
217
|
+
|
218
|
+
A->time++;
|
219
|
+
if (A->time > A->length[A->stage])
|
220
|
+
{
|
221
|
+
A->time = 0;
|
222
|
+
A->stage++;
|
223
|
+
if (A->stage == 3)
|
224
|
+
A->playing = BLOOPS_STOP;
|
225
|
+
}
|
226
|
+
|
227
|
+
switch (A->stage) {
|
228
|
+
case 0:
|
229
|
+
A->volume = (float)A->time / A->length[0];
|
230
|
+
break;
|
231
|
+
case 1:
|
232
|
+
A->volume = 1.0f + pow(1.0f - (float)A->time / A->length[1], 1.0f) * 2.0f * A->P->punch;
|
233
|
+
break;
|
234
|
+
case 2:
|
235
|
+
A->volume = 1.0f - (float)A->time / A->length[2];
|
236
|
+
break;
|
237
|
+
}
|
238
|
+
|
239
|
+
A->fphase += A->dphase;
|
240
|
+
A->iphase = abs((int)A->fphase);
|
241
|
+
if (A->iphase > 1023) A->iphase = 1023;
|
242
|
+
|
243
|
+
if (A->filter[7] != 0.0f)
|
244
|
+
{
|
245
|
+
A->filter[6] *= A->filter[7];
|
246
|
+
if (A->filter[6] < 0.00001f) A->filter[6] = 0.00001f;
|
247
|
+
if (A->filter[6] > 0.1f) A->filter[6] = 0.1f;
|
248
|
+
}
|
249
|
+
|
250
|
+
float ssample = 0.0f;
|
251
|
+
for (si = 0; si < 8; si++)
|
252
|
+
{
|
253
|
+
float sample = 0.0f;
|
254
|
+
A->phase++;
|
255
|
+
if (A->phase >= period)
|
256
|
+
{
|
257
|
+
A->phase %= period;
|
258
|
+
if (A->P->type == BLOOPS_NOISE)
|
259
|
+
for (i = 0; i < 32; i++)
|
260
|
+
A->noise[i] = frnd(2.0f) - 1.0f;
|
261
|
+
}
|
262
|
+
|
263
|
+
float fp = (float)A->phase / period;
|
264
|
+
switch (A->P->type)
|
265
|
+
{
|
266
|
+
case BLOOPS_SQUARE:
|
267
|
+
if (fp < A->square)
|
268
|
+
sample = 0.5f;
|
269
|
+
else
|
270
|
+
sample = -0.5f;
|
271
|
+
break;
|
272
|
+
case BLOOPS_SAWTOOTH:
|
273
|
+
sample = 1.0f - fp * 2;
|
274
|
+
break;
|
275
|
+
case BLOOPS_SINE:
|
276
|
+
sample = (float)sin(fp * 2 * PI);
|
277
|
+
break;
|
278
|
+
case BLOOPS_NOISE:
|
279
|
+
sample = A->noise[A->phase * 32 / period];
|
280
|
+
break;
|
281
|
+
}
|
282
|
+
|
283
|
+
float pp = A->filter[0];
|
284
|
+
A->filter[2] *= A->filter[3];
|
285
|
+
if (A->filter[2] < 0.0f) A->filter[2] = 0.0f;
|
286
|
+
if (A->filter[2] > 0.1f) A->filter[2] = 0.1f;
|
287
|
+
if (A->P->lpf != 1.0f)
|
288
|
+
{
|
289
|
+
A->filter[1] += (sample - A->filter[0]) * A->filter[2];
|
290
|
+
A->filter[1] -= A->filter[1] * A->filter[4];
|
291
|
+
}
|
292
|
+
else
|
293
|
+
{
|
294
|
+
A->filter[0] = sample;
|
295
|
+
A->filter[1] = 0.0f;
|
296
|
+
}
|
297
|
+
A->filter[0] += A->filter[1];
|
298
|
+
|
299
|
+
A->filter[5] += A->filter[0] - pp;
|
300
|
+
A->filter[5] -= A->filter[5] * A->filter[6];
|
301
|
+
sample = A->filter[5];
|
302
|
+
|
303
|
+
A->phaser[A->phasex & 1023] = sample;
|
304
|
+
sample += A->phaser[(A->phasex - A->iphase + 1024) & 1023];
|
305
|
+
A->phasex = (A->phasex + 1) & 1023;
|
306
|
+
|
307
|
+
ssample += sample * A->volume;
|
308
|
+
}
|
309
|
+
ssample = ssample / 8 * B->volume;
|
310
|
+
ssample *= 2.0f * A->P->volume;
|
311
|
+
|
312
|
+
if (ssample > 1.0f) ssample = 1.0f;
|
313
|
+
if (ssample < -1.0f) ssample = -1.0f;
|
314
|
+
allsample += ssample;
|
315
|
+
}
|
316
|
+
|
317
|
+
if (moreframes == 0)
|
318
|
+
B->play = BLOOPS_STOP;
|
319
|
+
*buffer++ = allsample;
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
static int bloops_port_callback(const void *inputBuffer, void *outputBuffer,
|
324
|
+
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo,
|
325
|
+
PaStreamCallbackFlags statusFlags, void *data)
|
326
|
+
{
|
327
|
+
int i;
|
328
|
+
float *out = (float*)outputBuffer;
|
329
|
+
bloops *B = (bloops *)data;
|
330
|
+
|
331
|
+
if (B->play == BLOOPS_PLAY)
|
332
|
+
bloops_synth(B, framesPerBuffer, out);
|
333
|
+
else
|
334
|
+
for(i = 0; i < framesPerBuffer; i++)
|
335
|
+
*out++ = 0.0f;
|
336
|
+
|
337
|
+
return 0;
|
338
|
+
}
|
339
|
+
|
340
|
+
bloopsaphone *
|
341
|
+
bloops_square()
|
342
|
+
{
|
343
|
+
bloopsaphone *P = (bloopsaphone *)calloc(sizeof(bloopsaphone), 1);
|
344
|
+
P->type = BLOOPS_SQUARE;
|
345
|
+
P->volume = 0.5f;
|
346
|
+
P->sustain = 0.3f;
|
347
|
+
P->decay = 0.4f;
|
348
|
+
P->freq = 0.3f;
|
349
|
+
P->lpf = 1.0f;
|
350
|
+
return P;
|
351
|
+
}
|
352
|
+
|
353
|
+
bloopsaphone *
|
354
|
+
bloops_load(char* filename)
|
355
|
+
{
|
356
|
+
bloopsaphone *P = NULL;
|
357
|
+
FILE* file = fopen(filename, "rb");
|
358
|
+
if (!file) return NULL;
|
359
|
+
|
360
|
+
int version = 0;
|
361
|
+
fread(&version, 1, sizeof(int), file);
|
362
|
+
if (version != 102)
|
363
|
+
return NULL;
|
364
|
+
|
365
|
+
P = (bloopsaphone *)malloc(sizeof(bloopsaphone));
|
366
|
+
fread(&P->type, 1, sizeof(int), file);
|
367
|
+
|
368
|
+
P->volume = 0.5f;
|
369
|
+
fread(&P->volume, 1, sizeof(float), file);
|
370
|
+
fread(&P->freq, 1, sizeof(float), file);
|
371
|
+
fread(&P->limit, 1, sizeof(float), file);
|
372
|
+
fread(&P->slide, 1, sizeof(float), file);
|
373
|
+
fread(&P->dslide, 1, sizeof(float), file);
|
374
|
+
fread(&P->square, 1, sizeof(float), file);
|
375
|
+
fread(&P->sweep, 1, sizeof(float), file);
|
376
|
+
|
377
|
+
fread(&P->vibe, 1, sizeof(float), file);
|
378
|
+
fread(&P->vspeed, 1, sizeof(float), file);
|
379
|
+
fread(&P->vdelay, 1, sizeof(float), file);
|
380
|
+
|
381
|
+
fread(&P->attack, 1, sizeof(float), file);
|
382
|
+
fread(&P->sustain, 1, sizeof(float), file);
|
383
|
+
fread(&P->decay, 1, sizeof(float), file);
|
384
|
+
fread(&P->punch, 1, sizeof(float), file);
|
385
|
+
|
386
|
+
fread(&P->resonance, 1, sizeof(float), file);
|
387
|
+
fread(&P->lpf, 1, sizeof(float), file);
|
388
|
+
fread(&P->lsweep, 1, sizeof(float), file);
|
389
|
+
fread(&P->hpf, 1, sizeof(float), file);
|
390
|
+
fread(&P->hsweep, 1, sizeof(float), file);
|
391
|
+
|
392
|
+
fread(&P->phase, 1, sizeof(float), file);
|
393
|
+
fread(&P->psweep, 1, sizeof(float), file);
|
394
|
+
|
395
|
+
fread(&P->repeat, 1, sizeof(float), file);
|
396
|
+
fread(&P->arp, 1, sizeof(float), file);
|
397
|
+
fread(&P->aspeed, 1, sizeof(float), file);
|
398
|
+
|
399
|
+
fclose(file);
|
400
|
+
return P;
|
401
|
+
}
|
402
|
+
|
403
|
+
static int bloops_open = 0;
|
404
|
+
|
405
|
+
bloops *
|
406
|
+
bloops_new()
|
407
|
+
{
|
408
|
+
bloops *B = (bloops *)malloc(sizeof(bloops));
|
409
|
+
B->volume = 0.10f;
|
410
|
+
B->tempo = 120;
|
411
|
+
B->play = BLOOPS_STOP;
|
412
|
+
bloops_clear(B);
|
413
|
+
|
414
|
+
if (!bloops_open++)
|
415
|
+
{
|
416
|
+
srand(time(NULL));
|
417
|
+
Pa_Initialize();
|
418
|
+
}
|
419
|
+
|
420
|
+
Pa_OpenDefaultStream(&B->stream, 0, 1, paFloat32,
|
421
|
+
SAMPLE_RATE, 512, bloops_port_callback, B);
|
422
|
+
Pa_StartStream(B->stream);
|
423
|
+
return B;
|
424
|
+
}
|
425
|
+
|
426
|
+
void
|
427
|
+
bloops_destroy(bloops *B)
|
428
|
+
{
|
429
|
+
Pa_StopStream(B->stream);
|
430
|
+
Pa_CloseStream(B->stream);
|
431
|
+
free((void *)B);
|
432
|
+
|
433
|
+
if (!--bloops_open)
|
434
|
+
Pa_Terminate();
|
435
|
+
}
|
436
|
+
|
437
|
+
void
|
438
|
+
bloops_track_destroy(bloopsatrack *track)
|
439
|
+
{
|
440
|
+
if (track->notes != NULL)
|
441
|
+
free(track->notes);
|
442
|
+
free(track);
|
443
|
+
}
|