├── COPYING ├── Makefile ├── README ├── bloopsaphone.gemspec ├── c ├── bloopsaphone-internal.h ├── bloopsaphone.c ├── bloopsaphone.h ├── bloopsawhat.c ├── notation.c └── notation.rl ├── ext └── ruby │ ├── extconf.rb │ ├── rubyext.c │ ├── test.rb │ ├── test_load.rb │ ├── tune_cheeky_drat.rb │ └── tune_warp.rb ├── misc └── Makefile-dll └── sounds ├── dart.blu ├── error.blu ├── ice.blu ├── jump.blu ├── pogo.blu └── stun.blu /COPYING: -------------------------------------------------------------------------------- 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 | 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRC = c/bloopsaphone.c c/notation.c 2 | OBJ = ${SRC:.c=.o} 3 | 4 | PREFIX = /usr/local 5 | CC = gcc 6 | AR = ar 7 | ARFLAGS = cr 8 | CFLAGS ?= -Wall 9 | DEBUG ?= 0 10 | ECHO = /bin/echo 11 | INCS = -Ic 12 | LDFLAGS ?= 13 | LIBS = -lm -lportaudio 14 | RAGEL = ragel 15 | 16 | RAGELV = `${RAGEL} -v | sed "/ version /!d; s/.* version //; s/ .*//"` 17 | 18 | all: bloopsaphone 19 | 20 | rebuild: clean bloopsaphone 21 | 22 | bloopsaphone: bloopsawhat bloopsalib 23 | 24 | bloopsawhat: ${OBJ} c/bloopsawhat.o 25 | @${ECHO} LINK bloopsawhat 26 | @${CC} ${CFLAGS} ${OBJ} c/bloopsawhat.o ${LDFLAGS} ${LIBS} -o bloopsawhat 27 | 28 | bloopsalib: ${OBJ} 29 | @${ECHO} LINK bloopsalib 30 | @${AR} ${ARFLAGS} libbloopsaphone.a ${OBJ} 31 | 32 | c/notation.c: c/notation.rl 33 | @if [ "${RAGELV}" != "6.3" ]; then \ 34 | if [ "${RAGELV}" != "6.2" ]; then \ 35 | ${ECHO} "** bloopsaphone may not work with ragel ${RAGELV}! try version 6.2 or 6.3."; \ 36 | fi; \ 37 | fi 38 | @${ECHO} RAGEL c/notation.rl 39 | @${RAGEL} c/notation.rl -C -o $@ 40 | 41 | %.o: %.c 42 | @${ECHO} CC $< 43 | @${CC} -c ${CFLAGS} ${INCS} -o $@ $< 44 | 45 | clean: 46 | @${ECHO} cleaning 47 | @rm -f ${OBJ} 48 | @rm -f c/notation.c c/*.o 49 | @rm -f bloopsawhat libbloopsaphone.a bloopsaphone.so 50 | @cd ext/ruby && make distclean || true 51 | 52 | ruby: c/notation.c c/bloopsaphone.c 53 | @${ECHO} RUBY extconf.rb 54 | @cd ext/ruby && CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" ruby extconf.rb && make 55 | @${ECHO} "" 56 | @${ECHO} "To test: cd ext/ruby" 57 | @${ECHO} "Then: ruby test.rb" 58 | @${ECHO} "" 59 | 60 | .PHONY: all bloopsaphone clean rebuild ruby 61 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 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 | 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 | 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 | To build from source isn't too bad. 86 | Download PortAudio 1.9 and build it. 87 | 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 96 | 97 | Then go back to Bloopsaphone and do 98 | a `make ruby`. 99 | 100 | ~ 101 | 102 | -$- THE IDEALS, 103 | 104 | -1- ASYNCHRONOUS. 105 | You send it a song and it plays in 106 | the background. You'll get an event 107 | when it finishes. 108 | 109 | -2- SMALL. 110 | This is just a toy, I don't want it 111 | to be very big and comprehensive. 112 | Just to play little tunes with a 113 | nostalgic arcade sound rather than 114 | the CASIO-stylings of most MIDI. 115 | 116 | -3- CUSTOM NOTATION. 117 | Someone told me about Nokring, iMelody, 118 | numbered musical notation and I did 119 | some reading. They're little languages 120 | for texting yourself a ringtone. 121 | 122 | 123 | 124 | 125 | Bloopsaphone uses a variation on RTTTL. 126 | 127 | Instead of commas, I use whitespace. 128 | A rest is simply a number. A plus sign 129 | moves everything up an octave. A minus 130 | down an octave. 131 | 132 | The Simpsons' Theme, for instance, would be: 133 | 134 | 32 + C E F# 8:A G E C - 8:A 8:F# 8:F# 8:F# 2:G 135 | 136 | Which translates into: 137 | 138 | * a 1/32nd note rest. 139 | * change one octave up. 140 | * C quarter note. 141 | * E quarter note. 142 | * F# quarter note. 143 | * A eighth note. 144 | * G quarter. 145 | * E quarter. 146 | * C one-quarter note. 147 | * change one octave down. 148 | * A eighth. 149 | * Three F# eighths. 150 | * G half note. 151 | 152 | The colons are optional. They are there because you 153 | can place an octave number after each note. Somehow 154 | "8B6" (an eighth note of B at the sixth octave) looks 155 | more confusing than "8:B6". I guess I figured that 156 | the timing "8" is conceptually separate from the 157 | actual tone "B6", even though they both comprise 158 | the note itself. 159 | 160 | -4- SERIALIZE SOUNDS. 161 | To accomodate passing instruments between 162 | ruby and c, bloopsaphone comes with a tiny 163 | file format for describing sounds. 164 | 165 | You can find examples of these in the sounds/ 166 | folder in this distro. Possible sound types 167 | are 'square', 'sawtooth', 'sine' and 'noise'. 168 | All other settings go from 0.0 to 1.0. 169 | 170 | The 'freq' setting is only used if the sound 171 | is played without a tune. 172 | 173 | -------------------------------------------------------------------------------- /bloopsaphone.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'bloopsaphone' 3 | s.version = '0.4' 4 | 5 | s.authors = ["why the lucky stiff"] 6 | s.date = '2009-02-12' 7 | s.description = 'arcade sounds and chiptunes' 8 | s.email = 'why@ruby-lang.org' 9 | s.extensions = ["ext/ruby/extconf.rb"] 10 | s.extra_rdoc_files = ["README", "COPYING"] 11 | s.files = ["COPYING", "README", "c/bloopsaphone.c", "c/bloopsaphone.h", "c/notation.c", 12 | "ext/ruby/extconf.rb", "ext/ruby/rubyext.c", "ext/ruby/test.rb", "ext/ruby/test_load.rb", 13 | "sounds/dart.blu", "sounds/error.blu", "sounds/ice.blu", "sounds/jump.blu", 14 | "sounds/pogo.blu", "sounds/stun.blu"] 15 | s.has_rdoc = false 16 | s.homepage = 'http://github.com/why/bloopsaphone' 17 | s.summary = 'arcade sounds and chiptunes' 18 | end 19 | -------------------------------------------------------------------------------- /c/bloopsaphone-internal.h: -------------------------------------------------------------------------------- 1 | // 2 | // threads.h - threaded garments for the bloopsaphone 3 | // 4 | #ifndef BLOOPSAPHONE_INTERNAL_H 5 | #define BLOOPSAPHONE_INTERNAL_H 6 | 7 | #ifdef _WIN32 8 | #include 9 | typedef CRITICAL_SECTION bloopsalock; 10 | static inline void bloops_lock_init(bloopsalock *lock) { 11 | InitializeCriticalSection(lock); 12 | } 13 | static inline void bloops_lock_acquire(bloopsalock *lock) { 14 | EnterCriticalSection(lock); 15 | } 16 | static inline int bloops_lock_try_acquire(bloopsalock *lock) { 17 | return !!TryEnterCriticalSection(lock); 18 | } 19 | static inline void bloops_lock_release(bloopsalock *lock) { 20 | LeaveCriticalSection(lock); 21 | } 22 | static inline void bloops_lock_finalize(bloopsalock *lock) { 23 | DeleteCriticalSection(lock); 24 | } 25 | #else 26 | #include 27 | #include 28 | typedef pthread_mutex_t bloopsalock; 29 | static inline void bloops_lock_init(bloopsalock *lock) { 30 | pthread_mutex_init(lock, NULL); 31 | } 32 | static inline void bloops_lock_acquire(bloopsalock *lock) { 33 | pthread_mutex_lock(lock); 34 | } 35 | static inline int bloops_lock_try_acquire(bloopsalock *lock) { 36 | return !pthread_mutex_trylock(lock); 37 | } 38 | static inline void bloops_lock_release(bloopsalock *lock) { 39 | pthread_mutex_unlock(lock); 40 | } 41 | static inline void bloops_lock_finalize(bloopsalock *lock) { 42 | pthread_mutex_destroy(lock); 43 | } 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /c/bloopsaphone.c: -------------------------------------------------------------------------------- 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 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 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 | } 597 | -------------------------------------------------------------------------------- /c/bloopsaphone.h: -------------------------------------------------------------------------------- 1 | // 2 | // bloopsaphone.h 3 | // the chiptune maker for portaudio 4 | // 5 | #ifndef BLOOPSAPHONE_H 6 | #define BLOOPSAPHONE_H 7 | 8 | #define BLOOPSAPHONE_VERSION "1.0" 9 | 10 | typedef enum { 11 | BLOOPS_STOP = 0, 12 | BLOOPS_PLAY = 1 13 | } bloopsastate; 14 | 15 | typedef enum { 16 | BLOOPS_SQUARE = 0, 17 | BLOOPS_SAWTOOTH = 1, 18 | BLOOPS_SINE = 2, 19 | BLOOPS_NOISE = 3 20 | } bloopswaveform; 21 | 22 | typedef enum { 23 | BLOOPS_FX_VOLUME = 0, 24 | BLOOPS_FX_PUNCH = 1, 25 | BLOOPS_FX_ATTACK = 2, 26 | BLOOPS_FX_SUSTAIN = 3, 27 | BLOOPS_FX_DECAY = 4, 28 | BLOOPS_FX_SWEEP = 5, 29 | BLOOPS_FX_SQUARE = 6, 30 | BLOOPS_FX_VIBE = 7, 31 | BLOOPS_FX_VSPEED = 8, 32 | BLOOPS_FX_VDELAY = 9, 33 | BLOOPS_FX_LPF = 10, 34 | BLOOPS_FX_LSWEEP = 11, 35 | BLOOPS_FX_RESONANCE = 12, 36 | BLOOPS_FX_HPF = 13, 37 | BLOOPS_FX_HSWEEP = 14, 38 | BLOOPS_FX_ARP = 15, 39 | BLOOPS_FX_ASPEED = 16, 40 | BLOOPS_FX_PHASE = 17, 41 | BLOOPS_FX_PSWEEP = 18, 42 | BLOOPS_FX_REPEAT = 19 43 | } bloopsafxcmd; 44 | 45 | typedef struct { 46 | bloopswaveform type; 47 | unsigned char pan; 48 | float volume; 49 | float punch; 50 | float attack; 51 | float sustain; 52 | float decay; 53 | float freq, limit, slide, dslide; // pitch 54 | float square, sweep; // square wave 55 | float vibe, vspeed, vdelay; // vibrato 56 | float lpf, lsweep, resonance, hpf, hsweep; 57 | // hi-pass, lo-pass 58 | float arp, aspeed; // arpeggiator 59 | float phase, psweep; // phaser 60 | float repeat; // repeats? 61 | } bloopsaparams; 62 | 63 | typedef struct { 64 | unsigned refcount; 65 | bloopsaparams params; 66 | } bloopsaphone; 67 | 68 | #define BLOOPS_HI_OCTAVE 8 69 | 70 | typedef struct bloopsafx_tag { 71 | bloopsafxcmd cmd; 72 | float val; 73 | char mod; 74 | struct bloopsafx_tag *next; 75 | } bloopsafx; 76 | 77 | typedef struct { 78 | char tone, octave, duration; 79 | bloopsafx *FX; 80 | } bloopsanote; 81 | 82 | typedef struct { 83 | unsigned refcount; 84 | int nlen, capa; 85 | bloopsanote *notes; 86 | bloopsaparams params; 87 | } bloopsatrack; 88 | 89 | typedef struct { 90 | bloopsatrack *track; 91 | bloopsaparams params; 92 | int frames, nextnote[2]; 93 | float volume, freq; 94 | bloopsastate state; 95 | int stage, time, length[3]; 96 | double period, maxperiod, slide, dslide; 97 | float square, sweep; 98 | int phase, iphase, phasex; 99 | float fphase, dphase; 100 | float phaser[1024]; 101 | float noise[32]; 102 | float filter[8]; 103 | float vibe, vspeed, vdelay; 104 | int repeat, limit; 105 | double arp; 106 | int atime, alimit; 107 | } bloopsavoice; 108 | 109 | #define BLOOPS_MAX_TRACKS 64 110 | #define BLOOPS_MAX_CHANNELS 64 111 | 112 | typedef struct { 113 | unsigned refcount; 114 | int tempo; 115 | float volume; 116 | bloopsavoice voices[BLOOPS_MAX_TRACKS]; 117 | bloopsastate state; 118 | } bloops; 119 | 120 | typedef struct { 121 | bloops *B[BLOOPS_MAX_CHANNELS]; 122 | void *stream; 123 | } bloopsmix; 124 | 125 | // 126 | // the api 127 | // 128 | bloops *bloops_new(); 129 | void bloops_ref(bloops *); 130 | void bloops_destroy(bloops *); 131 | 132 | void bloops_clear(bloops *); 133 | void bloops_tempo(bloops *, int tempo); 134 | void bloops_play(bloops *); 135 | void bloops_stop(bloops *); 136 | int bloops_is_done(bloops *); 137 | 138 | bloopsatrack *bloops_track(bloops *, bloopsaphone *, char *, int); 139 | bloopsatrack *bloops_track2(bloops *, bloopsaphone *, char *); 140 | void bloops_track_ref(bloopsatrack *); 141 | void bloops_track_destroy(bloopsatrack *); 142 | 143 | bloopsaphone *bloops_square(); 144 | bloopsaphone *bloops_sound_file(bloops *, char *); 145 | void bloops_sound_copy(bloopsaphone *, bloopsaphone const *); 146 | void bloops_sound_ref(bloopsaphone *); 147 | void bloops_sound_destroy(bloopsaphone *); 148 | 149 | char *bloops_track_str(bloopsatrack *); 150 | char *bloops_fxcmd_name(bloopsafxcmd fxcmd); 151 | float bloops_note_freq(char, int); 152 | char *bloops_sound_str(bloopsaphone *); 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /c/bloopsawhat.c: -------------------------------------------------------------------------------- 1 | // 2 | // bloopsawhat.c 3 | // a simple commandline player 4 | // 5 | #include 6 | #include 7 | #include 8 | #include "bloopsaphone.h" 9 | 10 | static void 11 | usage() 12 | { 13 | printf("usage: bloopsawhat notes\n" 14 | " (ex.: bloopsawhat \"a b c d e f g + a b c\"\n"); 15 | } 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | char *str; 21 | if (argc > 1) { 22 | bloops *B = bloops_new(); 23 | bloopsaphone *P = bloops_square(); 24 | bloopsatrack *track = bloops_track2(B, P, argv[1]); 25 | bloops_sound_destroy(P); 26 | printf("%s\n", str = bloops_track_str(track)); 27 | bloops_play(B); 28 | while (!bloops_is_done(B)) 29 | sleep(1); 30 | free(str); 31 | bloops_track_destroy(track); 32 | bloops_destroy(B); 33 | return 0; 34 | } 35 | 36 | usage(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /c/notation.c: -------------------------------------------------------------------------------- 1 | #line 1 "c/notation.rl" 2 | // 3 | // notation.rl 4 | // the musical notation parser 5 | // 6 | // (c) 2009 why the lucky stiff 7 | // See COPYING for the license 8 | // 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "bloopsaphone.h" 15 | 16 | #define ATOI(X,N) ({ \ 17 | char *Ap = X; \ 18 | int Ai = 0; \ 19 | size_t Al = N; \ 20 | while (Al--) { \ 21 | if ((*Ap >= '0') && (*Ap <= '9')) { \ 22 | Ai = (Ai * 10) + (*Ap - '0'); \ 23 | Ap++; \ 24 | } \ 25 | else break; \ 26 | } \ 27 | Ai; \ 28 | }) 29 | 30 | #define NOTE S->notes[S->nlen] 31 | 32 | #define NEXT() \ 33 | NOTE.duration = len; \ 34 | NOTE.octave = oct; \ 35 | mod = 0; \ 36 | tone = 0; \ 37 | len = 4; \ 38 | fxval = 0; \ 39 | fxmod = 0; \ 40 | S->nlen++ 41 | 42 | 43 | #line 44 "c/notation.c" 44 | static const char _bloopnotes_actions[] = { 45 | 0, 1, 1, 1, 3, 1, 4, 1, 46 | 6, 1, 8, 1, 9, 1, 10, 1, 47 | 11, 1, 12, 1, 13, 1, 14, 1, 48 | 15, 1, 16, 1, 17, 1, 18, 1, 49 | 19, 1, 20, 1, 21, 1, 22, 1, 50 | 23, 1, 24, 1, 25, 1, 26, 1, 51 | 27, 1, 28, 1, 29, 1, 30, 1, 52 | 31, 1, 32, 1, 33, 1, 34, 1, 53 | 35, 1, 36, 1, 41, 2, 0, 37, 54 | 2, 0, 39, 2, 0, 40, 2, 28, 55 | 39, 2, 29, 40, 2, 35, 0, 2, 56 | 35, 5, 2, 35, 30, 2, 35, 32, 57 | 3, 1, 2, 38, 3, 3, 2, 38, 58 | 3, 30, 2, 38, 3, 32, 2, 38, 59 | 3, 35, 4, 5, 3, 35, 5, 7, 60 | 4, 35, 4, 5, 7 61 | }; 62 | 63 | static const short _bloopnotes_key_offsets[] = { 64 | 0, 0, 8, 11, 12, 20, 27, 31, 65 | 37, 39, 43, 45, 48, 52, 54, 57, 66 | 60, 66, 70, 71, 72, 73, 74, 82, 67 | 83, 84, 85, 86, 94, 95, 96, 97, 68 | 98, 106, 108, 109, 117, 118, 119, 120, 69 | 121, 129, 131, 132, 140, 141, 142, 143, 70 | 144, 152, 155, 156, 157, 158, 166, 167, 71 | 168, 169, 170, 178, 179, 180, 181, 189, 72 | 190, 192, 193, 194, 195, 203, 204, 205, 73 | 206, 207, 208, 209, 217, 220, 221, 222, 74 | 223, 224, 232, 233, 234, 235, 236, 237, 75 | 245, 246, 247, 248, 256, 260, 261, 262, 76 | 263, 264, 272, 273, 274, 282, 283, 284, 77 | 285, 286, 294, 295, 296, 297, 298, 306, 78 | 317, 319, 322, 323, 323, 325, 328, 329, 79 | 329, 336, 341, 345, 350, 353, 354 80 | }; 81 | 82 | static const char _bloopnotes_trans_keys[] = { 83 | 97, 100, 104, 108, 112, 114, 115, 118, 84 | 114, 115, 116, 112, 32, 43, 45, 58, 85 | 9, 13, 48, 57, 32, 43, 45, 9, 86 | 13, 48, 57, 32, 58, 9, 13, 32, 87 | 45, 9, 13, 48, 57, 48, 57, 46, 88 | 93, 48, 57, 48, 57, 93, 48, 57, 89 | 46, 93, 48, 57, 48, 57, 93, 48, 90 | 57, 45, 48, 57, 32, 58, 9, 13, 91 | 48, 57, 43, 45, 48, 57, 112, 101, 92 | 101, 100, 32, 43, 45, 58, 9, 13, 93 | 48, 57, 116, 97, 99, 107, 32, 43, 94 | 45, 58, 9, 13, 48, 57, 101, 99, 95 | 97, 121, 32, 43, 45, 58, 9, 13, 96 | 48, 57, 112, 115, 102, 32, 43, 45, 97 | 58, 9, 13, 48, 57, 119, 101, 101, 98 | 112, 32, 43, 45, 58, 9, 13, 48, 99 | 57, 112, 115, 102, 32, 43, 45, 58, 100 | 9, 13, 48, 57, 119, 101, 101, 112, 101 | 32, 43, 45, 58, 9, 13, 48, 57, 102 | 104, 115, 117, 97, 115, 101, 32, 43, 103 | 45, 58, 9, 13, 48, 57, 119, 101, 104 | 101, 112, 32, 43, 45, 58, 9, 13, 105 | 48, 57, 110, 99, 104, 32, 43, 45, 106 | 58, 9, 13, 48, 57, 101, 112, 115, 107 | 101, 97, 116, 32, 43, 45, 58, 9, 108 | 13, 48, 57, 111, 110, 97, 110, 99, 109 | 101, 32, 43, 45, 58, 9, 13, 48, 110 | 57, 113, 117, 119, 117, 97, 114, 101, 111 | 32, 43, 45, 58, 9, 13, 48, 57, 112 | 115, 116, 97, 105, 110, 32, 43, 45, 113 | 58, 9, 13, 48, 57, 101, 101, 112, 114 | 32, 43, 45, 58, 9, 13, 48, 57, 115 | 100, 105, 111, 115, 101, 108, 97, 121, 116 | 32, 43, 45, 58, 9, 13, 48, 57, 117 | 98, 101, 32, 43, 45, 58, 9, 13, 118 | 48, 57, 108, 117, 109, 101, 32, 43, 119 | 45, 58, 9, 13, 48, 57, 112, 101, 120 | 101, 100, 32, 43, 45, 58, 9, 13, 121 | 48, 57, 32, 43, 45, 9, 13, 49, 122 | 57, 65, 71, 97, 103, 49, 57, 58, 123 | 48, 57, 58, 49, 57, 58, 48, 57, 124 | 58, 58, 48, 57, 65, 71, 97, 103, 125 | 58, 65, 71, 97, 103, 65, 71, 97, 126 | 103, 35, 91, 98, 49, 56, 91, 49, 127 | 56, 91, 91, 0 128 | }; 129 | 130 | static const char _bloopnotes_single_lengths[] = { 131 | 0, 8, 3, 1, 4, 3, 2, 2, 132 | 0, 2, 0, 1, 2, 0, 1, 1, 133 | 2, 2, 1, 1, 1, 1, 4, 1, 134 | 1, 1, 1, 4, 1, 1, 1, 1, 135 | 4, 2, 1, 4, 1, 1, 1, 1, 136 | 4, 2, 1, 4, 1, 1, 1, 1, 137 | 4, 3, 1, 1, 1, 4, 1, 1, 138 | 1, 1, 4, 1, 1, 1, 4, 1, 139 | 2, 1, 1, 1, 4, 1, 1, 1, 140 | 1, 1, 1, 4, 3, 1, 1, 1, 141 | 1, 4, 1, 1, 1, 1, 1, 4, 142 | 1, 1, 1, 4, 4, 1, 1, 1, 143 | 1, 4, 1, 1, 4, 1, 1, 1, 144 | 1, 4, 1, 1, 1, 1, 4, 3, 145 | 0, 1, 1, 0, 0, 1, 1, 0, 146 | 1, 1, 0, 3, 1, 1, 1 147 | }; 148 | 149 | static const char _bloopnotes_range_lengths[] = { 150 | 0, 0, 0, 0, 2, 2, 1, 2, 151 | 1, 1, 1, 1, 1, 1, 1, 1, 152 | 2, 1, 0, 0, 0, 0, 2, 0, 153 | 0, 0, 0, 2, 0, 0, 0, 0, 154 | 2, 0, 0, 2, 0, 0, 0, 0, 155 | 2, 0, 0, 2, 0, 0, 0, 0, 156 | 2, 0, 0, 0, 0, 2, 0, 0, 157 | 0, 0, 2, 0, 0, 0, 2, 0, 158 | 0, 0, 0, 0, 2, 0, 0, 0, 159 | 0, 0, 0, 2, 0, 0, 0, 0, 160 | 0, 2, 0, 0, 0, 0, 0, 2, 161 | 0, 0, 0, 2, 0, 0, 0, 0, 162 | 0, 2, 0, 0, 2, 0, 0, 0, 163 | 0, 2, 0, 0, 0, 0, 2, 4, 164 | 1, 1, 0, 0, 1, 1, 0, 0, 165 | 3, 2, 2, 1, 1, 0, 0 166 | }; 167 | 168 | static const short _bloopnotes_index_offsets[] = { 169 | 0, 0, 9, 13, 15, 22, 28, 32, 170 | 37, 39, 43, 45, 48, 52, 54, 57, 171 | 60, 65, 69, 71, 73, 75, 77, 84, 172 | 86, 88, 90, 92, 99, 101, 103, 105, 173 | 107, 114, 117, 119, 126, 128, 130, 132, 174 | 134, 141, 144, 146, 153, 155, 157, 159, 175 | 161, 168, 172, 174, 176, 178, 185, 187, 176 | 189, 191, 193, 200, 202, 204, 206, 213, 177 | 215, 218, 220, 222, 224, 231, 233, 235, 178 | 237, 239, 241, 243, 250, 254, 256, 258, 179 | 260, 262, 269, 271, 273, 275, 277, 279, 180 | 286, 288, 290, 292, 299, 304, 306, 308, 181 | 310, 312, 319, 321, 323, 330, 332, 334, 182 | 336, 338, 345, 347, 349, 351, 353, 360, 183 | 368, 370, 373, 375, 376, 378, 381, 383, 184 | 384, 389, 393, 396, 401, 404, 406 185 | }; 186 | 187 | static const char _bloopnotes_trans_targs[] = { 188 | 2, 28, 33, 41, 49, 63, 76, 92, 189 | 111, 3, 18, 23, 111, 4, 111, 5, 190 | 6, 16, 17, 5, 12, 111, 5, 6, 191 | 16, 5, 12, 111, 7, 15, 7, 111, 192 | 7, 8, 7, 12, 111, 9, 111, 10, 193 | 126, 9, 111, 11, 111, 126, 11, 111, 194 | 13, 126, 12, 111, 14, 111, 126, 14, 195 | 111, 8, 12, 111, 7, 15, 7, 9, 196 | 111, 6, 16, 12, 111, 19, 111, 20, 197 | 111, 21, 111, 22, 111, 5, 6, 16, 198 | 17, 5, 12, 111, 24, 111, 25, 111, 199 | 26, 111, 27, 111, 5, 6, 16, 17, 200 | 5, 12, 111, 29, 111, 30, 111, 31, 201 | 111, 32, 111, 5, 6, 16, 17, 5, 202 | 12, 111, 34, 36, 111, 35, 111, 5, 203 | 6, 16, 17, 5, 12, 111, 37, 111, 204 | 38, 111, 39, 111, 40, 111, 5, 6, 205 | 16, 17, 5, 12, 111, 42, 44, 111, 206 | 43, 111, 5, 6, 16, 17, 5, 12, 207 | 111, 45, 111, 46, 111, 47, 111, 48, 208 | 111, 5, 6, 16, 17, 5, 12, 111, 209 | 50, 54, 59, 111, 51, 111, 52, 111, 210 | 53, 111, 5, 6, 16, 17, 5, 12, 211 | 111, 55, 111, 56, 111, 57, 111, 58, 212 | 111, 5, 6, 16, 17, 5, 12, 111, 213 | 60, 111, 61, 111, 62, 111, 5, 6, 214 | 16, 17, 5, 12, 111, 64, 111, 65, 215 | 69, 111, 66, 111, 67, 111, 68, 111, 216 | 5, 6, 16, 17, 5, 12, 111, 70, 217 | 111, 71, 111, 72, 111, 73, 111, 74, 218 | 111, 75, 111, 5, 6, 16, 17, 5, 219 | 12, 111, 77, 82, 88, 111, 78, 111, 220 | 79, 111, 80, 111, 81, 111, 5, 6, 221 | 16, 17, 5, 12, 111, 83, 111, 84, 222 | 111, 85, 111, 86, 111, 87, 111, 5, 223 | 6, 16, 17, 5, 12, 111, 89, 111, 224 | 90, 111, 91, 111, 5, 6, 16, 17, 225 | 5, 12, 111, 93, 98, 101, 106, 111, 226 | 94, 111, 95, 111, 96, 111, 97, 111, 227 | 5, 6, 16, 17, 5, 12, 111, 99, 228 | 111, 100, 111, 5, 6, 16, 17, 5, 229 | 12, 111, 102, 111, 103, 111, 104, 111, 230 | 105, 111, 5, 6, 16, 17, 5, 12, 231 | 111, 107, 111, 108, 111, 109, 111, 110, 232 | 111, 5, 6, 16, 17, 5, 12, 111, 233 | 111, 112, 116, 111, 120, 123, 123, 0, 234 | 113, 111, 115, 114, 111, 115, 111, 111, 235 | 117, 111, 119, 118, 111, 119, 111, 111, 236 | 122, 121, 123, 123, 111, 122, 123, 123, 237 | 111, 123, 123, 111, 124, 1, 124, 125, 238 | 111, 1, 125, 111, 1, 111, 1, 111, 239 | 111, 111, 111, 111, 111, 111, 111, 111, 240 | 111, 111, 111, 111, 111, 111, 111, 111, 241 | 111, 111, 111, 111, 111, 111, 111, 111, 242 | 111, 111, 111, 111, 111, 111, 111, 111, 243 | 111, 111, 111, 111, 111, 111, 111, 111, 244 | 111, 111, 111, 111, 111, 111, 111, 111, 245 | 111, 111, 111, 111, 111, 111, 111, 111, 246 | 111, 111, 111, 111, 111, 111, 111, 111, 247 | 111, 111, 111, 111, 111, 111, 111, 111, 248 | 111, 111, 111, 111, 111, 111, 111, 111, 249 | 111, 111, 111, 111, 111, 111, 111, 111, 250 | 111, 111, 111, 111, 111, 111, 111, 111, 251 | 111, 111, 111, 111, 111, 111, 111, 111, 252 | 111, 111, 111, 111, 111, 111, 111, 111, 253 | 111, 111, 111, 111, 111, 111, 111, 111, 254 | 111, 111, 111, 111, 111, 0 255 | }; 256 | 257 | static const char _bloopnotes_trans_actions[] = { 258 | 0, 0, 0, 0, 0, 0, 0, 0, 259 | 67, 0, 0, 0, 67, 0, 67, 39, 260 | 39, 39, 39, 39, 39, 67, 0, 0, 261 | 0, 0, 0, 67, 55, 55, 55, 67, 262 | 0, 0, 0, 0, 67, 0, 67, 5, 263 | 120, 0, 67, 7, 67, 116, 0, 67, 264 | 5, 112, 0, 67, 7, 67, 87, 0, 265 | 67, 0, 0, 67, 55, 55, 55, 0, 266 | 67, 0, 0, 0, 67, 0, 67, 0, 267 | 67, 0, 67, 0, 67, 41, 41, 41, 268 | 41, 41, 41, 67, 0, 67, 0, 67, 269 | 0, 67, 0, 67, 13, 13, 13, 13, 270 | 13, 13, 67, 0, 67, 0, 67, 0, 271 | 67, 0, 67, 17, 17, 17, 17, 17, 272 | 17, 67, 0, 0, 67, 0, 67, 35, 273 | 35, 35, 35, 35, 35, 67, 0, 67, 274 | 0, 67, 0, 67, 0, 67, 37, 37, 275 | 37, 37, 37, 37, 67, 0, 0, 67, 276 | 0, 67, 29, 29, 29, 29, 29, 29, 277 | 67, 0, 67, 0, 67, 0, 67, 0, 278 | 67, 31, 31, 31, 31, 31, 31, 67, 279 | 0, 0, 0, 67, 0, 67, 0, 67, 280 | 0, 67, 43, 43, 43, 43, 43, 43, 281 | 67, 0, 67, 0, 67, 0, 67, 0, 282 | 67, 45, 45, 45, 45, 45, 45, 67, 283 | 0, 67, 0, 67, 0, 67, 11, 11, 284 | 11, 11, 11, 11, 67, 0, 67, 0, 285 | 0, 67, 0, 67, 0, 67, 0, 67, 286 | 47, 47, 47, 47, 47, 47, 67, 0, 287 | 67, 0, 67, 0, 67, 0, 67, 0, 288 | 67, 0, 67, 33, 33, 33, 33, 33, 289 | 33, 67, 0, 0, 0, 67, 0, 67, 290 | 0, 67, 0, 67, 0, 67, 19, 19, 291 | 19, 19, 19, 19, 67, 0, 67, 0, 292 | 67, 0, 67, 0, 67, 0, 67, 15, 293 | 15, 15, 15, 15, 15, 67, 0, 67, 294 | 0, 67, 0, 67, 21, 21, 21, 21, 295 | 21, 21, 67, 0, 0, 0, 0, 67, 296 | 0, 67, 0, 67, 0, 67, 0, 67, 297 | 27, 27, 27, 27, 27, 27, 67, 0, 298 | 67, 0, 67, 23, 23, 23, 23, 23, 299 | 23, 67, 0, 67, 0, 67, 0, 67, 300 | 0, 67, 9, 9, 9, 9, 9, 9, 301 | 67, 0, 67, 0, 67, 0, 67, 0, 302 | 67, 25, 25, 25, 25, 25, 25, 67, 303 | 65, 0, 0, 65, 0, 63, 63, 0, 304 | 49, 78, 0, 0, 72, 0, 72, 72, 305 | 51, 81, 0, 0, 75, 0, 75, 75, 306 | 0, 0, 84, 84, 69, 0, 84, 84, 307 | 69, 84, 84, 69, 93, 57, 93, 93, 308 | 108, 53, 90, 104, 1, 96, 3, 100, 309 | 67, 67, 67, 67, 67, 67, 67, 67, 310 | 67, 67, 67, 67, 67, 67, 67, 67, 311 | 67, 67, 67, 67, 67, 67, 67, 67, 312 | 67, 67, 67, 67, 67, 67, 67, 67, 313 | 67, 67, 67, 67, 67, 67, 67, 67, 314 | 67, 67, 67, 67, 67, 67, 67, 67, 315 | 67, 67, 67, 67, 67, 67, 67, 67, 316 | 67, 67, 67, 67, 67, 67, 67, 67, 317 | 67, 67, 67, 67, 67, 67, 67, 67, 318 | 67, 67, 67, 67, 67, 67, 67, 67, 319 | 67, 67, 67, 67, 67, 67, 67, 67, 320 | 67, 67, 67, 67, 67, 67, 67, 67, 321 | 67, 67, 67, 67, 67, 67, 67, 67, 322 | 67, 67, 67, 67, 67, 67, 78, 72, 323 | 72, 72, 81, 75, 75, 75, 69, 69, 324 | 69, 108, 104, 96, 100, 0 325 | }; 326 | 327 | static const char _bloopnotes_to_state_actions[] = { 328 | 0, 0, 0, 0, 0, 0, 0, 0, 329 | 0, 0, 0, 0, 0, 0, 0, 0, 330 | 0, 0, 0, 0, 0, 0, 0, 0, 331 | 0, 0, 0, 0, 0, 0, 0, 0, 332 | 0, 0, 0, 0, 0, 0, 0, 0, 333 | 0, 0, 0, 0, 0, 0, 0, 0, 334 | 0, 0, 0, 0, 0, 0, 0, 0, 335 | 0, 0, 0, 0, 0, 0, 0, 0, 336 | 0, 0, 0, 0, 0, 0, 0, 0, 337 | 0, 0, 0, 0, 0, 0, 0, 0, 338 | 0, 0, 0, 0, 0, 0, 0, 0, 339 | 0, 0, 0, 0, 0, 0, 0, 0, 340 | 0, 0, 0, 0, 0, 0, 0, 0, 341 | 0, 0, 0, 0, 0, 0, 0, 59, 342 | 0, 0, 0, 0, 0, 0, 0, 0, 343 | 0, 0, 0, 0, 0, 0, 0 344 | }; 345 | 346 | static const char _bloopnotes_from_state_actions[] = { 347 | 0, 0, 0, 0, 0, 0, 0, 0, 348 | 0, 0, 0, 0, 0, 0, 0, 0, 349 | 0, 0, 0, 0, 0, 0, 0, 0, 350 | 0, 0, 0, 0, 0, 0, 0, 0, 351 | 0, 0, 0, 0, 0, 0, 0, 0, 352 | 0, 0, 0, 0, 0, 0, 0, 0, 353 | 0, 0, 0, 0, 0, 0, 0, 0, 354 | 0, 0, 0, 0, 0, 0, 0, 0, 355 | 0, 0, 0, 0, 0, 0, 0, 0, 356 | 0, 0, 0, 0, 0, 0, 0, 0, 357 | 0, 0, 0, 0, 0, 0, 0, 0, 358 | 0, 0, 0, 0, 0, 0, 0, 0, 359 | 0, 0, 0, 0, 0, 0, 0, 0, 360 | 0, 0, 0, 0, 0, 0, 0, 61, 361 | 0, 0, 0, 0, 0, 0, 0, 0, 362 | 0, 0, 0, 0, 0, 0, 0 363 | }; 364 | 365 | static const short _bloopnotes_eof_trans[] = { 366 | 0, 518, 518, 518, 518, 518, 518, 518, 367 | 518, 518, 518, 518, 518, 518, 518, 518, 368 | 518, 518, 518, 518, 518, 518, 518, 518, 369 | 518, 518, 518, 518, 518, 518, 518, 518, 370 | 518, 518, 518, 518, 518, 518, 518, 518, 371 | 518, 518, 518, 518, 518, 518, 518, 518, 372 | 518, 518, 518, 518, 518, 518, 518, 518, 373 | 518, 518, 518, 518, 518, 518, 518, 518, 374 | 518, 518, 518, 518, 518, 518, 518, 518, 375 | 518, 518, 518, 518, 518, 518, 518, 518, 376 | 518, 518, 518, 518, 518, 518, 518, 518, 377 | 518, 518, 518, 518, 518, 518, 518, 518, 378 | 518, 518, 518, 518, 518, 518, 518, 518, 379 | 518, 518, 518, 518, 518, 518, 518, 0, 380 | 519, 522, 522, 522, 523, 526, 526, 526, 381 | 529, 529, 529, 530, 531, 532, 533 382 | }; 383 | 384 | static const int bloopnotes_start = 111; 385 | static const int bloopnotes_error = 0; 386 | 387 | static const int bloopnotes_en_main = 111; 388 | 389 | #line 154 "c/notation.rl" 390 | 391 | 392 | extern void _bloops_track_add(bloops *B, bloopsatrack *track); 393 | 394 | bloopsatrack * 395 | bloops_track(bloops *B, bloopsaphone *P, char *track, int tracklen) 396 | { 397 | int cs, act, oct = 4, len = 4; 398 | bloopsatrack *S = (bloopsatrack *)malloc(sizeof(bloopsatrack)); 399 | char tone, mod, fxmod, *p, *pe, *pf, *ts, *te, *eof = 0; 400 | bloopsafxcmd fxcmd = (bloopsafxcmd)0; 401 | float fxval = 0; 402 | 403 | S->refcount = 1; 404 | S->nlen = 0; 405 | S->capa = 1024; 406 | S->notes = (bloopsanote *)calloc(sizeof(bloopsanote), 1024); 407 | 408 | p = track; 409 | pe = track + tracklen + 1; 410 | 411 | 412 | #line 413 "c/notation.c" 413 | { 414 | cs = bloopnotes_start; 415 | ts = 0; 416 | te = 0; 417 | act = 0; 418 | } 419 | #line 176 "c/notation.rl" 420 | 421 | #line 422 "c/notation.c" 422 | { 423 | int _klen; 424 | unsigned int _trans; 425 | const char *_acts; 426 | unsigned int _nacts; 427 | const char *_keys; 428 | 429 | if ( p == pe ) 430 | goto _test_eof; 431 | if ( cs == 0 ) 432 | goto _out; 433 | _resume: 434 | _acts = _bloopnotes_actions + _bloopnotes_from_state_actions[cs]; 435 | _nacts = (unsigned int) *_acts++; 436 | while ( _nacts-- > 0 ) { 437 | switch ( *_acts++ ) { 438 | case 34: 439 | #line 1 "c/notation.rl" 440 | {ts = p;} 441 | break; 442 | #line 443 "c/notation.c" 443 | } 444 | } 445 | 446 | _keys = _bloopnotes_trans_keys + _bloopnotes_key_offsets[cs]; 447 | _trans = _bloopnotes_index_offsets[cs]; 448 | 449 | _klen = _bloopnotes_single_lengths[cs]; 450 | if ( _klen > 0 ) { 451 | const char *_lower = _keys; 452 | const char *_mid; 453 | const char *_upper = _keys + _klen - 1; 454 | while (1) { 455 | if ( _upper < _lower ) 456 | break; 457 | 458 | _mid = _lower + ((_upper-_lower) >> 1); 459 | if ( (*p) < *_mid ) 460 | _upper = _mid - 1; 461 | else if ( (*p) > *_mid ) 462 | _lower = _mid + 1; 463 | else { 464 | _trans += (_mid - _keys); 465 | goto _match; 466 | } 467 | } 468 | _keys += _klen; 469 | _trans += _klen; 470 | } 471 | 472 | _klen = _bloopnotes_range_lengths[cs]; 473 | if ( _klen > 0 ) { 474 | const char *_lower = _keys; 475 | const char *_mid; 476 | const char *_upper = _keys + (_klen<<1) - 2; 477 | while (1) { 478 | if ( _upper < _lower ) 479 | break; 480 | 481 | _mid = _lower + (((_upper-_lower) >> 1) & ~1); 482 | if ( (*p) < _mid[0] ) 483 | _upper = _mid - 2; 484 | else if ( (*p) > _mid[1] ) 485 | _lower = _mid + 2; 486 | else { 487 | _trans += ((_mid - _keys)>>1); 488 | goto _match; 489 | } 490 | } 491 | _trans += _klen; 492 | } 493 | 494 | _match: 495 | _eof_trans: 496 | cs = _bloopnotes_trans_targs[_trans]; 497 | 498 | if ( _bloopnotes_trans_actions[_trans] == 0 ) 499 | goto _again; 500 | 501 | _acts = _bloopnotes_actions + _bloopnotes_trans_actions[_trans]; 502 | _nacts = (unsigned int) *_acts++; 503 | while ( _nacts-- > 0 ) 504 | { 505 | switch ( *_acts++ ) 506 | { 507 | case 0: 508 | #line 44 "c/notation.rl" 509 | { 510 | len = ATOI(ts, p - ts); 511 | } 512 | break; 513 | case 1: 514 | #line 48 "c/notation.rl" 515 | { 516 | oct = ATOI(p - 1, 1); 517 | } 518 | break; 519 | case 2: 520 | #line 52 "c/notation.rl" 521 | { 522 | switch (tone) { 523 | case 'a': case 'A': 524 | if (mod == 'b') NOTE.tone = 'a'; 525 | else if (mod == '#') NOTE.tone = 'b'; 526 | else NOTE.tone = 'A'; 527 | break; 528 | case 'b': case 'B': 529 | if (mod == 'b') NOTE.tone = 'b'; 530 | else if (mod == '#') NOTE.tone = 'C'; 531 | else NOTE.tone = 'B'; 532 | break; 533 | case 'c': case 'C': 534 | if (mod == 'b') NOTE.tone = 'B'; 535 | else if (mod == '#') NOTE.tone = 'd'; 536 | else NOTE.tone = 'C'; 537 | break; 538 | case 'd': case 'D': 539 | if (mod == 'b') NOTE.tone = 'd'; 540 | else if (mod == '#') NOTE.tone = 'e'; 541 | else NOTE.tone = 'D'; 542 | break; 543 | case 'e': case 'E': 544 | if (mod == 'b') NOTE.tone = 'e'; 545 | else if (mod == '#') NOTE.tone = 'F'; 546 | else NOTE.tone = 'E'; 547 | break; 548 | case 'f': case 'F': 549 | if (mod == 'b') NOTE.tone = 'E'; 550 | else if (mod == '#') NOTE.tone = 'g'; 551 | else NOTE.tone = 'F'; 552 | break; 553 | case 'g': case 'G': 554 | if (mod == 'b') NOTE.tone = 'g'; 555 | else if (mod == '#') NOTE.tone = 'a'; 556 | else NOTE.tone = 'G'; 557 | break; 558 | } 559 | } 560 | break; 561 | case 3: 562 | #line 92 "c/notation.rl" 563 | { 564 | bloopsafx *fx = (bloopsafx *)malloc(sizeof(bloopsafx)); 565 | fx->next = NOTE.FX; 566 | fx->cmd = fxcmd; 567 | fx->val = fxval; 568 | fx->mod = fxmod; 569 | fxval = fxmod = 0; 570 | NOTE.FX = fx; 571 | } 572 | break; 573 | case 4: 574 | #line 102 "c/notation.rl" 575 | { 576 | fxval = atoi(p-1) * 1.0f; 577 | } 578 | break; 579 | case 5: 580 | #line 106 "c/notation.rl" 581 | { 582 | fxval += ATOI(pf, p - pf) * pow(0.1f, p - pf); 583 | } 584 | break; 585 | case 6: 586 | #line 110 "c/notation.rl" 587 | { pf = p; } 588 | break; 589 | case 7: 590 | #line 111 "c/notation.rl" 591 | { fxval *= -1.0f; } 592 | break; 593 | case 8: 594 | #line 112 "c/notation.rl" 595 | { fxcmd = BLOOPS_FX_VOLUME; } 596 | break; 597 | case 9: 598 | #line 113 "c/notation.rl" 599 | { fxcmd = BLOOPS_FX_PUNCH; } 600 | break; 601 | case 10: 602 | #line 114 "c/notation.rl" 603 | { fxcmd = BLOOPS_FX_ATTACK; } 604 | break; 605 | case 11: 606 | #line 115 "c/notation.rl" 607 | { fxcmd = BLOOPS_FX_SUSTAIN; } 608 | break; 609 | case 12: 610 | #line 116 "c/notation.rl" 611 | { fxcmd = BLOOPS_FX_DECAY; } 612 | break; 613 | case 13: 614 | #line 117 "c/notation.rl" 615 | { fxcmd = BLOOPS_FX_SQUARE; } 616 | break; 617 | case 14: 618 | #line 118 "c/notation.rl" 619 | { fxcmd = BLOOPS_FX_SWEEP; } 620 | break; 621 | case 15: 622 | #line 119 "c/notation.rl" 623 | { fxcmd = BLOOPS_FX_VIBE; } 624 | break; 625 | case 16: 626 | #line 120 "c/notation.rl" 627 | { fxcmd = BLOOPS_FX_VSPEED; } 628 | break; 629 | case 17: 630 | #line 121 "c/notation.rl" 631 | { fxcmd = BLOOPS_FX_VDELAY; } 632 | break; 633 | case 18: 634 | #line 122 "c/notation.rl" 635 | { fxcmd = BLOOPS_FX_LPF; } 636 | break; 637 | case 19: 638 | #line 123 "c/notation.rl" 639 | { fxcmd = BLOOPS_FX_LSWEEP; } 640 | break; 641 | case 20: 642 | #line 124 "c/notation.rl" 643 | { fxcmd = BLOOPS_FX_RESONANCE; } 644 | break; 645 | case 21: 646 | #line 125 "c/notation.rl" 647 | { fxcmd = BLOOPS_FX_HPF; } 648 | break; 649 | case 22: 650 | #line 126 "c/notation.rl" 651 | { fxcmd = BLOOPS_FX_HSWEEP; } 652 | break; 653 | case 23: 654 | #line 127 "c/notation.rl" 655 | { fxcmd = BLOOPS_FX_ARP; } 656 | break; 657 | case 24: 658 | #line 128 "c/notation.rl" 659 | { fxcmd = BLOOPS_FX_ASPEED; } 660 | break; 661 | case 25: 662 | #line 129 "c/notation.rl" 663 | { fxcmd = BLOOPS_FX_PHASE; } 664 | break; 665 | case 26: 666 | #line 130 "c/notation.rl" 667 | { fxcmd = BLOOPS_FX_PSWEEP; } 668 | break; 669 | case 27: 670 | #line 131 "c/notation.rl" 671 | { fxcmd = BLOOPS_FX_REPEAT; } 672 | break; 673 | case 28: 674 | #line 134 "c/notation.rl" 675 | { len = 1; } 676 | break; 677 | case 29: 678 | #line 135 "c/notation.rl" 679 | { len = 1; } 680 | break; 681 | case 30: 682 | #line 136 "c/notation.rl" 683 | { mod = p[-1]; } 684 | break; 685 | case 31: 686 | #line 138 "c/notation.rl" 687 | { fxmod = p[-1]; } 688 | break; 689 | case 32: 690 | #line 140 "c/notation.rl" 691 | { tone = p[-1]; } 692 | break; 693 | case 35: 694 | #line 1 "c/notation.rl" 695 | {te = p+1;} 696 | break; 697 | case 36: 698 | #line 150 "c/notation.rl" 699 | {te = p+1;} 700 | break; 701 | case 37: 702 | #line 143 "c/notation.rl" 703 | {te = p;p--;{ 704 | NOTE.tone = 0; 705 | NEXT(); 706 | }} 707 | break; 708 | case 38: 709 | #line 147 "c/notation.rl" 710 | {te = p;p--;{ NEXT(); }} 711 | break; 712 | case 39: 713 | #line 148 "c/notation.rl" 714 | {te = p;p--;{ oct++; len = 4; }} 715 | break; 716 | case 40: 717 | #line 149 "c/notation.rl" 718 | {te = p;p--;{ oct--; len = 4; }} 719 | break; 720 | case 41: 721 | #line 147 "c/notation.rl" 722 | {{p = ((te))-1;}{ NEXT(); }} 723 | break; 724 | #line 725 "c/notation.c" 725 | } 726 | } 727 | 728 | _again: 729 | _acts = _bloopnotes_actions + _bloopnotes_to_state_actions[cs]; 730 | _nacts = (unsigned int) *_acts++; 731 | while ( _nacts-- > 0 ) { 732 | switch ( *_acts++ ) { 733 | case 33: 734 | #line 1 "c/notation.rl" 735 | {ts = 0;} 736 | break; 737 | #line 738 "c/notation.c" 738 | } 739 | } 740 | 741 | if ( cs == 0 ) 742 | goto _out; 743 | if ( ++p != pe ) 744 | goto _resume; 745 | _test_eof: {} 746 | if ( p == eof ) 747 | { 748 | if ( _bloopnotes_eof_trans[cs] > 0 ) { 749 | _trans = _bloopnotes_eof_trans[cs] - 1; 750 | goto _eof_trans; 751 | } 752 | } 753 | 754 | _out: {} 755 | } 756 | #line 177 "c/notation.rl" 757 | 758 | memcpy(&S->params, &P->params, sizeof(bloopsaparams)); 759 | 760 | _bloops_track_add(B, S); 761 | 762 | return S; 763 | } 764 | 765 | bloopsatrack * 766 | bloops_track2(bloops *B, bloopsaphone *P, char *track) 767 | { 768 | return bloops_track(B, P, track, strlen(track)); 769 | } 770 | 771 | char * 772 | bloops_track_str(bloopsatrack *track) 773 | { 774 | int bufsize = sizeof(char) * (track->nlen * 6 + 1024); 775 | char *str = (char *)malloc(bufsize), *ptr = str; 776 | int i, adv = 0; 777 | 778 | for (i = 0; i < track->nlen; i++) 779 | { 780 | if (ptr - str + adv + sizeof(char) * 256 > bufsize) { 781 | char *new_str; 782 | bufsize += sizeof(char) * 1024; 783 | new_str = realloc(str, bufsize); 784 | if (new_str == NULL) { 785 | free(str); 786 | return NULL; 787 | } 788 | } 789 | 790 | if (ptr > str) 791 | strcat(ptr++, " "); 792 | 793 | if (track->notes[i].duration != 4) 794 | { 795 | adv = sprintf(ptr, "%d:", (int)track->notes[i].duration); 796 | ptr += adv; 797 | } 798 | 799 | if (track->notes[i].tone) 800 | { 801 | char tone[3] = "\0\0\0"; 802 | tone[0] = track->notes[i].tone; 803 | switch (tone[0]) { 804 | case 'a': tone[0] = 'A'; tone[1] = 'b'; break; 805 | case 'b': tone[0] = 'B'; tone[1] = 'b'; break; 806 | case 'd': tone[0] = 'C'; tone[1] = '#'; break; 807 | case 'e': tone[0] = 'E'; tone[1] = 'b'; break; 808 | case 'g': tone[0] = 'F'; tone[1] = '#'; break; 809 | } 810 | adv = sprintf(ptr, "%s", tone); 811 | ptr += adv; 812 | 813 | adv = sprintf(ptr, "%d", (int)track->notes[i].octave); 814 | ptr += adv; 815 | bloopsafx *fx = (bloopsafx *)track->notes[i].FX; 816 | while (fx) { 817 | if (fx->mod == 0) 818 | adv = sprintf(ptr, "[%s %0.3f]", bloops_fxcmd_name(fx->cmd), fx->val); 819 | else 820 | adv = sprintf(ptr, "[%s %c %0.3f]", bloops_fxcmd_name(fx->cmd), fx->mod, fx->val); 821 | ptr += adv; 822 | fx = (bloopsafx *)fx->next; 823 | } 824 | } 825 | } 826 | 827 | return str; 828 | } 829 | 830 | char * 831 | bloops_fxcmd_name(bloopsafxcmd fxcmd) { 832 | char *fxname = "\0"; 833 | switch (fxcmd) { 834 | case BLOOPS_FX_VOLUME: fxname = "volume"; break; 835 | case BLOOPS_FX_PUNCH: fxname = "punch"; break; 836 | case BLOOPS_FX_ATTACK: fxname = "attack"; break; 837 | case BLOOPS_FX_SUSTAIN: fxname = "sustain"; break; 838 | case BLOOPS_FX_DECAY: fxname = "decay"; break; 839 | case BLOOPS_FX_SQUARE: fxname = "square"; break; 840 | case BLOOPS_FX_SWEEP: fxname = "sweep"; break; 841 | case BLOOPS_FX_VIBE: fxname = "vibe"; break; 842 | case BLOOPS_FX_VSPEED: fxname = "vspeed"; break; 843 | case BLOOPS_FX_VDELAY: fxname = "vdelay"; break; 844 | case BLOOPS_FX_LPF: fxname = "lpf"; break; 845 | case BLOOPS_FX_LSWEEP: fxname = "lsweep"; break; 846 | case BLOOPS_FX_RESONANCE: fxname = "resonance"; break; 847 | case BLOOPS_FX_HPF: fxname = "hpf"; break; 848 | case BLOOPS_FX_HSWEEP: fxname = "hsweep"; break; 849 | case BLOOPS_FX_ARP: fxname = "arp"; break; 850 | case BLOOPS_FX_ASPEED: fxname = "aspeed"; break; 851 | case BLOOPS_FX_PHASE: fxname = "phase"; break; 852 | case BLOOPS_FX_PSWEEP: fxname = "psweep"; break; 853 | case BLOOPS_FX_REPEAT: fxname = "repeat"; break; 854 | } 855 | return fxname; 856 | } 857 | 858 | float 859 | bloops_note_freq(char note, int octave) 860 | { 861 | switch (note) 862 | { 863 | case 'A': // A 864 | if (octave <= 0) return 0.0; 865 | else if (octave == 1) return 0.121; 866 | else if (octave == 2) return 0.175; 867 | else if (octave == 3) return 0.248; 868 | else if (octave == 4) return 0.353; 869 | else if (octave == 5) return 0.500; 870 | break; 871 | 872 | case 'b': // A# or Bb 873 | if (octave <= 0) return 0.0; 874 | else if (octave == 1) return 0.125; 875 | else if (octave == 2) return 0.181; 876 | else if (octave == 3) return 0.255; 877 | else if (octave == 4) return 0.364; 878 | else if (octave == 5) return 0.515; 879 | break; 880 | 881 | case 'B': // B 882 | if (octave <= 0) return 0.0; 883 | else if (octave == 1) return 0.129; 884 | else if (octave == 2) return 0.187; 885 | else if (octave == 3) return 0.263; 886 | else if (octave == 4) return 0.374; 887 | else if (octave == 5) return 0.528; 888 | break; 889 | 890 | case 'C': // C 891 | if (octave <= 1) return 0.0; 892 | else if (octave == 2) return 0.133; 893 | else if (octave == 3) return 0.192; 894 | else if (octave == 4) return 0.271; 895 | else if (octave == 5) return 0.385; 896 | else if (octave == 6) return 0.544; 897 | break; 898 | 899 | case 'd': // C# or Db 900 | if (octave <= 1) return 0.0; 901 | else if (octave == 2) return 0.138; 902 | else if (octave == 3) return 0.198; 903 | else if (octave == 4) return 0.279; 904 | else if (octave == 5) return 0.395; 905 | else if (octave == 6) return 0.559; 906 | break; 907 | 908 | case 'D': // D 909 | if (octave <= 1) return 0.0; 910 | else if (octave == 2) return 0.143; 911 | else if (octave == 3) return 0.202; 912 | else if (octave == 4) return 0.287; 913 | else if (octave == 5) return 0.406; 914 | else if (octave == 6) return 0.575; 915 | break; 916 | 917 | case 'e': // D# or Eb 918 | if (octave <= 1) return 0.0; 919 | else if (octave == 2) return 0.148; 920 | else if (octave == 3) return 0.208; 921 | else if (octave == 4) return 0.296; 922 | else if (octave == 5) return 0.418; 923 | else if (octave == 6) return 0.593; 924 | break; 925 | 926 | case 'E': // E 927 | if (octave <= 1) return 0.0; 928 | else if (octave == 2) return 0.152; 929 | else if (octave == 3) return 0.214; 930 | else if (octave == 4) return 0.305; 931 | else if (octave == 5) return 0.429; 932 | else if (octave == 6) return 0.608; 933 | break; 934 | 935 | case 'F': // F 936 | if (octave <= 1) return 0.0; 937 | else if (octave == 2) return 0.155; 938 | else if (octave == 3) return 0.220; 939 | else if (octave == 4) return 0.314; 940 | else if (octave == 5) return 0.441; 941 | break; 942 | 943 | case 'g': // F# or Gb 944 | if (octave <= 1) return 0.0; 945 | else if (octave == 2) return 0.160; 946 | else if (octave == 3) return 0.227; 947 | else if (octave == 4) return 0.323; 948 | else if (octave == 5) return 0.454; 949 | break; 950 | 951 | case 'G': // G 952 | if (octave <= 1) return 0.0; 953 | else if (octave == 2) return 0.164; 954 | else if (octave == 3) return 0.234; 955 | else if (octave == 4) return 0.332; 956 | else if (octave == 5) return 0.468; 957 | break; 958 | 959 | case 'a': // G# or Ab 960 | if (octave <= 1) return 0.117; 961 | else if (octave == 2) return 0.170; 962 | else if (octave == 3) return 0.242; 963 | else if (octave == 4) return 0.343; 964 | else if (octave == 5) return 0.485; 965 | break; 966 | } 967 | 968 | return 0.0; 969 | } 970 | 971 | #define KEY(name) key = (void *)&P->params.name 972 | 973 | 974 | #line 975 "c/notation.c" 975 | static const char _bloopserial_actions[] = { 976 | 0, 1, 0, 1, 1, 1, 2, 1, 977 | 5, 1, 6, 1, 7, 1, 8, 1, 978 | 9, 1, 10, 1, 11, 1, 12, 1, 979 | 13, 1, 14, 1, 15, 1, 16, 1, 980 | 17, 1, 18, 1, 19, 1, 20, 1, 981 | 21, 1, 22, 1, 23, 1, 24, 1, 982 | 25, 1, 26, 1, 27, 1, 29, 1, 983 | 30, 1, 31, 1, 32, 1, 33, 1, 984 | 34, 1, 35, 1, 36, 2, 1, 3, 985 | 2, 1, 35, 2, 4, 28, 3, 1, 986 | 3, 35 987 | }; 988 | 989 | static const unsigned char _bloopserial_key_offsets[] = { 990 | 0, 0, 3, 4, 7, 13, 15, 18, 991 | 20, 23, 25, 26, 27, 28, 29, 32, 992 | 33, 34, 35, 36, 39, 41, 42, 43, 993 | 44, 47, 48, 49, 50, 51, 54, 55, 994 | 56, 57, 60, 62, 63, 66, 67, 68, 995 | 69, 70, 73, 76, 77, 78, 79, 82, 996 | 83, 86, 87, 88, 89, 90, 93, 96, 997 | 97, 98, 99, 102, 103, 104, 105, 106, 998 | 109, 110, 111, 112, 115, 116, 118, 119, 999 | 120, 121, 124, 125, 126, 127, 128, 129, 1000 | 130, 133, 137, 138, 139, 140, 143, 144, 1001 | 145, 146, 147, 150, 151, 152, 153, 154, 1002 | 155, 158, 159, 160, 161, 164, 165, 166, 1003 | 167, 170, 175, 176, 177, 178, 179, 182, 1004 | 183, 184, 185, 186, 187, 188, 189, 190, 1005 | 191, 192, 193, 194, 198, 199, 200, 201, 1006 | 202, 205, 206, 207, 210, 211, 212, 213, 1007 | 214, 217, 218, 219, 220, 221, 224, 237, 1008 | 240, 245, 248 1009 | }; 1010 | 1011 | static const char _bloopserial_trans_keys[] = { 1012 | 114, 115, 116, 112, 32, 9, 13, 32, 1013 | 45, 9, 13, 48, 57, 48, 57, 46, 1014 | 48, 57, 48, 57, 46, 48, 57, 48, 1015 | 57, 112, 101, 101, 100, 32, 9, 13, 1016 | 116, 97, 99, 107, 32, 9, 13, 101, 1017 | 115, 99, 97, 121, 32, 9, 13, 108, 1018 | 105, 100, 101, 32, 9, 13, 114, 101, 1019 | 113, 32, 9, 13, 112, 115, 102, 32, 1020 | 9, 13, 119, 101, 101, 112, 32, 9, 1021 | 13, 105, 112, 115, 109, 105, 116, 32, 1022 | 9, 13, 102, 32, 9, 13, 119, 101, 1023 | 101, 112, 32, 9, 13, 104, 115, 117, 1024 | 97, 115, 101, 32, 9, 13, 119, 101, 1025 | 101, 112, 32, 9, 13, 110, 99, 104, 1026 | 32, 9, 13, 101, 112, 115, 101, 97, 1027 | 116, 32, 9, 13, 111, 110, 97, 110, 1028 | 99, 101, 32, 9, 13, 108, 113, 117, 1029 | 119, 105, 100, 101, 32, 9, 13, 117, 1030 | 97, 114, 101, 32, 9, 13, 115, 116, 1031 | 97, 105, 110, 32, 9, 13, 101, 101, 1032 | 112, 32, 9, 13, 121, 112, 101, 32, 1033 | 9, 13, 32, 110, 115, 9, 13, 111, 1034 | 105, 115, 101, 97, 105, 113, 119, 116, 1035 | 111, 111, 116, 104, 110, 101, 117, 97, 1036 | 114, 101, 100, 105, 111, 115, 101, 108, 1037 | 97, 121, 32, 9, 13, 98, 101, 32, 1038 | 9, 13, 108, 117, 109, 101, 32, 9, 1039 | 13, 112, 101, 101, 100, 32, 9, 13, 1040 | 32, 97, 100, 102, 104, 108, 112, 114, 1041 | 115, 116, 118, 9, 13, 32, 9, 13, 1042 | 32, 9, 13, 48, 57, 32, 9, 13, 1043 | 32, 9, 13, 48, 57, 0 1044 | }; 1045 | 1046 | static const char _bloopserial_single_lengths[] = { 1047 | 0, 3, 1, 1, 2, 0, 1, 0, 1048 | 1, 0, 1, 1, 1, 1, 1, 1, 1049 | 1, 1, 1, 1, 2, 1, 1, 1, 1050 | 1, 1, 1, 1, 1, 1, 1, 1, 1051 | 1, 1, 2, 1, 1, 1, 1, 1, 1052 | 1, 1, 3, 1, 1, 1, 1, 1, 1053 | 1, 1, 1, 1, 1, 1, 3, 1, 1054 | 1, 1, 1, 1, 1, 1, 1, 1, 1055 | 1, 1, 1, 1, 1, 2, 1, 1, 1056 | 1, 1, 1, 1, 1, 1, 1, 1, 1057 | 1, 4, 1, 1, 1, 1, 1, 1, 1058 | 1, 1, 1, 1, 1, 1, 1, 1, 1059 | 1, 1, 1, 1, 1, 1, 1, 1, 1060 | 1, 3, 1, 1, 1, 1, 3, 1, 1061 | 1, 1, 1, 1, 1, 1, 1, 1, 1062 | 1, 1, 1, 4, 1, 1, 1, 1, 1063 | 1, 1, 1, 1, 1, 1, 1, 1, 1064 | 1, 1, 1, 1, 1, 1, 11, 1, 1065 | 1, 1, 1 1066 | }; 1067 | 1068 | static const char _bloopserial_range_lengths[] = { 1069 | 0, 0, 0, 1, 2, 1, 1, 1, 1070 | 1, 1, 0, 0, 0, 0, 1, 0, 1071 | 0, 0, 0, 1, 0, 0, 0, 0, 1072 | 1, 0, 0, 0, 0, 1, 0, 0, 1073 | 0, 1, 0, 0, 1, 0, 0, 0, 1074 | 0, 1, 0, 0, 0, 0, 1, 0, 1075 | 1, 0, 0, 0, 0, 1, 0, 0, 1076 | 0, 0, 1, 0, 0, 0, 0, 1, 1077 | 0, 0, 0, 1, 0, 0, 0, 0, 1078 | 0, 1, 0, 0, 0, 0, 0, 0, 1079 | 1, 0, 0, 0, 0, 1, 0, 0, 1080 | 0, 0, 1, 0, 0, 0, 0, 0, 1081 | 1, 0, 0, 0, 1, 0, 0, 0, 1082 | 1, 1, 0, 0, 0, 0, 0, 0, 1083 | 0, 0, 0, 0, 0, 0, 0, 0, 1084 | 0, 0, 0, 0, 0, 0, 0, 0, 1085 | 1, 0, 0, 1, 0, 0, 0, 0, 1086 | 1, 0, 0, 0, 0, 1, 1, 1, 1087 | 2, 1, 2 1088 | }; 1089 | 1090 | static const short _bloopserial_index_offsets[] = { 1091 | 0, 0, 4, 6, 9, 14, 16, 19, 1092 | 21, 24, 26, 28, 30, 32, 34, 37, 1093 | 39, 41, 43, 45, 48, 51, 53, 55, 1094 | 57, 60, 62, 64, 66, 68, 71, 73, 1095 | 75, 77, 80, 83, 85, 88, 90, 92, 1096 | 94, 96, 99, 103, 105, 107, 109, 112, 1097 | 114, 117, 119, 121, 123, 125, 128, 132, 1098 | 134, 136, 138, 141, 143, 145, 147, 149, 1099 | 152, 154, 156, 158, 161, 163, 166, 168, 1100 | 170, 172, 175, 177, 179, 181, 183, 185, 1101 | 187, 190, 195, 197, 199, 201, 204, 206, 1102 | 208, 210, 212, 215, 217, 219, 221, 223, 1103 | 225, 228, 230, 232, 234, 237, 239, 241, 1104 | 243, 246, 251, 253, 255, 257, 259, 263, 1105 | 265, 267, 269, 271, 273, 275, 277, 279, 1106 | 281, 283, 285, 287, 292, 294, 296, 298, 1107 | 300, 303, 305, 307, 310, 312, 314, 316, 1108 | 318, 321, 323, 325, 327, 329, 332, 345, 1109 | 348, 352, 355 1110 | }; 1111 | 1112 | static const unsigned char _bloopserial_trans_targs[] = { 1113 | 2, 10, 15, 0, 3, 0, 4, 4, 1114 | 0, 4, 5, 4, 8, 0, 6, 0, 1115 | 7, 6, 0, 144, 0, 9, 8, 0, 1116 | 146, 0, 11, 0, 12, 0, 13, 0, 1117 | 14, 0, 4, 4, 0, 16, 0, 17, 1118 | 0, 18, 0, 19, 0, 4, 4, 0, 1119 | 21, 25, 0, 22, 0, 23, 0, 24, 1120 | 0, 4, 4, 0, 26, 0, 27, 0, 1121 | 28, 0, 29, 0, 4, 4, 0, 31, 1122 | 0, 32, 0, 33, 0, 4, 4, 0, 1123 | 35, 37, 0, 36, 0, 4, 4, 0, 1124 | 38, 0, 39, 0, 40, 0, 41, 0, 1125 | 4, 4, 0, 43, 47, 49, 0, 44, 1126 | 0, 45, 0, 46, 0, 4, 4, 0, 1127 | 48, 0, 4, 4, 0, 50, 0, 51, 1128 | 0, 52, 0, 53, 0, 4, 4, 0, 1129 | 55, 59, 64, 0, 56, 0, 57, 0, 1130 | 58, 0, 4, 4, 0, 60, 0, 61, 1131 | 0, 62, 0, 63, 0, 4, 4, 0, 1132 | 65, 0, 66, 0, 67, 0, 4, 4, 1133 | 0, 69, 0, 70, 74, 0, 71, 0, 1134 | 72, 0, 73, 0, 4, 4, 0, 75, 1135 | 0, 76, 0, 77, 0, 78, 0, 79, 1136 | 0, 80, 0, 4, 4, 0, 82, 86, 1137 | 91, 97, 0, 83, 0, 84, 0, 85, 1138 | 0, 4, 4, 0, 87, 0, 88, 0, 1139 | 89, 0, 90, 0, 4, 4, 0, 92, 1140 | 0, 93, 0, 94, 0, 95, 0, 96, 1141 | 0, 4, 4, 0, 98, 0, 99, 0, 1142 | 100, 0, 4, 4, 0, 102, 0, 103, 1143 | 0, 104, 0, 105, 105, 0, 105, 106, 1144 | 110, 105, 0, 107, 0, 108, 0, 109, 1145 | 0, 142, 0, 111, 117, 119, 0, 112, 1146 | 0, 113, 0, 114, 0, 115, 0, 116, 1147 | 0, 142, 0, 118, 0, 142, 0, 120, 1148 | 0, 121, 0, 122, 0, 142, 0, 124, 1149 | 129, 132, 137, 0, 125, 0, 126, 0, 1150 | 127, 0, 128, 0, 4, 4, 0, 130, 1151 | 0, 131, 0, 4, 4, 0, 133, 0, 1152 | 134, 0, 135, 0, 136, 0, 4, 4, 1153 | 0, 138, 0, 139, 0, 140, 0, 141, 1154 | 0, 4, 4, 0, 143, 1, 20, 30, 1155 | 34, 42, 54, 68, 81, 101, 123, 143, 1156 | 0, 143, 143, 142, 145, 145, 144, 142, 1157 | 145, 145, 142, 145, 145, 146, 142, 142, 1158 | 142, 142, 142, 0 1159 | }; 1160 | 1161 | static const char _bloopserial_trans_actions[] = { 1162 | 0, 0, 0, 0, 0, 0, 7, 7, 1163 | 0, 0, 0, 0, 0, 0, 0, 0, 1164 | 1, 0, 0, 5, 0, 1, 0, 0, 1165 | 5, 0, 0, 0, 0, 0, 0, 0, 1166 | 0, 0, 9, 9, 0, 0, 0, 0, 1167 | 0, 0, 0, 0, 0, 11, 11, 0, 1168 | 0, 0, 0, 0, 0, 0, 0, 0, 1169 | 0, 13, 13, 0, 0, 0, 0, 0, 1170 | 0, 0, 0, 0, 15, 15, 0, 0, 1171 | 0, 0, 0, 0, 0, 17, 17, 0, 1172 | 0, 0, 0, 0, 0, 19, 19, 0, 1173 | 0, 0, 0, 0, 0, 0, 0, 0, 1174 | 21, 21, 0, 0, 0, 0, 0, 0, 1175 | 0, 0, 0, 0, 0, 23, 23, 0, 1176 | 0, 0, 25, 25, 0, 0, 0, 0, 1177 | 0, 0, 0, 0, 0, 27, 27, 0, 1178 | 0, 0, 0, 0, 0, 0, 0, 0, 1179 | 0, 0, 29, 29, 0, 0, 0, 0, 1180 | 0, 0, 0, 0, 0, 31, 31, 0, 1181 | 0, 0, 0, 0, 0, 0, 45, 45, 1182 | 0, 0, 0, 0, 0, 0, 0, 0, 1183 | 0, 0, 0, 0, 33, 33, 0, 0, 1184 | 0, 0, 0, 0, 0, 0, 0, 0, 1185 | 0, 0, 0, 35, 35, 0, 0, 0, 1186 | 0, 0, 0, 0, 0, 0, 0, 0, 1187 | 0, 37, 37, 0, 0, 0, 0, 0, 1188 | 0, 0, 0, 0, 39, 39, 0, 0, 1189 | 0, 0, 0, 0, 0, 0, 0, 0, 1190 | 0, 41, 41, 0, 0, 0, 0, 0, 1191 | 0, 0, 43, 43, 0, 0, 0, 0, 1192 | 0, 0, 0, 0, 0, 0, 0, 0, 1193 | 0, 0, 0, 0, 0, 0, 0, 0, 1194 | 0, 63, 0, 0, 0, 0, 0, 0, 1195 | 0, 0, 0, 0, 0, 0, 0, 0, 1196 | 0, 59, 0, 0, 0, 61, 0, 0, 1197 | 0, 0, 0, 0, 0, 57, 0, 0, 1198 | 0, 0, 0, 0, 0, 0, 0, 0, 1199 | 0, 0, 0, 0, 51, 51, 0, 0, 1200 | 0, 0, 0, 47, 47, 0, 0, 0, 1201 | 0, 0, 0, 0, 0, 0, 75, 75, 1202 | 0, 0, 0, 0, 0, 0, 0, 0, 1203 | 0, 49, 49, 0, 0, 0, 0, 0, 1204 | 0, 0, 0, 0, 0, 0, 0, 0, 1205 | 0, 0, 0, 67, 69, 69, 0, 78, 1206 | 0, 0, 65, 3, 3, 0, 72, 67, 1207 | 78, 65, 72, 0 1208 | }; 1209 | 1210 | static const char _bloopserial_to_state_actions[] = { 1211 | 0, 0, 0, 0, 0, 0, 0, 0, 1212 | 0, 0, 0, 0, 0, 0, 0, 0, 1213 | 0, 0, 0, 0, 0, 0, 0, 0, 1214 | 0, 0, 0, 0, 0, 0, 0, 0, 1215 | 0, 0, 0, 0, 0, 0, 0, 0, 1216 | 0, 0, 0, 0, 0, 0, 0, 0, 1217 | 0, 0, 0, 0, 0, 0, 0, 0, 1218 | 0, 0, 0, 0, 0, 0, 0, 0, 1219 | 0, 0, 0, 0, 0, 0, 0, 0, 1220 | 0, 0, 0, 0, 0, 0, 0, 0, 1221 | 0, 0, 0, 0, 0, 0, 0, 0, 1222 | 0, 0, 0, 0, 0, 0, 0, 0, 1223 | 0, 0, 0, 0, 0, 0, 0, 0, 1224 | 0, 0, 0, 0, 0, 0, 0, 0, 1225 | 0, 0, 0, 0, 0, 0, 0, 0, 1226 | 0, 0, 0, 0, 0, 0, 0, 0, 1227 | 0, 0, 0, 0, 0, 0, 0, 0, 1228 | 0, 0, 0, 0, 0, 0, 53, 0, 1229 | 0, 0, 0 1230 | }; 1231 | 1232 | static const char _bloopserial_from_state_actions[] = { 1233 | 0, 0, 0, 0, 0, 0, 0, 0, 1234 | 0, 0, 0, 0, 0, 0, 0, 0, 1235 | 0, 0, 0, 0, 0, 0, 0, 0, 1236 | 0, 0, 0, 0, 0, 0, 0, 0, 1237 | 0, 0, 0, 0, 0, 0, 0, 0, 1238 | 0, 0, 0, 0, 0, 0, 0, 0, 1239 | 0, 0, 0, 0, 0, 0, 0, 0, 1240 | 0, 0, 0, 0, 0, 0, 0, 0, 1241 | 0, 0, 0, 0, 0, 0, 0, 0, 1242 | 0, 0, 0, 0, 0, 0, 0, 0, 1243 | 0, 0, 0, 0, 0, 0, 0, 0, 1244 | 0, 0, 0, 0, 0, 0, 0, 0, 1245 | 0, 0, 0, 0, 0, 0, 0, 0, 1246 | 0, 0, 0, 0, 0, 0, 0, 0, 1247 | 0, 0, 0, 0, 0, 0, 0, 0, 1248 | 0, 0, 0, 0, 0, 0, 0, 0, 1249 | 0, 0, 0, 0, 0, 0, 0, 0, 1250 | 0, 0, 0, 0, 0, 0, 55, 0, 1251 | 0, 0, 0 1252 | }; 1253 | 1254 | static const short _bloopserial_eof_trans[] = { 1255 | 0, 0, 0, 0, 0, 0, 0, 0, 1256 | 0, 0, 0, 0, 0, 0, 0, 0, 1257 | 0, 0, 0, 0, 0, 0, 0, 0, 1258 | 0, 0, 0, 0, 0, 0, 0, 0, 1259 | 0, 0, 0, 0, 0, 0, 0, 0, 1260 | 0, 0, 0, 0, 0, 0, 0, 0, 1261 | 0, 0, 0, 0, 0, 0, 0, 0, 1262 | 0, 0, 0, 0, 0, 0, 0, 0, 1263 | 0, 0, 0, 0, 0, 0, 0, 0, 1264 | 0, 0, 0, 0, 0, 0, 0, 0, 1265 | 0, 0, 0, 0, 0, 0, 0, 0, 1266 | 0, 0, 0, 0, 0, 0, 0, 0, 1267 | 0, 0, 0, 0, 0, 0, 0, 0, 1268 | 0, 0, 0, 0, 0, 0, 0, 0, 1269 | 0, 0, 0, 0, 0, 0, 0, 0, 1270 | 0, 0, 0, 0, 0, 0, 0, 0, 1271 | 0, 0, 0, 0, 0, 0, 0, 0, 1272 | 0, 0, 0, 0, 0, 0, 0, 360, 1273 | 361, 362, 363 1274 | }; 1275 | 1276 | static const int bloopserial_start = 142; 1277 | static const int bloopserial_error = 0; 1278 | 1279 | static const int bloopserial_en_main = 142; 1280 | 1281 | #line 446 "c/notation.rl" 1282 | 1283 | 1284 | bloopsaphone * 1285 | bloops_sound_file(bloops *B, char *fname) 1286 | { 1287 | FILE *fp; 1288 | struct stat stats; 1289 | int cs, act, len; 1290 | float fval; 1291 | void *key; 1292 | char *str, *p, *pe, *pf, *ts, *te, *eof = 0; 1293 | bloopsaphone *P; 1294 | 1295 | if (stat(fname, &stats) == -1) 1296 | return NULL; 1297 | 1298 | fp = fopen(fname, "rb"); 1299 | if (!fp) 1300 | return NULL; 1301 | 1302 | len = stats.st_size; 1303 | str = (char *)malloc(stats.st_size + 1); 1304 | if (fread(str, 1, stats.st_size, fp) != stats.st_size) 1305 | goto done; 1306 | 1307 | p = str; 1308 | pe = str + len + 1; 1309 | p[len] = '\0'; 1310 | 1311 | P = bloops_square(); 1312 | 1313 | #line 1314 "c/notation.c" 1314 | { 1315 | cs = bloopserial_start; 1316 | ts = 0; 1317 | te = 0; 1318 | act = 0; 1319 | } 1320 | #line 477 "c/notation.rl" 1321 | 1322 | #line 1323 "c/notation.c" 1323 | { 1324 | int _klen; 1325 | unsigned int _trans; 1326 | const char *_acts; 1327 | unsigned int _nacts; 1328 | const char *_keys; 1329 | 1330 | if ( p == pe ) 1331 | goto _test_eof; 1332 | if ( cs == 0 ) 1333 | goto _out; 1334 | _resume: 1335 | _acts = _bloopserial_actions + _bloopserial_from_state_actions[cs]; 1336 | _nacts = (unsigned int) *_acts++; 1337 | while ( _nacts-- > 0 ) { 1338 | switch ( *_acts++ ) { 1339 | case 30: 1340 | #line 1 "c/notation.rl" 1341 | {ts = p;} 1342 | break; 1343 | #line 1344 "c/notation.c" 1344 | } 1345 | } 1346 | 1347 | _keys = _bloopserial_trans_keys + _bloopserial_key_offsets[cs]; 1348 | _trans = _bloopserial_index_offsets[cs]; 1349 | 1350 | _klen = _bloopserial_single_lengths[cs]; 1351 | if ( _klen > 0 ) { 1352 | const char *_lower = _keys; 1353 | const char *_mid; 1354 | const char *_upper = _keys + _klen - 1; 1355 | while (1) { 1356 | if ( _upper < _lower ) 1357 | break; 1358 | 1359 | _mid = _lower + ((_upper-_lower) >> 1); 1360 | if ( (*p) < *_mid ) 1361 | _upper = _mid - 1; 1362 | else if ( (*p) > *_mid ) 1363 | _lower = _mid + 1; 1364 | else { 1365 | _trans += (_mid - _keys); 1366 | goto _match; 1367 | } 1368 | } 1369 | _keys += _klen; 1370 | _trans += _klen; 1371 | } 1372 | 1373 | _klen = _bloopserial_range_lengths[cs]; 1374 | if ( _klen > 0 ) { 1375 | const char *_lower = _keys; 1376 | const char *_mid; 1377 | const char *_upper = _keys + (_klen<<1) - 2; 1378 | while (1) { 1379 | if ( _upper < _lower ) 1380 | break; 1381 | 1382 | _mid = _lower + (((_upper-_lower) >> 1) & ~1); 1383 | if ( (*p) < _mid[0] ) 1384 | _upper = _mid - 2; 1385 | else if ( (*p) > _mid[1] ) 1386 | _lower = _mid + 2; 1387 | else { 1388 | _trans += ((_mid - _keys)>>1); 1389 | goto _match; 1390 | } 1391 | } 1392 | _trans += _klen; 1393 | } 1394 | 1395 | _match: 1396 | _eof_trans: 1397 | cs = _bloopserial_trans_targs[_trans]; 1398 | 1399 | if ( _bloopserial_trans_actions[_trans] == 0 ) 1400 | goto _again; 1401 | 1402 | _acts = _bloopserial_actions + _bloopserial_trans_actions[_trans]; 1403 | _nacts = (unsigned int) *_acts++; 1404 | while ( _nacts-- > 0 ) 1405 | { 1406 | switch ( *_acts++ ) 1407 | { 1408 | case 0: 1409 | #line 400 "c/notation.rl" 1410 | { 1411 | fval = ATOI(ts, p - ts) * 1.0f; 1412 | } 1413 | break; 1414 | case 1: 1415 | #line 404 "c/notation.rl" 1416 | { 1417 | fval = ATOI(pf, p - pf) * pow(0.1f, p - pf); 1418 | } 1419 | break; 1420 | case 2: 1421 | #line 408 "c/notation.rl" 1422 | { pf = p; } 1423 | break; 1424 | case 3: 1425 | #line 409 "c/notation.rl" 1426 | { fval *= -1.0f; } 1427 | break; 1428 | case 4: 1429 | #line 410 "c/notation.rl" 1430 | { KEY(volume); } 1431 | break; 1432 | case 5: 1433 | #line 411 "c/notation.rl" 1434 | { KEY(arp); } 1435 | break; 1436 | case 6: 1437 | #line 412 "c/notation.rl" 1438 | { KEY(aspeed); } 1439 | break; 1440 | case 7: 1441 | #line 413 "c/notation.rl" 1442 | { KEY(attack); } 1443 | break; 1444 | case 8: 1445 | #line 414 "c/notation.rl" 1446 | { KEY(decay); } 1447 | break; 1448 | case 9: 1449 | #line 415 "c/notation.rl" 1450 | { KEY(dslide); } 1451 | break; 1452 | case 10: 1453 | #line 416 "c/notation.rl" 1454 | { KEY(freq); } 1455 | break; 1456 | case 11: 1457 | #line 417 "c/notation.rl" 1458 | { KEY(hpf); } 1459 | break; 1460 | case 12: 1461 | #line 418 "c/notation.rl" 1462 | { KEY(hsweep); } 1463 | break; 1464 | case 13: 1465 | #line 419 "c/notation.rl" 1466 | { KEY(limit); } 1467 | break; 1468 | case 14: 1469 | #line 420 "c/notation.rl" 1470 | { KEY(lpf); } 1471 | break; 1472 | case 15: 1473 | #line 421 "c/notation.rl" 1474 | { KEY(lsweep); } 1475 | break; 1476 | case 16: 1477 | #line 422 "c/notation.rl" 1478 | { KEY(phase); } 1479 | break; 1480 | case 17: 1481 | #line 423 "c/notation.rl" 1482 | { KEY(psweep); } 1483 | break; 1484 | case 18: 1485 | #line 424 "c/notation.rl" 1486 | { KEY(repeat); } 1487 | break; 1488 | case 19: 1489 | #line 425 "c/notation.rl" 1490 | { KEY(resonance); } 1491 | break; 1492 | case 20: 1493 | #line 426 "c/notation.rl" 1494 | { KEY(slide); } 1495 | break; 1496 | case 21: 1497 | #line 427 "c/notation.rl" 1498 | { KEY(square); } 1499 | break; 1500 | case 22: 1501 | #line 428 "c/notation.rl" 1502 | { KEY(sustain); } 1503 | break; 1504 | case 23: 1505 | #line 429 "c/notation.rl" 1506 | { KEY(sweep); } 1507 | break; 1508 | case 24: 1509 | #line 430 "c/notation.rl" 1510 | { KEY(punch); } 1511 | break; 1512 | case 25: 1513 | #line 431 "c/notation.rl" 1514 | { KEY(vibe); } 1515 | break; 1516 | case 26: 1517 | #line 432 "c/notation.rl" 1518 | { KEY(vspeed); } 1519 | break; 1520 | case 27: 1521 | #line 433 "c/notation.rl" 1522 | { KEY(vdelay); } 1523 | break; 1524 | case 28: 1525 | #line 434 "c/notation.rl" 1526 | { KEY(volume); } 1527 | break; 1528 | case 31: 1529 | #line 438 "c/notation.rl" 1530 | {te = p+1;{ P->params.type = BLOOPS_SQUARE; }} 1531 | break; 1532 | case 32: 1533 | #line 439 "c/notation.rl" 1534 | {te = p+1;{ P->params.type = BLOOPS_SAWTOOTH; }} 1535 | break; 1536 | case 33: 1537 | #line 440 "c/notation.rl" 1538 | {te = p+1;{ P->params.type = BLOOPS_SINE; }} 1539 | break; 1540 | case 34: 1541 | #line 441 "c/notation.rl" 1542 | {te = p+1;{ P->params.type = BLOOPS_NOISE; }} 1543 | break; 1544 | case 35: 1545 | #line 437 "c/notation.rl" 1546 | {te = p;p--;{ *((float *)key) = fval; }} 1547 | break; 1548 | case 36: 1549 | #line 442 "c/notation.rl" 1550 | {te = p;p--;} 1551 | break; 1552 | #line 1553 "c/notation.c" 1553 | } 1554 | } 1555 | 1556 | _again: 1557 | _acts = _bloopserial_actions + _bloopserial_to_state_actions[cs]; 1558 | _nacts = (unsigned int) *_acts++; 1559 | while ( _nacts-- > 0 ) { 1560 | switch ( *_acts++ ) { 1561 | case 29: 1562 | #line 1 "c/notation.rl" 1563 | {ts = 0;} 1564 | break; 1565 | #line 1566 "c/notation.c" 1566 | } 1567 | } 1568 | 1569 | if ( cs == 0 ) 1570 | goto _out; 1571 | if ( ++p != pe ) 1572 | goto _resume; 1573 | _test_eof: {} 1574 | if ( p == eof ) 1575 | { 1576 | if ( _bloopserial_eof_trans[cs] > 0 ) { 1577 | _trans = _bloopserial_eof_trans[cs] - 1; 1578 | goto _eof_trans; 1579 | } 1580 | } 1581 | 1582 | _out: {} 1583 | } 1584 | #line 478 "c/notation.rl" 1585 | 1586 | done: 1587 | fclose(fp); 1588 | return P; 1589 | } 1590 | 1591 | char * 1592 | bloops_sound_str(bloopsaphone *P) 1593 | { 1594 | char *lines = (char *)malloc(4096), *str = lines; 1595 | bloopsaphone *sq = bloops_square(); 1596 | if (P->params.type == BLOOPS_SQUARE) 1597 | str += sprintf(str, "type square\n"); 1598 | else if (P->params.type == BLOOPS_SAWTOOTH) 1599 | str += sprintf(str, "type sawtooth\n"); 1600 | else if (P->params.type == BLOOPS_SINE) 1601 | str += sprintf(str, "type sine\n"); 1602 | else if (P->params.type == BLOOPS_NOISE) 1603 | str += sprintf(str, "type noise\n"); 1604 | 1605 | if (P->params.volume != sq->params.volume) 1606 | str += sprintf(str, "volume %0.3f\n", P->params.volume); 1607 | if (P->params.punch != sq->params.punch) 1608 | str += sprintf(str, "punch %0.3f\n", P->params.punch); 1609 | if (P->params.attack != sq->params.attack) 1610 | str += sprintf(str, "attack %0.3f\n", P->params.attack); 1611 | if (P->params.sustain != sq->params.sustain) 1612 | str += sprintf(str, "sustain %0.3f\n", P->params.sustain); 1613 | if (P->params.decay != sq->params.decay) 1614 | str += sprintf(str, "decay %0.3f\n", P->params.decay); 1615 | if (P->params.freq != sq->params.freq) 1616 | str += sprintf(str, "freq %0.3f\n", P->params.freq); 1617 | if (P->params.limit != sq->params.limit) 1618 | str += sprintf(str, "limit %0.3f\n", P->params.limit); 1619 | if (P->params.slide != sq->params.slide) 1620 | str += sprintf(str, "slide %0.3f\n", P->params.slide); 1621 | if (P->params.dslide != sq->params.dslide) 1622 | str += sprintf(str, "dslide %0.3f\n", P->params.dslide); 1623 | if (P->params.square != sq->params.square) 1624 | str += sprintf(str, "square %0.3f\n", P->params.square); 1625 | if (P->params.sweep != sq->params.sweep) 1626 | str += sprintf(str, "sweep %0.3f\n", P->params.sweep); 1627 | if (P->params.vibe != sq->params.vibe) 1628 | str += sprintf(str, "vibe %0.3f\n", P->params.vibe); 1629 | if (P->params.vspeed != sq->params.vspeed) 1630 | str += sprintf(str, "vspeed %0.3f\n", P->params.vspeed); 1631 | if (P->params.vdelay != sq->params.vdelay) 1632 | str += sprintf(str, "vdelay %0.3f\n", P->params.vdelay); 1633 | if (P->params.lpf != sq->params.lpf) 1634 | str += sprintf(str, "lpf %0.3f\n", P->params.lpf); 1635 | if (P->params.lsweep != sq->params.lsweep) 1636 | str += sprintf(str, "lsweep %0.3f\n", P->params.lsweep); 1637 | if (P->params.resonance != sq->params.resonance) 1638 | str += sprintf(str, "resonance %0.3f\n", P->params.resonance); 1639 | if (P->params.hpf != sq->params.hpf) 1640 | str += sprintf(str, "hpf %0.3f\n", P->params.hpf); 1641 | if (P->params.hsweep != sq->params.hsweep) 1642 | str += sprintf(str, "hsweep %0.3f\n", P->params.hsweep); 1643 | if (P->params.arp != sq->params.arp) 1644 | str += sprintf(str, "arp %0.3f\n", P->params.arp); 1645 | if (P->params.aspeed != sq->params.aspeed) 1646 | str += sprintf(str, "aspeed %0.3f\n", P->params.aspeed); 1647 | if (P->params.phase != sq->params.phase) 1648 | str += sprintf(str, "phase %0.3f\n", P->params.phase); 1649 | if (P->params.psweep != sq->params.psweep) 1650 | str += sprintf(str, "psweep %0.3f\n", P->params.psweep); 1651 | if (P->params.repeat != sq->params.repeat) 1652 | str += sprintf(str, "repeat %0.3f\n", P->params.repeat); 1653 | 1654 | bloops_sound_destroy(sq); 1655 | return lines; 1656 | } 1657 | -------------------------------------------------------------------------------- /c/notation.rl: -------------------------------------------------------------------------------- 1 | // 2 | // notation.rl 3 | // the musical notation parser 4 | // 5 | // (c) 2009 why the lucky stiff 6 | // See COPYING for the license 7 | // 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "bloopsaphone.h" 14 | 15 | #define ATOI(X,N) ({ \ 16 | char *Ap = X; \ 17 | int Ai = 0; \ 18 | size_t Al = N; \ 19 | while (Al--) { \ 20 | if ((*Ap >= '0') && (*Ap <= '9')) { \ 21 | Ai = (Ai * 10) + (*Ap - '0'); \ 22 | Ap++; \ 23 | } \ 24 | else break; \ 25 | } \ 26 | Ai; \ 27 | }) 28 | 29 | #define NOTE S->notes[S->nlen] 30 | 31 | #define NEXT() \ 32 | NOTE.duration = len; \ 33 | NOTE.octave = oct; \ 34 | mod = 0; \ 35 | tone = 0; \ 36 | len = 4; \ 37 | fxval = 0; \ 38 | fxmod = 0; \ 39 | S->nlen++ 40 | 41 | %%{ 42 | machine bloopnotes; 43 | 44 | action Alen { 45 | len = ATOI(ts, p - ts); 46 | } 47 | 48 | action Aoct { 49 | oct = ATOI(p - 1, 1); 50 | } 51 | 52 | action Anote { 53 | switch (tone) { 54 | case 'a': case 'A': 55 | if (mod == 'b') NOTE.tone = 'a'; 56 | else if (mod == '#') NOTE.tone = 'b'; 57 | else NOTE.tone = 'A'; 58 | break; 59 | case 'b': case 'B': 60 | if (mod == 'b') NOTE.tone = 'b'; 61 | else if (mod == '#') NOTE.tone = 'C'; 62 | else NOTE.tone = 'B'; 63 | break; 64 | case 'c': case 'C': 65 | if (mod == 'b') NOTE.tone = 'B'; 66 | else if (mod == '#') NOTE.tone = 'd'; 67 | else NOTE.tone = 'C'; 68 | break; 69 | case 'd': case 'D': 70 | if (mod == 'b') NOTE.tone = 'd'; 71 | else if (mod == '#') NOTE.tone = 'e'; 72 | else NOTE.tone = 'D'; 73 | break; 74 | case 'e': case 'E': 75 | if (mod == 'b') NOTE.tone = 'e'; 76 | else if (mod == '#') NOTE.tone = 'F'; 77 | else NOTE.tone = 'E'; 78 | break; 79 | case 'f': case 'F': 80 | if (mod == 'b') NOTE.tone = 'E'; 81 | else if (mod == '#') NOTE.tone = 'g'; 82 | else NOTE.tone = 'F'; 83 | break; 84 | case 'g': case 'G': 85 | if (mod == 'b') NOTE.tone = 'g'; 86 | else if (mod == '#') NOTE.tone = 'a'; 87 | else NOTE.tone = 'G'; 88 | break; 89 | } 90 | } 91 | 92 | action Afx { 93 | bloopsafx *fx = (bloopsafx *)malloc(sizeof(bloopsafx)); 94 | fx->next = NOTE.FX; 95 | fx->cmd = fxcmd; 96 | fx->val = fxval; 97 | fx->mod = fxmod; 98 | fxval = fxmod = 0; 99 | NOTE.FX = fx; 100 | } 101 | 102 | action fxval1 { 103 | fxval = atoi(p-1) * 1.0f; 104 | } 105 | 106 | action fxval2 { 107 | fxval += ATOI(pf, p - pf) * pow(0.1f, p - pf); 108 | } 109 | 110 | dec = digit+ %fxval1 ("." %{ pf = p; } digit+ )? %fxval2; 111 | float = ("-" dec %{ fxval *= -1.0f; } | dec); 112 | fxcmd = "volume" %{ fxcmd = BLOOPS_FX_VOLUME; } | 113 | "punch" %{ fxcmd = BLOOPS_FX_PUNCH; } | 114 | "attack" %{ fxcmd = BLOOPS_FX_ATTACK; } | 115 | "sustain" %{ fxcmd = BLOOPS_FX_SUSTAIN; } | 116 | "decay" %{ fxcmd = BLOOPS_FX_DECAY; } | 117 | "square" %{ fxcmd = BLOOPS_FX_SQUARE; } | 118 | "sweep" %{ fxcmd = BLOOPS_FX_SWEEP; } | 119 | "vibe" %{ fxcmd = BLOOPS_FX_VIBE; } | 120 | "vspeed" %{ fxcmd = BLOOPS_FX_VSPEED; } | 121 | "vdelay" %{ fxcmd = BLOOPS_FX_VDELAY; } | 122 | "lpf" %{ fxcmd = BLOOPS_FX_LPF; } | 123 | "lsweep" %{ fxcmd = BLOOPS_FX_LSWEEP; } | 124 | "resonance" %{ fxcmd = BLOOPS_FX_RESONANCE; } | 125 | "hpf" %{ fxcmd = BLOOPS_FX_HPF; } | 126 | "hsweep" %{ fxcmd = BLOOPS_FX_HSWEEP; } | 127 | "arp" %{ fxcmd = BLOOPS_FX_ARP; } | 128 | "aspeed" %{ fxcmd = BLOOPS_FX_ASPEED; } | 129 | "phase" %{ fxcmd = BLOOPS_FX_PHASE; } | 130 | "psweep" %{ fxcmd = BLOOPS_FX_PSWEEP; } | 131 | "repeat" %{ fxcmd = BLOOPS_FX_REPEAT; }; 132 | 133 | len = [1-9] [0-9]? ":"? %Alen; 134 | up = "+" %{ len = 1; } len?; 135 | down = "-" %{ len = 1; } len?; 136 | mod = [b#] %{ mod = p[-1]; }; 137 | oct = [1-8] %Aoct; 138 | fxmod = ( ("+"|"-") %{ fxmod = p[-1]; } (":"|space+) )?; 139 | fx = ("[" fxcmd (":"|space*) fxmod float "]" %Afx ); 140 | note = len? [a-gA-G] %{ tone = p[-1]; } mod? oct? fx* %Anote; 141 | 142 | main := |* 143 | len => { 144 | NOTE.tone = 0; 145 | NEXT(); 146 | }; 147 | note => { NEXT(); }; 148 | up => { oct++; len = 4; }; 149 | down => { oct--; len = 4; }; 150 | space; 151 | *|; 152 | 153 | write data nofinal; 154 | }%% 155 | 156 | extern void _bloops_track_add(bloops *B, bloopsatrack *track); 157 | 158 | bloopsatrack * 159 | bloops_track(bloops *B, bloopsaphone *P, char *track, int tracklen) 160 | { 161 | int cs, act, oct = 4, len = 4; 162 | bloopsatrack *S = (bloopsatrack *)malloc(sizeof(bloopsatrack)); 163 | char tone, mod, fxmod, *p, *pe, *pf, *ts, *te, *eof = 0; 164 | bloopsafxcmd fxcmd = (bloopsafxcmd)0; 165 | float fxval = 0; 166 | 167 | S->refcount = 1; 168 | S->nlen = 0; 169 | S->capa = 1024; 170 | S->notes = (bloopsanote *)calloc(sizeof(bloopsanote), 1024); 171 | 172 | p = track; 173 | pe = track + tracklen + 1; 174 | 175 | %% write init; 176 | %% write exec; 177 | 178 | memcpy(&S->params, &P->params, sizeof(bloopsaparams)); 179 | 180 | _bloops_track_add(B, S); 181 | 182 | return S; 183 | } 184 | 185 | bloopsatrack * 186 | bloops_track2(bloops *B, bloopsaphone *P, char *track) 187 | { 188 | return bloops_track(B, P, track, strlen(track)); 189 | } 190 | 191 | char * 192 | bloops_track_str(bloopsatrack *track) 193 | { 194 | int bufsize = sizeof(char) * (track->nlen * 6 + 1024); 195 | char *str = (char *)malloc(bufsize), *ptr = str; 196 | int i, adv = 0; 197 | 198 | for (i = 0; i < track->nlen; i++) 199 | { 200 | if (ptr - str + adv + sizeof(char) * 256 > bufsize) { 201 | char *new_str; 202 | bufsize += sizeof(char) * 1024; 203 | new_str = realloc(str, bufsize); 204 | if (new_str == NULL) { 205 | free(str); 206 | return NULL; 207 | } 208 | } 209 | 210 | if (ptr > str) 211 | strcat(ptr++, " "); 212 | 213 | if (track->notes[i].duration != 4) 214 | { 215 | adv = sprintf(ptr, "%d:", (int)track->notes[i].duration); 216 | ptr += adv; 217 | } 218 | 219 | if (track->notes[i].tone) 220 | { 221 | char tone[3] = "\0\0\0"; 222 | tone[0] = track->notes[i].tone; 223 | switch (tone[0]) { 224 | case 'a': tone[0] = 'A'; tone[1] = 'b'; break; 225 | case 'b': tone[0] = 'B'; tone[1] = 'b'; break; 226 | case 'd': tone[0] = 'C'; tone[1] = '#'; break; 227 | case 'e': tone[0] = 'E'; tone[1] = 'b'; break; 228 | case 'g': tone[0] = 'F'; tone[1] = '#'; break; 229 | } 230 | adv = sprintf(ptr, "%s", tone); 231 | ptr += adv; 232 | 233 | adv = sprintf(ptr, "%d", (int)track->notes[i].octave); 234 | ptr += adv; 235 | bloopsafx *fx = (bloopsafx *)track->notes[i].FX; 236 | while (fx) { 237 | if (fx->mod == 0) 238 | adv = sprintf(ptr, "[%s %0.3f]", bloops_fxcmd_name(fx->cmd), fx->val); 239 | else 240 | adv = sprintf(ptr, "[%s %c %0.3f]", bloops_fxcmd_name(fx->cmd), fx->mod, fx->val); 241 | ptr += adv; 242 | fx = (bloopsafx *)fx->next; 243 | } 244 | } 245 | } 246 | 247 | return str; 248 | } 249 | 250 | char * 251 | bloops_fxcmd_name(bloopsafxcmd fxcmd) { 252 | char *fxname = "\0"; 253 | switch (fxcmd) { 254 | case BLOOPS_FX_VOLUME: fxname = "volume"; break; 255 | case BLOOPS_FX_PUNCH: fxname = "punch"; break; 256 | case BLOOPS_FX_ATTACK: fxname = "attack"; break; 257 | case BLOOPS_FX_SUSTAIN: fxname = "sustain"; break; 258 | case BLOOPS_FX_DECAY: fxname = "decay"; break; 259 | case BLOOPS_FX_SQUARE: fxname = "square"; break; 260 | case BLOOPS_FX_SWEEP: fxname = "sweep"; break; 261 | case BLOOPS_FX_VIBE: fxname = "vibe"; break; 262 | case BLOOPS_FX_VSPEED: fxname = "vspeed"; break; 263 | case BLOOPS_FX_VDELAY: fxname = "vdelay"; break; 264 | case BLOOPS_FX_LPF: fxname = "lpf"; break; 265 | case BLOOPS_FX_LSWEEP: fxname = "lsweep"; break; 266 | case BLOOPS_FX_RESONANCE: fxname = "resonance"; break; 267 | case BLOOPS_FX_HPF: fxname = "hpf"; break; 268 | case BLOOPS_FX_HSWEEP: fxname = "hsweep"; break; 269 | case BLOOPS_FX_ARP: fxname = "arp"; break; 270 | case BLOOPS_FX_ASPEED: fxname = "aspeed"; break; 271 | case BLOOPS_FX_PHASE: fxname = "phase"; break; 272 | case BLOOPS_FX_PSWEEP: fxname = "psweep"; break; 273 | case BLOOPS_FX_REPEAT: fxname = "repeat"; break; 274 | } 275 | return fxname; 276 | } 277 | 278 | float 279 | bloops_note_freq(char note, int octave) 280 | { 281 | switch (note) 282 | { 283 | case 'A': // A 284 | if (octave <= 0) return 0.0; 285 | else if (octave == 1) return 0.121; 286 | else if (octave == 2) return 0.175; 287 | else if (octave == 3) return 0.248; 288 | else if (octave == 4) return 0.353; 289 | else if (octave == 5) return 0.500; 290 | break; 291 | 292 | case 'b': // A# or Bb 293 | if (octave <= 0) return 0.0; 294 | else if (octave == 1) return 0.125; 295 | else if (octave == 2) return 0.181; 296 | else if (octave == 3) return 0.255; 297 | else if (octave == 4) return 0.364; 298 | else if (octave == 5) return 0.515; 299 | break; 300 | 301 | case 'B': // B 302 | if (octave <= 0) return 0.0; 303 | else if (octave == 1) return 0.129; 304 | else if (octave == 2) return 0.187; 305 | else if (octave == 3) return 0.263; 306 | else if (octave == 4) return 0.374; 307 | else if (octave == 5) return 0.528; 308 | break; 309 | 310 | case 'C': // C 311 | if (octave <= 1) return 0.0; 312 | else if (octave == 2) return 0.133; 313 | else if (octave == 3) return 0.192; 314 | else if (octave == 4) return 0.271; 315 | else if (octave == 5) return 0.385; 316 | else if (octave == 6) return 0.544; 317 | break; 318 | 319 | case 'd': // C# or Db 320 | if (octave <= 1) return 0.0; 321 | else if (octave == 2) return 0.138; 322 | else if (octave == 3) return 0.198; 323 | else if (octave == 4) return 0.279; 324 | else if (octave == 5) return 0.395; 325 | else if (octave == 6) return 0.559; 326 | break; 327 | 328 | case 'D': // D 329 | if (octave <= 1) return 0.0; 330 | else if (octave == 2) return 0.143; 331 | else if (octave == 3) return 0.202; 332 | else if (octave == 4) return 0.287; 333 | else if (octave == 5) return 0.406; 334 | else if (octave == 6) return 0.575; 335 | break; 336 | 337 | case 'e': // D# or Eb 338 | if (octave <= 1) return 0.0; 339 | else if (octave == 2) return 0.148; 340 | else if (octave == 3) return 0.208; 341 | else if (octave == 4) return 0.296; 342 | else if (octave == 5) return 0.418; 343 | else if (octave == 6) return 0.593; 344 | break; 345 | 346 | case 'E': // E 347 | if (octave <= 1) return 0.0; 348 | else if (octave == 2) return 0.152; 349 | else if (octave == 3) return 0.214; 350 | else if (octave == 4) return 0.305; 351 | else if (octave == 5) return 0.429; 352 | else if (octave == 6) return 0.608; 353 | break; 354 | 355 | case 'F': // F 356 | if (octave <= 1) return 0.0; 357 | else if (octave == 2) return 0.155; 358 | else if (octave == 3) return 0.220; 359 | else if (octave == 4) return 0.314; 360 | else if (octave == 5) return 0.441; 361 | break; 362 | 363 | case 'g': // F# or Gb 364 | if (octave <= 1) return 0.0; 365 | else if (octave == 2) return 0.160; 366 | else if (octave == 3) return 0.227; 367 | else if (octave == 4) return 0.323; 368 | else if (octave == 5) return 0.454; 369 | break; 370 | 371 | case 'G': // G 372 | if (octave <= 1) return 0.0; 373 | else if (octave == 2) return 0.164; 374 | else if (octave == 3) return 0.234; 375 | else if (octave == 4) return 0.332; 376 | else if (octave == 5) return 0.468; 377 | break; 378 | 379 | case 'a': // G# or Ab 380 | if (octave <= 1) return 0.117; 381 | else if (octave == 2) return 0.170; 382 | else if (octave == 3) return 0.242; 383 | else if (octave == 4) return 0.343; 384 | else if (octave == 5) return 0.485; 385 | break; 386 | } 387 | 388 | return 0.0; 389 | } 390 | 391 | #define KEY(name) key = (void *)&P->params.name 392 | 393 | %%{ 394 | machine bloopserial; 395 | 396 | action ival { 397 | ival = ATOI(ts, p - ts); 398 | } 399 | 400 | action fval1 { 401 | fval = ATOI(ts, p - ts) * 1.0f; 402 | } 403 | 404 | action fval2 { 405 | fval = ATOI(pf, p - pf) * pow(0.1f, p - pf); 406 | } 407 | 408 | dec = [0-9]+ %fval1 "." %{ pf = p; } [0-9]+ %fval2; 409 | float = ("-" dec %{ fval *= -1.0f; } | dec); 410 | key = "volume" %{ KEY(volume); } | 411 | "arp" %{ KEY(arp); } | 412 | "aspeed" %{ KEY(aspeed); } | 413 | "attack" %{ KEY(attack); } | 414 | "decay" %{ KEY(decay); } | 415 | "dslide" %{ KEY(dslide); } | 416 | "freq" %{ KEY(freq); } | 417 | "hpf" %{ KEY(hpf); } | 418 | "hsweep" %{ KEY(hsweep); } | 419 | "limit" %{ KEY(limit); } | 420 | "lpf" %{ KEY(lpf); } | 421 | "lsweep" %{ KEY(lsweep); } | 422 | "phase" %{ KEY(phase); } | 423 | "psweep" %{ KEY(psweep); } | 424 | "repeat" %{ KEY(repeat); } | 425 | "resonance" %{ KEY(resonance); } | 426 | "slide" %{ KEY(slide); } | 427 | "square" %{ KEY(square); } | 428 | "sustain" %{ KEY(sustain); } | 429 | "sweep" %{ KEY(sweep); } | 430 | "punch" %{ KEY(punch); } | 431 | "vibe" %{ KEY(vibe); } | 432 | "vspeed" %{ KEY(vspeed); } | 433 | "vdelay" %{ KEY(vdelay); } | 434 | "volume" %{ KEY(volume); }; 435 | 436 | main := |* 437 | key space+ float space* => { *((float *)key) = fval; }; 438 | "type" space+ "square" => { P->params.type = BLOOPS_SQUARE; }; 439 | "type" space+ "sawtooth" => { P->params.type = BLOOPS_SAWTOOTH; }; 440 | "type" space+ "sine" => { P->params.type = BLOOPS_SINE; }; 441 | "type" space+ "noise" => { P->params.type = BLOOPS_NOISE; }; 442 | space+; 443 | *|; 444 | 445 | write data nofinal; 446 | }%% 447 | 448 | bloopsaphone * 449 | bloops_sound_file(bloops *B, char *fname) 450 | { 451 | FILE *fp; 452 | struct stat stats; 453 | int cs, act, len; 454 | float fval; 455 | void *key; 456 | char *str, *p, *pe, *pf, *ts, *te, *eof = 0; 457 | bloopsaphone *P; 458 | 459 | if (stat(fname, &stats) == -1) 460 | return NULL; 461 | 462 | fp = fopen(fname, "rb"); 463 | if (!fp) 464 | return NULL; 465 | 466 | len = stats.st_size; 467 | str = (char *)malloc(stats.st_size + 1); 468 | if (fread(str, 1, stats.st_size, fp) != stats.st_size) 469 | goto done; 470 | 471 | p = str; 472 | pe = str + len + 1; 473 | p[len] = '\0'; 474 | 475 | P = bloops_square(); 476 | %% write init; 477 | %% write exec; 478 | 479 | done: 480 | fclose(fp); 481 | return P; 482 | } 483 | 484 | char * 485 | bloops_sound_str(bloopsaphone *P) 486 | { 487 | char *lines = (char *)malloc(4096), *str = lines; 488 | bloopsaphone *sq = bloops_square(); 489 | if (P->params.type == BLOOPS_SQUARE) 490 | str += sprintf(str, "type square\n"); 491 | else if (P->params.type == BLOOPS_SAWTOOTH) 492 | str += sprintf(str, "type sawtooth\n"); 493 | else if (P->params.type == BLOOPS_SINE) 494 | str += sprintf(str, "type sine\n"); 495 | else if (P->params.type == BLOOPS_NOISE) 496 | str += sprintf(str, "type noise\n"); 497 | 498 | if (P->params.volume != sq->params.volume) 499 | str += sprintf(str, "volume %0.3f\n", P->params.volume); 500 | if (P->params.punch != sq->params.punch) 501 | str += sprintf(str, "punch %0.3f\n", P->params.punch); 502 | if (P->params.attack != sq->params.attack) 503 | str += sprintf(str, "attack %0.3f\n", P->params.attack); 504 | if (P->params.sustain != sq->params.sustain) 505 | str += sprintf(str, "sustain %0.3f\n", P->params.sustain); 506 | if (P->params.decay != sq->params.decay) 507 | str += sprintf(str, "decay %0.3f\n", P->params.decay); 508 | if (P->params.freq != sq->params.freq) 509 | str += sprintf(str, "freq %0.3f\n", P->params.freq); 510 | if (P->params.limit != sq->params.limit) 511 | str += sprintf(str, "limit %0.3f\n", P->params.limit); 512 | if (P->params.slide != sq->params.slide) 513 | str += sprintf(str, "slide %0.3f\n", P->params.slide); 514 | if (P->params.dslide != sq->params.dslide) 515 | str += sprintf(str, "dslide %0.3f\n", P->params.dslide); 516 | if (P->params.square != sq->params.square) 517 | str += sprintf(str, "square %0.3f\n", P->params.square); 518 | if (P->params.sweep != sq->params.sweep) 519 | str += sprintf(str, "sweep %0.3f\n", P->params.sweep); 520 | if (P->params.vibe != sq->params.vibe) 521 | str += sprintf(str, "vibe %0.3f\n", P->params.vibe); 522 | if (P->params.vspeed != sq->params.vspeed) 523 | str += sprintf(str, "vspeed %0.3f\n", P->params.vspeed); 524 | if (P->params.vdelay != sq->params.vdelay) 525 | str += sprintf(str, "vdelay %0.3f\n", P->params.vdelay); 526 | if (P->params.lpf != sq->params.lpf) 527 | str += sprintf(str, "lpf %0.3f\n", P->params.lpf); 528 | if (P->params.lsweep != sq->params.lsweep) 529 | str += sprintf(str, "lsweep %0.3f\n", P->params.lsweep); 530 | if (P->params.resonance != sq->params.resonance) 531 | str += sprintf(str, "resonance %0.3f\n", P->params.resonance); 532 | if (P->params.hpf != sq->params.hpf) 533 | str += sprintf(str, "hpf %0.3f\n", P->params.hpf); 534 | if (P->params.hsweep != sq->params.hsweep) 535 | str += sprintf(str, "hsweep %0.3f\n", P->params.hsweep); 536 | if (P->params.arp != sq->params.arp) 537 | str += sprintf(str, "arp %0.3f\n", P->params.arp); 538 | if (P->params.aspeed != sq->params.aspeed) 539 | str += sprintf(str, "aspeed %0.3f\n", P->params.aspeed); 540 | if (P->params.phase != sq->params.phase) 541 | str += sprintf(str, "phase %0.3f\n", P->params.phase); 542 | if (P->params.psweep != sq->params.psweep) 543 | str += sprintf(str, "psweep %0.3f\n", P->params.psweep); 544 | if (P->params.repeat != sq->params.repeat) 545 | str += sprintf(str, "repeat %0.3f\n", P->params.repeat); 546 | 547 | bloops_sound_destroy(sq); 548 | return lines; 549 | } 550 | -------------------------------------------------------------------------------- /ext/ruby/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | require 'fileutils' 3 | 4 | $CFLAGS << " -I../../c #{ENV['CFLAGS']}" 5 | $LIBS << " -lm -lportaudio #{ENV['LDFLAGS']}" 6 | 7 | %w[notation.c bloopsaphone-internal.h bloopsaphone.c bloopsaphone.h].each do |fn| 8 | fn = "../../c/#{fn}" 9 | abort "!! ERROR !!\n** #{fn} not found; type 'make ruby' in the top directory\n\n" \ 10 | unless File.exists? fn 11 | FileUtils.cp(fn, ".") 12 | end 13 | 14 | have_library("portaudio") 15 | create_makefile("bloops") 16 | -------------------------------------------------------------------------------- /ext/ruby/rubyext.c: -------------------------------------------------------------------------------- 1 | // 2 | // rubyext.c 3 | // the ruby binding to bloopsaphone 4 | // 5 | // (c) 2009 why the lucky stiff 6 | // 7 | #include 8 | #include "bloopsaphone.h" 9 | 10 | static VALUE cBloops, cSound, cTrack; 11 | static bloopsaphone *Pplain; 12 | 13 | #ifndef RSTRING_LEN 14 | #define RSTRING_LEN(str) RSTRING(str)->len 15 | #define RSTRING_PTR(str) RSTRING(str)->ptr 16 | #endif 17 | 18 | // 19 | // Main Bloops object 20 | // 21 | static void 22 | rb_bloops_free(bloops *B) 23 | { 24 | bloops_destroy(B); 25 | } 26 | 27 | VALUE 28 | rb_bloops_alloc(VALUE klass) 29 | { 30 | bloops *B = bloops_new(); 31 | return Data_Wrap_Struct(klass, NULL, rb_bloops_free, B); 32 | } 33 | 34 | VALUE 35 | rb_bloops_clear(VALUE self) 36 | { 37 | bloops *B; 38 | Data_Get_Struct(self, bloops, B); 39 | bloops_clear(B); 40 | return self; 41 | } 42 | 43 | VALUE 44 | rb_bloops_play(VALUE self) 45 | { 46 | bloops *B; 47 | Data_Get_Struct(self, bloops, B); 48 | bloops_play(B); 49 | return self; 50 | } 51 | 52 | VALUE 53 | rb_bloops_is_stopped(VALUE self) 54 | { 55 | bloops *B; 56 | Data_Get_Struct(self, bloops, B); 57 | return bloops_is_done(B) ? Qtrue : Qfalse; 58 | } 59 | 60 | VALUE 61 | rb_bloops_get_tempo(VALUE self) 62 | { 63 | bloops *B; 64 | Data_Get_Struct(self, bloops, B); 65 | return INT2NUM(B->tempo); 66 | } 67 | 68 | VALUE 69 | rb_bloops_set_tempo(VALUE self, VALUE tempo) 70 | { 71 | bloops *B; 72 | Data_Get_Struct(self, bloops, B); 73 | bloops_tempo(B, NUM2INT(tempo)); 74 | return tempo; 75 | } 76 | 77 | // 78 | // Instrument creation 79 | // 80 | static void 81 | rb_bloops_sound_free(bloopsaphone *sound) 82 | { 83 | bloops_sound_destroy(sound); 84 | } 85 | 86 | VALUE 87 | rb_bloops_load(VALUE self, VALUE fname) 88 | { 89 | bloops *B; 90 | bloopsaphone *P; 91 | Data_Get_Struct(self, bloops, B); 92 | 93 | StringValue(fname); 94 | P = bloops_sound_file(B, RSTRING_PTR(fname)); 95 | if (P == NULL) return Qnil; 96 | return Data_Wrap_Struct(cSound, NULL, rb_bloops_sound_free, P); 97 | } 98 | 99 | VALUE 100 | rb_bloops_sound(VALUE self, VALUE type) 101 | { 102 | bloopsaphone *P = bloops_square(); 103 | P->params.type = (unsigned char)NUM2INT(type); 104 | return Data_Wrap_Struct(cSound, NULL, rb_bloops_sound_free, P); 105 | } 106 | 107 | VALUE 108 | rb_bloops_sound_copy(VALUE self, VALUE other) 109 | { 110 | bloopsaphone *P; 111 | bloopsaphone *O; 112 | Data_Get_Struct(self, bloopsaphone, P); 113 | Data_Get_Struct(other, bloopsaphone, O); 114 | bloops_sound_copy(P, O); 115 | return Qnil; 116 | } 117 | 118 | VALUE 119 | rb_bloops_sound_str(VALUE self) 120 | { 121 | bloopsaphone *P; 122 | Data_Get_Struct(self, bloopsaphone, P); 123 | return rb_str_new2(bloops_sound_str(P)); 124 | } 125 | 126 | VALUE 127 | rb_bloops_reset(VALUE self) 128 | { 129 | bloopsaphone *P; 130 | Data_Get_Struct(self, bloopsaphone, P); 131 | bloops_sound_copy(P, Pplain); 132 | return self; 133 | } 134 | 135 | VALUE 136 | rb_bloops_test(VALUE self) 137 | { 138 | bloops *B; 139 | bloopsatrack *T; 140 | bloopsaphone *P; 141 | 142 | Data_Get_Struct(self, bloopsaphone, P); 143 | 144 | B = bloops_new(); 145 | bloops_tempo(B, 120); 146 | T = bloops_track2(B, P, "C"); 147 | T->notes[0].tone = 'n'; 148 | memcpy(&T->params, &P->params, sizeof(bloopsaparams)); 149 | bloops_play(B); 150 | bloops_track_destroy(T); 151 | bloops_destroy(B); 152 | 153 | return self; 154 | } 155 | 156 | VALUE 157 | rb_bloops_get_type(VALUE self) 158 | { 159 | bloopsaphone *P; 160 | Data_Get_Struct(self, bloopsaphone, P); 161 | return INT2NUM((int)P->params.type); 162 | } 163 | 164 | VALUE 165 | rb_bloops_set_type(VALUE self, VALUE type) 166 | { 167 | bloopsaphone *P; 168 | Data_Get_Struct(self, bloopsaphone, P); 169 | P->params.type = (unsigned char)NUM2INT(type); 170 | return type; 171 | } 172 | 173 | #define SOUND_ACCESSOR(name) \ 174 | VALUE rb_bloops_get_##name(VALUE self) { \ 175 | bloopsaphone *P; \ 176 | Data_Get_Struct(self, bloopsaphone, P); \ 177 | return rb_float_new(P->params.name); \ 178 | } \ 179 | VALUE rb_bloops_set_##name(VALUE self, VALUE f) { \ 180 | bloopsaphone *P; \ 181 | Data_Get_Struct(self, bloopsaphone, P); \ 182 | P->params.name = (float)NUM2DBL(f); \ 183 | return f; \ 184 | } 185 | 186 | SOUND_ACCESSOR(arp); 187 | SOUND_ACCESSOR(aspeed); 188 | SOUND_ACCESSOR(attack); 189 | SOUND_ACCESSOR(decay); 190 | SOUND_ACCESSOR(dslide); 191 | SOUND_ACCESSOR(freq); 192 | SOUND_ACCESSOR(hpf); 193 | SOUND_ACCESSOR(hsweep); 194 | SOUND_ACCESSOR(limit); 195 | SOUND_ACCESSOR(lpf); 196 | SOUND_ACCESSOR(lsweep); 197 | SOUND_ACCESSOR(phase); 198 | SOUND_ACCESSOR(psweep); 199 | SOUND_ACCESSOR(repeat); 200 | SOUND_ACCESSOR(resonance); 201 | SOUND_ACCESSOR(slide); 202 | SOUND_ACCESSOR(square); 203 | SOUND_ACCESSOR(sustain); 204 | SOUND_ACCESSOR(sweep); 205 | SOUND_ACCESSOR(punch); 206 | SOUND_ACCESSOR(vibe); 207 | SOUND_ACCESSOR(vspeed); 208 | SOUND_ACCESSOR(vdelay); 209 | SOUND_ACCESSOR(volume); 210 | 211 | // 212 | // Individual track object 213 | // 214 | static void 215 | rb_bloops_track_free(bloopsatrack *track) 216 | { 217 | bloops_track_destroy(track); 218 | } 219 | 220 | VALUE 221 | rb_bloops_tune(VALUE self, VALUE sound, VALUE notes) 222 | { 223 | bloops *B; 224 | bloopsaphone *phone; 225 | bloopsatrack *track; 226 | Data_Get_Struct(self, bloops, B); 227 | Data_Get_Struct(sound, bloopsaphone, phone); 228 | 229 | StringValue(notes); 230 | track = bloops_track(B, phone, RSTRING_PTR(notes), RSTRING_LEN(notes)); 231 | return Data_Wrap_Struct(cTrack, NULL, rb_bloops_track_free, track); 232 | } 233 | 234 | VALUE 235 | rb_bloops_track_str(VALUE self) 236 | { 237 | char *str; 238 | VALUE obj; 239 | bloopsatrack *track; 240 | Data_Get_Struct(self, bloopsatrack, track); 241 | 242 | str = bloops_track_str(track); 243 | obj = rb_str_new2(str); 244 | free(str); 245 | 246 | return obj; 247 | } 248 | 249 | // 250 | // Ruby extension startup 251 | // 252 | void 253 | Init_bloops() 254 | { 255 | Pplain = bloops_square(); 256 | 257 | cBloops = rb_define_class("Bloops", rb_cObject); 258 | rb_define_alloc_func(cBloops, rb_bloops_alloc); 259 | rb_define_method(cBloops, "clear", rb_bloops_clear, 0); 260 | rb_define_method(cBloops, "load", rb_bloops_load, 1); 261 | rb_define_method(cBloops, "play", rb_bloops_play, 0); 262 | rb_define_method(cBloops, "sound", rb_bloops_sound, 1); 263 | rb_define_singleton_method(cBloops, "sound", rb_bloops_sound, 1); 264 | rb_define_method(cBloops, "stopped?", rb_bloops_is_stopped, 0); 265 | rb_define_method(cBloops, "tempo", rb_bloops_get_tempo, 0); 266 | rb_define_method(cBloops, "tempo=", rb_bloops_set_tempo, 1); 267 | rb_define_method(cBloops, "tune", rb_bloops_tune, 2); 268 | 269 | rb_const_set(cBloops, rb_intern("SQUARE"), INT2NUM(BLOOPS_SQUARE)); 270 | rb_const_set(cBloops, rb_intern("SAWTOOTH"), INT2NUM(BLOOPS_SAWTOOTH)); 271 | rb_const_set(cBloops, rb_intern("SINE"), INT2NUM(BLOOPS_SINE)); 272 | rb_const_set(cBloops, rb_intern("NOISE"), INT2NUM(BLOOPS_NOISE)); 273 | 274 | cSound = rb_define_class_under(cBloops, "Sound", rb_cObject); 275 | rb_define_method(cSound, "initialize_copy", rb_bloops_sound_copy, 1); 276 | rb_define_method(cSound, "to_s", rb_bloops_sound_str, 0); 277 | rb_define_method(cSound, "reset", rb_bloops_reset, 0); 278 | rb_define_method(cSound, "test", rb_bloops_test, 0); 279 | rb_define_method(cSound, "arp", rb_bloops_get_arp, 0); 280 | rb_define_method(cSound, "arp=", rb_bloops_set_arp, 1); 281 | rb_define_method(cSound, "aspeed", rb_bloops_get_aspeed, 0); 282 | rb_define_method(cSound, "aspeed=", rb_bloops_set_aspeed, 1); 283 | rb_define_method(cSound, "attack", rb_bloops_get_attack, 0); 284 | rb_define_method(cSound, "attack=", rb_bloops_set_attack, 1); 285 | rb_define_method(cSound, "decay", rb_bloops_get_decay, 0); 286 | rb_define_method(cSound, "decay=", rb_bloops_set_decay, 1); 287 | rb_define_method(cSound, "dslide", rb_bloops_get_dslide, 0); 288 | rb_define_method(cSound, "dslide=", rb_bloops_set_dslide, 1); 289 | rb_define_method(cSound, "freq", rb_bloops_get_freq, 0); 290 | rb_define_method(cSound, "freq=", rb_bloops_set_freq, 1); 291 | rb_define_method(cSound, "hpf", rb_bloops_get_hpf, 0); 292 | rb_define_method(cSound, "hpf=", rb_bloops_set_hpf, 1); 293 | rb_define_method(cSound, "hsweep", rb_bloops_get_hsweep, 0); 294 | rb_define_method(cSound, "hsweep=", rb_bloops_set_hsweep, 1); 295 | rb_define_method(cSound, "limit", rb_bloops_get_limit, 0); 296 | rb_define_method(cSound, "limit=", rb_bloops_set_limit, 1); 297 | rb_define_method(cSound, "lpf", rb_bloops_get_lpf, 0); 298 | rb_define_method(cSound, "lpf=", rb_bloops_set_lpf, 1); 299 | rb_define_method(cSound, "lsweep", rb_bloops_get_lsweep, 0); 300 | rb_define_method(cSound, "lsweep=", rb_bloops_set_lsweep, 1); 301 | rb_define_method(cSound, "phase", rb_bloops_get_phase, 0); 302 | rb_define_method(cSound, "phase=", rb_bloops_set_phase, 1); 303 | rb_define_method(cSound, "psweep", rb_bloops_get_psweep, 0); 304 | rb_define_method(cSound, "psweep=", rb_bloops_set_psweep, 1); 305 | rb_define_method(cSound, "punch", rb_bloops_get_punch, 0); 306 | rb_define_method(cSound, "punch=", rb_bloops_set_punch, 1); 307 | rb_define_method(cSound, "repeat", rb_bloops_get_repeat, 0); 308 | rb_define_method(cSound, "repeat=", rb_bloops_set_repeat, 1); 309 | rb_define_method(cSound, "resonance", rb_bloops_get_resonance, 0); 310 | rb_define_method(cSound, "resonance=", rb_bloops_set_resonance, 1); 311 | rb_define_method(cSound, "slide", rb_bloops_get_slide, 0); 312 | rb_define_method(cSound, "slide=", rb_bloops_set_slide, 1); 313 | rb_define_method(cSound, "square", rb_bloops_get_square, 0); 314 | rb_define_method(cSound, "square=", rb_bloops_set_square, 1); 315 | rb_define_method(cSound, "sweep", rb_bloops_get_sweep, 0); 316 | rb_define_method(cSound, "sweep=", rb_bloops_set_sweep, 1); 317 | rb_define_method(cSound, "sustain", rb_bloops_get_sustain, 0); 318 | rb_define_method(cSound, "sustain=", rb_bloops_set_sustain, 1); 319 | rb_define_method(cSound, "type", rb_bloops_get_type, 0); 320 | rb_define_method(cSound, "type=", rb_bloops_set_type, 1); 321 | rb_define_method(cSound, "vibe", rb_bloops_get_vibe, 0); 322 | rb_define_method(cSound, "vibe=", rb_bloops_set_vibe, 1); 323 | rb_define_method(cSound, "vspeed", rb_bloops_get_vspeed, 0); 324 | rb_define_method(cSound, "vspeed=", rb_bloops_set_vspeed, 1); 325 | rb_define_method(cSound, "vdelay", rb_bloops_get_vdelay, 0); 326 | rb_define_method(cSound, "vdelay=", rb_bloops_set_vdelay, 1); 327 | rb_define_method(cSound, "volume", rb_bloops_get_volume, 0); 328 | rb_define_method(cSound, "volume=", rb_bloops_set_volume, 1); 329 | 330 | cTrack = rb_define_class_under(cBloops, "Track", rb_cObject); 331 | rb_define_method(cTrack, "to_s", rb_bloops_track_str, 0); 332 | } 333 | -------------------------------------------------------------------------------- /ext/ruby/test.rb: -------------------------------------------------------------------------------- 1 | require './bloops' 2 | 3 | # the song object 4 | b = Bloops.new 5 | b.tempo = 320 6 | 7 | # an instrument 8 | saw = b.sound Bloops::SAWTOOTH 9 | saw.test 10 | 11 | # assign a track to the song 12 | b.tune saw, "c5 c6 b4 b5 d5 d6 e5 e6" 13 | 14 | # make it go 15 | b.play 16 | sleep 1 while !b.stopped? 17 | 18 | # a percussion 19 | beat = b.sound Bloops::NOISE 20 | beat.repeat = 0.6 21 | beat2 = b.sound Bloops::NOISE 22 | beat2.repeat = 0.2 23 | beat3 = b.sound Bloops::SQUARE 24 | beat3.sustain = 0.25 25 | beat3.decay = 0.2 26 | beat3.slide = 0.2 27 | beat3.square = 0.3 28 | beat3.vibe = 0.25 29 | beat3.vspeed = 0.25 30 | 31 | # assign a track to the song 32 | b.tune beat, "4 4 4 b4 4 d5 4 e5" 33 | b.tune beat2, "c2 4 c2 4 c2 4 c2 4" 34 | b.tune beat3, "4 4 4 4 4 c2 c5 4" 35 | 36 | # make it go 37 | loop do 38 | b.play 39 | saw.test 40 | sleep 0.02 while !b.stopped? 41 | end 42 | -------------------------------------------------------------------------------- /ext/ruby/test_load.rb: -------------------------------------------------------------------------------- 1 | require './bloops' 2 | 3 | b = Bloops.new 4 | 5 | # ice #1 6 | puts "** playing scale using ice.blu" 7 | ice = b.load "../../sounds/ice.blu" 8 | b.tune ice, "c c# d eb e f f# g ab a bb b + c" 9 | 10 | b.play 11 | sleep 1 while !b.stopped? 12 | 13 | b.clear 14 | 15 | # ice #2 16 | puts "** same scale built from ruby" 17 | ice2 = b.sound Bloops::SQUARE 18 | ice2.punch = 0.441 19 | ice2.sustain = 0.067 20 | ice2.decay = 0.197 21 | ice2.freq = 0.499 22 | b.tune ice2, "c c# d eb e f f# g ab a bb b + c" 23 | 24 | b.play 25 | sleep 1 while !b.stopped? 26 | -------------------------------------------------------------------------------- /ext/ruby/tune_cheeky_drat.rb: -------------------------------------------------------------------------------- 1 | # 2 | # -)= Cheeky Drat (=- 3 | # composed by freQvibez 4 | # [within TextMate] 5 | # exclusively for _why's BloopSaphone 6 | # 7 | # from Farbrausch with ♥ 8 | # 9 | 10 | require './bloops' 11 | 12 | b = Bloops.new 13 | b.tempo = 172 14 | 15 | bass = b.sound Bloops::SQUARE 16 | bass.volume = 0.4 17 | bass.sustain = 0.1 18 | bass.attack = 0.1 19 | bass.decay = 0.3 20 | 21 | base = b.sound Bloops::SQUARE 22 | base.volume = 0.35 23 | base.punch = 0.3 24 | base.sustain = 0.1 25 | base.decay = 0.3 26 | base.phase = 0.2 27 | base.lpf = 0.115 28 | base.resonance = 0.55 29 | base.slide = -0.4 30 | 31 | snare = b.sound Bloops::NOISE 32 | snare.attack = 0.075 33 | snare.sustain = 0.01 34 | snare.decay = 0.33 35 | snare.hpf = 0.55 36 | snare.resonance = 0.44 37 | snare.dslide = -0.452 38 | 39 | chord = b.sound Bloops::SQUARE 40 | chord.volume = 0.275 41 | chord.attack = 0.05 42 | chord.sustain = 0.6 43 | chord.decay = 0.9 44 | chord.phase = 0.35 45 | chord.psweep = -0.25 46 | chord.vibe = 0.0455 47 | chord.vspeed = 0.255 48 | 49 | lead = b.sound Bloops::SINE 50 | lead.volume = 0.45 51 | lead.attack = 0.3 52 | lead.sustain = 0.15 53 | lead.decay = 0.8 54 | lead.vibe = 0.035 55 | lead.vspeed = 0.345 56 | lead.vdelay = -0.5 57 | lead.hpf = 0.2 58 | lead.hsweep = -0.05 59 | lead.resonance = 0.55 60 | lead.phase = 0.4 61 | lead.psweep = -0.05 62 | 63 | b.tune bass, %q^ 64 | 8 4a1 8a 8a 4a 4a 4c2 9c 7c 4c 8e 65 | 8 4g2 8g 8 4g 4g 4d2 8 8c3 4b2 8e 66 | 8 4d2 8c 8c 4c 4 4a2 9a 7a 4a 8a 67 | 8 4g2 8g 8 4g 4d 4d2 9e3 7c2 8 4b1 68 | 69 | 8 4a2 8a 8d 4 4d 4a1 8a 8a 4d 8d 70 | 8 4g2 8g 8 4g 4g 4c2 8c 8c2 4g 8c 71 | 8 4d2 8d 8d 4d 4d 4a1 8a 8a 4a 8a 72 | 8 4g2 8g 8 4g 4g 4c2 8c 8c 4c 8b1 73 | 74 | 8 4a1 8a 8a 4a 4a 4c2 9c 7c 4c 8e 75 | 8 4g2 8g 8 4g 4g 4d2 8 8c3 4b2 8e 76 | 8 4d2 8c 8c 4c 4 4a2 9a 7a 4a 8a 77 | 8 4g2 8g 8 4g 4d 4d2 9e3 7c2 8 4b1 78 | 79 | 8 4a2 8a 8d 4 4d 4a1 8a 8a 4d 8d 80 | 8 4g2 8g 8 4g 4g 4c2 8c 8c2 4g 8c 81 | 8 4d2 8d 8d 4d 4d 4a1 8a 8a 4a 8a 82 | 8 4g2 8g 8 4g 4g 4c2 8c 8c 4c 8b1 83 | ^ 84 | 85 | b.tune base, %q^ 86 | 4a2 4 8a 8a 4 4a 4 8a 8a 4 87 | 4a 4 8a 8a 4 4a 4 4a 8 8a 88 | 4a 4 8a 8a 4 4a 4 8a 8a 4 89 | 4a 4 8a 4 8a 4a 4 8a 4 8a 90 | 91 | 4a2 4 8a 8a 4 4a 4 8a 8a 4 92 | 4a 4 8a 8a 4 4a 4 4a 8 8a 93 | 4a 4 8a 8a 4 4a 4 8a 8a 4 94 | 4a 4 8a 4 8a 4a 4 8a 4 8a 95 | 96 | 4a2 4 8a 8a 4 4a 4 8a 8a 4 97 | 4a 4 8a 8a 4 4a 4 4a 8 8a 98 | 4a 4 8a 8a 4 4a 4 8a 8a 4 99 | 4a 4 8a 4 8a 4a 4 8a 4 8a 100 | 101 | 4a2 4 8a 8a 4 4a 4 8a 8a 4 102 | 4a 4 8a 8a 4 4a 4 4a 8 8a 103 | 4a 4 8a 8a 4 4a 4 8a 8a 4 104 | 4a 4 8a 4 8a 4a 4 8a 4 8a 105 | ^ 106 | 107 | b.tune snare, %q^ 108 | 4 4a2 4 4a2 4 4a2 4 4a2 109 | 4 4a2 4 4a2 4 4a2 4 4a2 110 | 4 4a2 4 4a2 4 4a2 4 4a2 111 | 4 4a2 4 4a2 4 4a2 4 8a2 8a2 112 | 113 | 4 4a2 4 4a2 4 4a2 4 4a2 114 | 4 4a2 4 4a2 4 4a2 4 4a2 115 | 4 4a2 4 4a2 4 4a2 4 4a2 116 | 4 4a2 4 4a2 4 4a2 4 8a2 8a2 117 | 118 | 4 4a2 4 4a2 4 4a2 4 4a2 119 | 4 4a2 4 4a2 4 4a2 4 4a2 120 | 4 4a2 4 4a2 4 4a2 4 4a2 121 | 4 4a2 4 4a2 4 4a2 4 8a2 8a2 122 | 123 | 4 4a2 4 4a2 4 4a2 4 4a2 124 | 4 4a2 4 4a2 4 4a2 4 4a2 125 | 4 4a2 4 4a2 4 4a2 4 4a2 126 | 4 4a2 4 4a2 4 4a2 4 8a2 8a2 127 | ^ 128 | 129 | b.tune chord, %q^ 130 | 1 131 | 1 1 132 | 1 1 1 133 | 1 1 134 | 135 | 1a2 2a3 2 1g2 2d3 2 136 | 1a2 2a3 2 1d2 4g3 4g2 2e3 137 | 138 | 1a2 2a3 2 1g2 2d3 2 139 | 1a2 2a3 2 1d2 2g3 2 140 | 141 | 1a2 2a3 2 1g2 2d3 2 142 | 1a2 2a3 2 1d2 2g3 2 143 | 144 | 1a2 2a3 2 1g2 2d3 2 145 | 1a2 2a3 2 1d2 2g3 2 146 | ^ 147 | 148 | b.tune chord, %q^ 149 | 1 150 | 1 1 151 | 1 1 1 152 | 1 1 153 | 154 | 2 2c4 2 1 2b4 2 155 | 1 2c4 4 2g3 2b4 1 156 | 157 | 2 2c4 2 1 2b4 2 158 | 1 2c4 2 1 2b4 1 159 | 160 | 2 2c4 2 1 2b4 2 161 | 1 2c4 2 1 2b4 1 162 | 163 | 2 2c4 2 1 2b4 2 164 | 1 2c4 2 1 2b4 1 165 | ^ 166 | 167 | b.tune chord, %q^ 168 | 1 169 | 1 1 170 | 1 1 1 171 | 1 1 172 | 173 | 2 1 2e4 2 1 2d4 174 | 2 1 2e4 2 1 2d4 175 | 176 | 2 1 2e4 2 1 2d4 177 | 2 1 2e4 2 1 2d4 178 | 179 | 2 1 2e4 2 1 2d4 180 | 2 1 2e4 2 1 2d4 181 | 182 | 2 1 2e4 2 1 2d4 183 | 2 1 2e4 2 1 2d4 184 | ^ 185 | 186 | b.tune lead, %q^ 187 | 1 4 188 | 1 1 1 1 189 | 1 1 1 1 1 1 190 | 1 1 1 1 191 | 192 | 2g3 1a4 2 193 | 2c5 1e4 2 1 194 | 1a4 2 4 2e4 1d4 2 195 | 196 | 2a3 1b4 2 197 | 2d5 2g4 1c5 198 | 1a4 1e5 199 | 1b4 2 4 8 8d4 200 | 201 | 2g3 1a4 2 202 | 2c5 1e4 3d4 5g4 203 | 1a4 1e4 204 | 1d4 1 205 | ^ 206 | 207 | while true do 208 | b.play 209 | sleep 0.5 while not b.stopped? 210 | end 211 | -------------------------------------------------------------------------------- /ext/ruby/tune_warp.rb: -------------------------------------------------------------------------------- 1 | # 2 | # -=) warp-o-mat (=- 3 | # tune coded/composed by freQvibez 4 | # (c) 2009 Alex Brem 5 | # 6 | # exclusively for why's BloopSaphone 7 | # 8 | # from Farbrausch with ♥ 9 | # 10 | 11 | module LousyBloopMachine 12 | 13 | class Tune 14 | 15 | BPM = 67 16 | 17 | ### 18 | ### sequences 19 | ### 20 | 21 | SEQUENCES = { 22 | :bass => %w^ 23 | 01 02 01 02 01 02 01 02 24 | 01 02 01 02 01 02 01 02 25 | 26 | 01 02 01 02 01 02 01 02 27 | 01 02 01 02 01 02 01 02 28 | ^, 29 | :base => %w^ 30 | 00 01 01 01 01 01 01 01 31 | 01 01 01 01 01 01 01 01 32 | 33 | 01 01 01 01 01 01 01 01 34 | 01 01 01 01 01 01 01 01 35 | ^, 36 | :snare => %w^ 37 | 00 00 00 00 01 01 01 02 38 | 01 01 01 02 01 01 01 02 39 | 40 | 01 01 01 02 01 01 01 02 41 | 01 01 01 02 01 01 01 02 42 | ^, 43 | :hihat => %w^ 44 | 00 00 01 01 01 01 01 01 45 | 01 01 01 01 01 01 01 01 46 | 47 | 01 01 01 01 01 01 01 01 48 | 01 01 01 01 01 01 01 01 49 | ^, 50 | :rhodes_1 => %w^ 51 | 00 00 00 00 52 | 01 02 03 04 53 | 54 | 01 02 03 04 55 | 01 02 03 04 56 | ^, 57 | :rhodes_2 => %w^ 58 | 00 00 00 00 59 | 01 02 03 04 60 | 61 | 01 02 03 04 62 | 01 02 03 04 63 | ^, 64 | :rhodes_3 => %w^ 65 | 00 00 00 00 66 | 01 02 03 04 67 | 68 | 01 02 03 04 69 | 01 02 03 04 70 | ^, 71 | :rhodes_4 => %w^ 72 | 00 00 00 00 73 | 01 02 03 04 74 | 75 | 01 02 03 04 76 | 01 02 03 04 77 | ^, 78 | :silent => %w^ 79 | 00 80 | 00 81 | 82 | 01 83 | 01 84 | ^, 85 | :naughty => %w^ 86 | 00 87 | 00 88 | 89 | 00 90 | 01 91 | ^ 92 | } 93 | 94 | ### 95 | ### patterns 96 | ### 97 | 98 | PATTERNS = { 99 | 100 | :bass => { 101 | 01 => %q^ 102 | 32a1[attack 0.1][sustain 0.05] 32a 103 | 32a 32a 104 | 32a 32a2 105 | 32a1 32a 106 | 107 | 32a[sustain 0.1] 32a 108 | 32a 32a 109 | 32a[sustain 0.15] 32a 110 | 32a2[sustain 0.1] 32a1 111 | ^, 112 | 02 => %q^ 113 | 8 16a[attack 0.2][psweep 0.5][square 0.2] 16a[attack 0.1] 114 | 8 16a 16 115 | 116 | 16a 8 16a 117 | 16 16a 16 16a 118 | 119 | 8 16a 32a 16a 32a 120 | 32a 32 16a 32 121 | ^ 122 | }, 123 | 124 | :base => { 125 | 00 => %q^ 126 | 1 127 | ^, 128 | 01 => %q^ 129 | 8d2 8d 8d 8d 130 | 8d 8d 8d 8d 131 | ^ 132 | }, 133 | 134 | :snare => { 135 | 00 => %q^ 136 | 1 137 | ^, 138 | 01 => %q^ 139 | 8 8a 8 8a 140 | 8 8a 8 8a 141 | ^, 142 | 02 => %q^ 143 | 8 8a 8 8a 144 | 16 16 8a 32 32a[volume 0.05] 16 8a[volume 0.25] 145 | ^ 146 | }, 147 | 148 | :hihat => { 149 | 00 => %q^ 150 | 1 151 | ^, 152 | 01 => %q^ 153 | 16 16a 16 16a 16 16a 16 16a 154 | 16 16a 16 16a 16 16a 16 16a 155 | ^ 156 | }, 157 | 158 | :rhodes_1 => { 159 | 00 => %q^ 160 | 1 1 161 | ^, 162 | 01 => %q^ 163 | 1c4 1e4 164 | ^, 165 | 02 => %q^ 166 | 1c4 1e4 167 | ^, 168 | 03 => %q^ 169 | 1d4 1c4 170 | ^, 171 | 04 => %q^ 172 | 1e4 1eb4 173 | ^ 174 | }, 175 | 176 | :rhodes_2 => { 177 | 00 => %q^ 178 | 1 1 179 | ^, 180 | 01 => %q^ 181 | 1e4 1g4 182 | ^, 183 | 02 => %q^ 184 | 1e4 1g4 185 | ^, 186 | 03 => %q^ 187 | 1g4 1d4 188 | ^, 189 | 04 => %q^ 190 | 1gb4 1gb4 191 | ^ 192 | }, 193 | 194 | :rhodes_3 => { 195 | 00 => %q^ 196 | 1 1 197 | ^, 198 | 01 => %q^ 199 | 1g4 1b4 200 | ^, 201 | 02 => %q^ 202 | 1g4 1b4 203 | ^, 204 | 03 => %q^ 205 | 1a4 1g4 206 | ^, 207 | 04 => %q^ 208 | 1g4 1g4 209 | ^ 210 | }, 211 | 212 | :rhodes_4 => { 213 | 00 => %q^ 214 | 1 1 215 | ^, 216 | 01 => %q^ 217 | 1b4 1d4 218 | ^, 219 | 02 => %q^ 220 | 1b4 1d4 221 | ^, 222 | 03 => %q^ 223 | 1c4 1b4 224 | ^, 225 | 04 => %q^ 226 | 1c4 1b4 227 | ^ 228 | }, 229 | 230 | :silent => { 231 | 00 => %q^ 232 | 1 1 1 1 233 | 1 1 1 1 234 | ^, 235 | 01 => %q^ 236 | 1b4 1d5 237 | 2b4 2g4 1e4 238 | 239 | 1c4 2gb5 2b4 240 | 1c4 1b3 241 | ^ 242 | }, 243 | 244 | :naughty => { 245 | 00 => %q^ 246 | 1 1 1 1 247 | 1 1 1 1 248 | ^, 249 | 01 => %q^ 250 | 2 251 | 252 | 1b4 1e4 253 | 2b3 2d4 2b4 254 | 255 | 1a4 2gb4 2a3 256 | 1eb4 1gb4 257 | ^ 258 | } 259 | 260 | } 261 | 262 | end 263 | 264 | ### 265 | ### playroutine 266 | ### 267 | 268 | require 'yaml' 269 | require './bloops' 270 | 271 | extend self 272 | 273 | def init 274 | @bloops ||= Bloops.new 275 | @bloops.tempo = Tune::BPM 276 | 277 | return if @sounds 278 | 279 | @sounds = {} 280 | YAML.load(DATA.read).each do |track,instrument| 281 | @sounds[track] = @bloops.sound instrument['sound'].split("::").inject(Object) { |c1,c2| c1.const_get(c2) } 282 | instrument.reject{|k,v| k == 'sound'}.each do |sound,value| 283 | @sounds[track].send "#{sound}=", value 284 | end 285 | end 286 | 287 | Tune::SEQUENCES.each do |track,sequences| 288 | instr = track.to_s.split('_')[0] 289 | next unless @sounds[instr] 290 | next unless Tune::PATTERNS[track] 291 | 292 | notes = '' 293 | sequences.each do |seq| 294 | seq = seq.to_i 295 | next unless Tune::PATTERNS[track][seq] 296 | notes << Tune::PATTERNS[track][seq] 297 | end 298 | @bloops.tune @sounds[instr], notes 299 | end 300 | end 301 | 302 | def play 303 | init unless @bloops 304 | @bloops.play 305 | sleep 0.05 while !@bloops.stopped? 306 | end 307 | 308 | def play_endless 309 | while true do play; end 310 | end 311 | 312 | end 313 | 314 | LousyBloopMachine.play_endless if $0 == __FILE__ 315 | 316 | ### 317 | ### instruments 318 | ### 319 | 320 | __END__ 321 | 322 | bass: 323 | sound: Bloops::SQUARE 324 | volume: 0.9 325 | attack: 0.1 326 | decay: 0.15 327 | sustain: 0.05 328 | square: 0.05 329 | phase: 0.5 330 | psweep: -0.255 331 | 332 | base: 333 | sound: Bloops::SINE 334 | volume: 0.6 335 | attack: 0.0 336 | decay: 0.25 337 | sustain: 0.15 338 | lpf: 0.45 339 | resonance: 0.4 340 | dslide: -0.3 341 | 342 | snare: 343 | sound: Bloops::NOISE 344 | volume: 0.25 345 | attack: 0.01 346 | decay: 0.305 347 | sustain: 0 348 | hpf: 0.65 349 | resonance: 0.24 350 | dslide: -0.452 351 | 352 | hihat: 353 | sound: Bloops::NOISE 354 | volume: 0.25 355 | attack: 0.150 356 | decay: 0.105 357 | sustain: 0.205 358 | hpf: 0.95 359 | 360 | rhodes: 361 | sound: Bloops::SAWTOOTH 362 | volume: 0.09 363 | attack: 0.55 364 | decay: 1.0 365 | sustain: 0.45 366 | lpf: 0.55 367 | lsweep: -0.005 368 | resonance: 0.35 369 | vibe: 0.035 370 | vspeed: 0.292 371 | phase: 0.305 372 | psweep: -0.025 373 | vdelay: 0.9 374 | 375 | silent: 376 | sound: Bloops::SINE 377 | volume: 0.45 378 | attack: 0.35 379 | decay: 0.95 380 | sustain: 0.85 381 | lpf: 0.25 382 | lsweep: -0.025 383 | hpf: 0.25 384 | hsweep: -0.025 385 | resonance: 0.75 386 | vibe: 0.055 387 | vspeed: -0.325 388 | phase: 0.505 389 | psweep: -0.025 390 | 391 | naughty: 392 | sound: Bloops::SQUARE 393 | volume: 0.15 394 | attack: 0.45 395 | decay: 0.95 396 | sustain: 0.85 397 | lpf: 0.25 398 | lsweep: -0.025 399 | hpf: 0.25 400 | hsweep: -0.025 401 | resonance: 0.65 402 | vibe: 0.065 403 | vspeed: -0.325 404 | phase: 0.305 405 | psweep: -0.025 406 | square: 0.75 407 | phase: 0.0 408 | psweep: 0.555 409 | -------------------------------------------------------------------------------- /misc/Makefile-dll: -------------------------------------------------------------------------------- 1 | # Project: portaudio-dll 2 | # Makefile created by Dev-C++ 4.9.8.2 3 | # modified 2009-01-25 by Mateusz Czaplinski for MinGW and PortAudio V19. 4 | # http://www.musescore.org/en/handbook/compile-instructions-windows-mingw 5 | 6 | TMPOBJ = ./pa_asio.o ./iasiothiscallresolver.o ./pa_win_ds.o ./dsound_wrapper.o 7 | TMPLINKOBJ = ./pa_asio.o ./iasiothiscallresolver.o ./pa_win_ds.o ./dsound_wrapper.o 8 | 9 | CPP = g++.exe 10 | CC = gcc.exe 11 | WINDRES = windres.exe 12 | RES = 13 | OBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_wmme.o ./pa_win_waveformat.o $(RES) 14 | LINKOBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_wmme.o ./pa_win_waveformat.o $(RES) 15 | LIBS = -fmessage-length=0 -export-all-symbols --add-stdcall-alias -O3 -s -lwinmm 16 | INCS = -I"../../src/common" -I"../../include" 17 | CXXINCS = -I"../../src/common" -I"../../include" 18 | BIN = portaudio.dll 19 | CXXFLAGS = $(CXXINCS) -DBUILDING_DLL=1 -O3 -fmessage-length=0 -Wall -DPA_NO_DS -DPA_NO_ASIO 20 | CFLAGS = $(CXXFLAGS) 21 | 22 | .PHONY: all all-before all-after clean clean-custom 23 | 24 | all: all-before $(BIN) all-after 25 | 26 | 27 | clean: clean-custom 28 | rm -f $(OBJ) $(BIN) 29 | 30 | DLLWRAP=dllwrap.exe 31 | DEFFILE=libportaudio.def 32 | STATICLIB=libportaudio.a 33 | 34 | $(BIN): $(LINKOBJ) 35 | $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) 36 | 37 | ./pa_skeleton.o: ../../src/common/pa_skeleton.c 38 | $(CPP) -c ../../src/common/pa_skeleton.c -o ./pa_skeleton.o $(CXXFLAGS) 39 | 40 | ./pa_stream.o: ../../src/common/pa_stream.c 41 | $(CPP) -c ../../src/common/pa_stream.c -o ./pa_stream.o $(CXXFLAGS) 42 | 43 | ./pa_trace.o: ../../src/common/pa_trace.c 44 | $(CPP) -c ../../src/common/pa_trace.c -o ./pa_trace.o $(CXXFLAGS) 45 | 46 | ./pa_allocation.o: ../../src/common/pa_allocation.c 47 | $(CPP) -c ../../src/common/pa_allocation.c -o ./pa_allocation.o $(CXXFLAGS) 48 | 49 | ./pa_converters.o: ../../src/common/pa_converters.c 50 | $(CPP) -c ../../src/common/pa_converters.c -o ./pa_converters.o $(CXXFLAGS) 51 | 52 | ./pa_cpuload.o: ../../src/common/pa_cpuload.c 53 | $(CPP) -c ../../src/common/pa_cpuload.c -o ./pa_cpuload.o $(CXXFLAGS) 54 | 55 | ./pa_dither.o: ../../src/common/pa_dither.c 56 | $(CPP) -c ../../src/common/pa_dither.c -o ./pa_dither.o $(CXXFLAGS) 57 | 58 | ./pa_front.o: ../../src/common/pa_front.c 59 | $(CPP) -c ../../src/common/pa_front.c -o ./pa_front.o $(CXXFLAGS) 60 | 61 | ./pa_process.o: ../../src/common/pa_process.c 62 | $(CPP) -c ../../src/common/pa_process.c -o ./pa_process.o $(CXXFLAGS) 63 | 64 | #./pa_asio.o: ../../pa_asio/pa_asio.cpp 65 | # $(CPP) -c ../../pa_asio/pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS) 66 | 67 | ./pa_win_util.o: ../../src/os/win/pa_win_util.c 68 | $(CPP) -c ../../src/os/win/pa_win_util.c -o ./pa_win_util.o $(CXXFLAGS) 69 | 70 | ./pa_win_hostapis.o: ../../src/os/win/pa_win_hostapis.c 71 | $(CPP) -c ../../src/os/win/pa_win_hostapis.c -o ./pa_win_hostapis.o $(CXXFLAGS) 72 | 73 | #./pa_win_ds.o: ../../pa_win_ds/pa_win_ds.c 74 | # $(CPP) -c ../../pa_win_ds/pa_win_ds.c -o ./pa_win_ds.o $(CXXFLAGS) 75 | #./pa_win_ds.o: ../../src/hostapi/dsound/pa_win_ds.c 76 | # $(CPP) -c ../../src/hostapi/dsound/pa_win_ds.c -o ./pa_win_ds.o $(CXXFLAGS) 77 | 78 | #./dsound_wrapper.o: ../../pa_win_ds/dsound_wrapper.c 79 | # $(CPP) -c ../../pa_win_ds/dsound_wrapper.c -o ./dsound_wrapper.o $(CXXFLAGS) 80 | #./dsound_wrapper.o: ../../src/hostapi/dsound/pa_win_ds_dynlink.c 81 | # $(CPP) -c ../../src/hostapi/dsound/pa_win_ds_dynlink.c -o ./dsound_wrapper.o $(CXXFLAGS) 82 | 83 | ./pa_win_wmme.o: ../../src/hostapi/wmme/pa_win_wmme.c 84 | $(CPP) -c ../../src/hostapi/wmme/pa_win_wmme.c -o ./pa_win_wmme.o $(CXXFLAGS) 85 | 86 | #./iasiothiscallresolver.o: ../../pa_asio/iasiothiscallresolver.cpp 87 | # $(CPP) -c ../../pa_asio/iasiothiscallresolver.cpp -o ./iasiothiscallresolver.o $(CXXFLAGS) 88 | 89 | ./pa_win_waveformat.o: ../../src/os/win/pa_win_waveformat.c 90 | $(CPP) -c ../../src/os/win/pa_win_waveformat.c -o ./pa_win_waveformat.o $(CXXFLAGS) 91 | 92 | -------------------------------------------------------------------------------- /sounds/dart.blu: -------------------------------------------------------------------------------- 1 | type noise 2 | punch 0.524 3 | sustain 0.160 4 | decay 0.367 5 | freq 0.296 6 | slide -0.373 7 | vibe 0.665 8 | vspeed 0.103 9 | phase 0.141 10 | psweep -0.005 11 | -------------------------------------------------------------------------------- /sounds/error.blu: -------------------------------------------------------------------------------- 1 | type square 2 | sustain 0.333 3 | decay 0.380 4 | freq 0.336 5 | slide 0.292 6 | square 0.289 7 | sweep 0.020 8 | vibe 0.002 9 | lpf 0.220 10 | lsweep 0.015 11 | resonance 0.875 12 | aspeed 0.035 13 | repeat 0.551 14 | -------------------------------------------------------------------------------- /sounds/ice.blu: -------------------------------------------------------------------------------- 1 | type square 2 | punch 0.441 3 | sustain 0.067 4 | decay 0.197 5 | freq 0.499 6 | -------------------------------------------------------------------------------- /sounds/jump.blu: -------------------------------------------------------------------------------- 1 | type square 2 | sustain 0.266 3 | decay 0.187 4 | freq 0.268 5 | slide 0.179 6 | square 0.326 7 | vibe 0.227 8 | vspeed 0.231 9 | -------------------------------------------------------------------------------- /sounds/pogo.blu: -------------------------------------------------------------------------------- 1 | type square 2 | volume 0.977 3 | punch 0.190 4 | sustain 0.165 5 | slide 0.100 6 | dslide 0.030 7 | square 0.048 8 | sweep -0.055 9 | vibe 0.437 10 | vspeed 0.310 11 | lpf 0.355 12 | resonance 0.185 13 | hpf 0.205 14 | hsweep 0.255 15 | arp 0.677 16 | aspeed 0.275 17 | phase 0.200 18 | psweep -0.565 19 | repeat 0.500 20 | -------------------------------------------------------------------------------- /sounds/stun.blu: -------------------------------------------------------------------------------- 1 | type sawtooth 2 | sustain 0.306 3 | decay 0.477 4 | freq 0.429 5 | slide 0.217 6 | repeat 0.677 7 | --------------------------------------------------------------------------------