1 /*
2 BinauralBeat.c
3 Copyright (C) 2008 Bret Logan
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 //Purpose: BB loads an array with 32-bit mixed stereo PCM sound data,
21 // specifically mixing any number of "voices" (which currently can
22 // be either Pink Noise or a pair of stereo-separated pure sine
23 // waves implementing the Binaural Beat principle).
24
25 //To use BB:
26 // 1) Set the number of Voices with BB_InitVoices(#);
27 // 2) Allot Entry memory for each voice alloted in step 1 by running BB_SetupVoice() on each (BB_LoadDefaultVoice() gives an example)
28 // 3) Load the entries alotted in step 2 for each voice in any way you see fit (see BB_LoadDefaultVoice() for example);
29 // 4) Run BB_CalibrateVoice() on each voice to load up the internal variables, set BB_LoopCount (1 for 1 pass, 0 for infinite);
30 // 5) Init your sound code (I usually use PortAudio), giving it BB_MainLoop() as the fillup callback
31 // 6) Start your sound routine, ideally running your sound in it's own thread; check BB_InfoFlag occasionally for state info if desired
32 // 7) When you are done with BB, cleanup all BB resources by running BB_CleanupVoices();
33 //That's it. In pseudo code form:
34 //START pseudo code
35 // BB_InitVoices(2);
36 // for (int i = 0; i < BB_VoiceCount; i++) {
37 // BB_SetupVoice(i, BB_DefaultBBSched,
38 // (sizeof(BB_DefaultBBSched)/sizeof(BB_PRECISION_TYPE))/BB_EVENT_NUM_OF_ELEMENTS);
39 // }
40 // BB_Voice[0].type = BB_VOICETYPE_PINKNOISE;
41 //Put your sound code here, putting BB_MainLoop() in it's callback to create input. When done making sound:
42 // BB_CleanupVoices();
43 //END pseudo code
44 //Notes:
45 // - IMPORTANT: when user reloads all voices in BB, they must be sure to zero BB_TotalDuration
46 // before BB_CalibrateVoice is run, because the old BB_TotalDuration will persist
47 // - IMPORTANT: it is important that User sets up voices so that they are all the same TotalDuration,
48 // because BB will set BB_InfoFlag to BB_COMPLETED and/or BB_NEWLOOP whenever *any* voice ends.
49 // IOW, it is the responsibility of user to make all voices the same lenght in whatever way they see fit.
50 // - All volumes are in the range 0.0 to 1.0
51 // - You can start up sound and not worry that no data has been given
52 // yet, since as long as BB_VoiceCount == 0, only 0's will be passed to sound engine.
53 //TODO:
54 // - make it so that noise at full volume doesn't break-up
55 // - figure out a way (union?) to have data members have names that sound relevant to their voices
56 // - decide whether they're called Entries or Events
57
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <math.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include "BinauralBeat.h"
64
65 //these are globals defined in SoundEngine.h:
66 BB_VoiceData *BB_Voice = NULL;
67 const unsigned int BB_COMPLETED = 1;
68 const unsigned int BB_NEWLOOP = 2;
69 const unsigned int BB_NEWENTRY = 4;
70 const int BB_UPDATEPERIOD_SAMPLES = 16; //larger the number, less frequently I do some computationally expensive stuff. Ex: 441 = every .01 sec. @ 44100khz
71 const int BB_SIN_SCALER = 0x3FFF; // factors max output of sin() to fit a short (0x3fff)
72 const BB_PRECISION_TYPE BB_PI = 3.1415926535897932384626433832795;
73 const BB_PRECISION_TYPE BB_TWO_PI = 3.1415926535897932384626433832795 * 2.0;
74 const BB_PRECISION_TYPE BB_SAMPLE_FACTOR = ((3.1415926535897932384626433832795 * 2.0) / BB_AUDIOSAMPLERATE); // == 0.000142476 @ 44100.0khz
75 const BB_PRECISION_TYPE BB_AUDIOSAMPLERATE_HALF = .5 * BB_AUDIOSAMPLERATE;
76 BB_PRECISION_TYPE BB_TotalDuration = 0; //NOTE: User must be sure to zero BB_TotalDuration if resetting all voices
77 unsigned int BB_CurrentSampleCount = 0;
78 unsigned int BB_CurrentSampleCountLooped = 0;
79 unsigned int BB_InfoFlag = 0; //BB uses this only to send messages to the user, who must reset the messages.
80 int BB_ManualFreqOffsetControl = 0;
81 int BB_VoiceCount = 0;
82 int BB_Loops = 1; //user sets this to wherever BB_LoopCount should be set to in BB_Reset()
83 int BB_LoopCount = 1; // arbitrary right now; user should set this as desired
84 unsigned int BB_FileByteCount = 0;
85 int BB_WriteStopFlag = 0;
86 BB_PRECISION_TYPE BB_VolumeOverall_left = 1.0; // user can set this between 0.0 and 1.0, or negative to invert;
87 BB_PRECISION_TYPE BB_VolumeOverall_right = 1.0; // user can set this between 0.0 and 1.0, or negative to invert;
88 int BB_StereoSwap = 0; //set non-0 to swap left and right stereo channels
89 int BB_Mono = 0; //set non-0 to mix stereo channels
90 int BB_InCriticalLoopFlag = FALSE; //a brutish way to not do anything to BB_Voice data while audio thread is accessing data
91
92 //IMPORTANT NOTE, new 20070831 - BB_PauseFlag is mostly used to keep BB_MainLoop()'s thread from entering BB data while main
93 //thread is creating it. USER MUST FALSE IT WHEN DONE CREATING THE DATA:
94 int BB_PauseFlag = TRUE; //USER MUST FALSE THIS WHEN DONE CREATING THEIR DATA. It gets set TRUE whenever BB_InitVoices() is called
95 int BB_DebugFlag = FALSE;
96 void (*BB_UserSleep) (int microseconds) = NULL; //user sets this to their own function offering short sleep; used when BB is waiting for locked data
97 void (*BB_UserFunc) (int) = NULL; //user sets to their own function to cue external stimuli (gets called twice per Beat)
98 int BB_PeakL = 0; //20101014
99 int BB_PeakR = 0; //20101014
100
101 //start water stuff:
102 //size of waterdrop array:
103 #define BB_DROPLEN 8192
104 #define BB_RAINLEN 44
105 short *BB_DropMother = NULL; //20110516 this gets alloted
106 short *BB_RainMother = NULL; //20110520 this gets alloted
107 //end water stuff
108
109 // ======================================
110 //This is totally arbitrary, just to be sure something valid exists at start:
111 //beatL, beatR, Dur, Base, VolL, VolR:
112 const BB_PRECISION_TYPE BB_DefaultBBSched[] = {
113 0, 1, 0, 0, .5,
114 0, 1, 0, .5, 0,
115 0, 1, 0, 0, .5,
116 0, 1, 0, .5, 0
117 };
118
119 //======================================
120 //This gets called first, just before BB_SetupVoice:
BB_InitVoices(int NumberOfVoices)121 int BB_InitVoices (int NumberOfVoices)
122 {
123 //20070806: Was doing this here... until I realized it gets called every re-loading!
124 // BB_SeedRand (3676, 2676862);
125 int i = 0;
126
127 //a20070730: fixed critical memory leak -- was setting BB_VoiceCount = 0 BEFORE running BB_CleanupVoices()!
128 if (BB_Voice != NULL)
129 {
130 while (BB_InCriticalLoopFlag == TRUE)
131 {
132 ++i;
133 BB_DBGOUT_INT ("Waiting to exit datalock until Cleanup:", i);
134 if (NULL != BB_UserSleep)
135 {
136 BB_UserSleep (100000); // == 1/10th sec.
137 }
138 }
139 BB_PauseFlag = TRUE; //added 20070803
140 BB_CleanupVoices ();
141 }
142 //20070803: Next line seems redundant, but it can be important: may not have gotten zero'd
143 //in BB_CleanupVoices(), and BB_VoiceCount might be used by audio thread to
144 //keep from accessing invalid BB data:
145 BB_VoiceCount = 0;
146 BB_Voice = (BB_VoiceData *) calloc (NumberOfVoices, sizeof (BB_VoiceData));
147 if (BB_Voice == NULL)
148 {
149 return FALSE;
150 }
151 memset (BB_Voice, 0, NumberOfVoices * sizeof (BB_VoiceData));
152 for (i = 0; i < NumberOfVoices; i++)
153 {
154 BB_Voice[i].Entry = NULL;
155 BB_Voice[i].Drop = NULL; //20110516
156 BB_Voice[i].id = 0; //looks like this is sort of arbitrary now, for user's use
157 BB_Voice[i].mute = FALSE; //TRUE, FALSE
158 BB_Voice[i].mono = FALSE; //TRUE, FALSE [20100614]
159 BB_Voice[i].type = BB_VOICETYPE_BINAURALBEAT; //masks: BB_VOICETYPE_BINAURALBEAT, BB_VOICETYPE_PINKNOISE
160 BB_Voice[i].EntryCount = 0;
161 BB_Voice[i].CurEntry = 0;
162 BB_Voice[i].PCM_samples = NULL;
163 BB_Voice[i].PCM_samples_size = 0; //this is the raw array size (in shorts) of the PCM_samples array (NOT frame count, which would be half this)
164 BB_Voice[i].PCM_samples_currentcount = 0; //this holds current place in the array
165 BB_Voice[i].cur_beatfreq = 0.0;
166 BB_Voice[i].cur_beatfreq_phaseenvelope = 0.0;
167 BB_Voice[i].cur_beatfreq_phaseflag = 0;
168 BB_Voice[i].cur_beatfreq_phasesamplecount = 1;
169 BB_Voice[i].cur_beatfreq_phasesamplecount_start = 1;
170 BB_Voice[i].sinL = 0;
171 BB_Voice[i].sinR = 0;
172 BB_Voice[i].noiseL = 1;
173 BB_Voice[i].noiseR = 1;
174 }
175 BB_VoiceCount = NumberOfVoices;
176 return TRUE;
177 }
178
179 //======================================
180 //This gets called right after BB_InitVoices:
BB_SetupVoice(int VoiceID,int VoiceType,int mute,int mono,int NumberOfEvents)181 int BB_SetupVoice (int VoiceID, //array index of voice created by BB_InitVoices
182 int VoiceType, //a kind of BB_VOICETYPE_*
183 int mute, //TRUE or FALSE
184 int mono, //TRUE or FALSE [20100614]
185 int NumberOfEvents)
186 {
187 int i = VoiceID;
188
189 BB_Voice[i].type = VoiceType;
190 BB_Voice[i].mute = mute;
191 BB_Voice[i].mono = mono; // [20100614]
192 BB_Voice[i].EntryCount = 0;
193 if (BB_Voice[i].Drop != NULL)
194 {
195 free (BB_Voice[i].Drop);
196 BB_Voice[i].Drop = NULL; //just in case user is recycling 20110516
197 }
198 if (BB_Voice[i].Entry != NULL)
199 {
200 free (BB_Voice[i].Entry);
201 BB_Voice[i].Entry = NULL; //just in case thread is looking here
202 }
203 BB_Voice[i].CurEntry = 0;
204 BB_Voice[i].Entry =
205 (BB_EventData *) calloc (NumberOfEvents, sizeof (BB_EventData));
206 if (BB_Voice[i].Entry == NULL)
207 {
208 return FALSE;
209 }
210 memset (BB_Voice[i].Entry, 0, sizeof (BB_EventData) * NumberOfEvents);
211 BB_Voice[i].TotalDuration = 0;
212 BB_Voice[i].EntryCount = NumberOfEvents;
213 return TRUE;
214 //Now user must load this voice with data in any way they see fit, then
215 //call BB_CalibrateVoice()
216 }
217
218 //======================================
219 //you must call InitVoices() before calling this...
BB_LoadDefaultVoice(int VoiceID)220 void BB_LoadDefaultVoice (int VoiceID)
221 {
222 int NumberOfEvents =
223 (sizeof (BB_DefaultBBSched) / sizeof (BB_PRECISION_TYPE)) /
224 BB_EVENT_NUM_OF_ELEMENTS;
225 BB_DBGOUT_INT ("Sizeof Default Events Array:", (int) sizeof (BB_DefaultBBSched));
226 BB_DBGOUT_INT ("Default Voice number of events:", NumberOfEvents);
227 int i = VoiceID;
228 int j;
229 int k = 0;
230
231 BB_SetupVoice (VoiceID, BB_VOICETYPE_BINAURALBEAT, FALSE, FALSE, NumberOfEvents); //[modified 20100614]
232
233 //load up starting values:
234 for (j = 0; j < NumberOfEvents; j++)
235 {
236 BB_Voice[i].Entry[j].beatfreq_start_HALF = BB_DefaultBBSched[k++];
237 //k++; //needed until I remove corresponding part from default schedule
238 BB_Voice[i].Entry[j].duration = BB_DefaultBBSched[k++];
239 BB_Voice[i].Entry[j].basefreq_start = BB_DefaultBBSched[k++];
240 BB_Voice[i].Entry[j].volL_start = BB_DefaultBBSched[k++];
241 BB_Voice[i].Entry[j].volR_start = BB_DefaultBBSched[k++];
242 }
243
244 //do preprocessing on dataset:
245 BB_CalibrateVoice (i);
246 }
247
248 //======================================
249 //this simply sets compensates any voices found to be
250 //shorter than total duration by adding difference in duration
251 //to last DP in any voices found to be shorter
BB_FixVoiceDurations()252 int BB_FixVoiceDurations ()
253 {
254 int fixcount = 0; // set to number of voices fixed
255
256 //first get a very solid BB_TotalDuration:
257 BB_TotalDuration = 0;
258 BB_DetermineTotalDuration ();
259
260 //now add duration difference to last point of any voices found to be shorter:
261 int i;
262
263 for (i = 0; i < BB_VoiceCount; i++)
264 {
265 if (BB_Voice[i].TotalDuration < BB_TotalDuration)
266 {
267 int entry = BB_Voice[i].EntryCount - 1;
268
269 if (entry < 0)
270 {
271 entry = 0;
272 }
273 BB_Voice[i].Entry[entry].duration +=
274 (BB_TotalDuration - BB_Voice[i].TotalDuration);
275 BB_CalibrateVoice (i);
276 ++fixcount;
277 }
278 }
279 return fixcount;
280 }
281
282 //======================================
BB_DetermineTotalDuration()283 int BB_DetermineTotalDuration ()
284 {
285 BB_TotalDuration = 0;
286 int i;
287
288 for (i = 0; i < BB_VoiceCount; i++)
289 {
290 if (BB_Voice[i].TotalDuration > BB_TotalDuration)
291 {
292 BB_TotalDuration = BB_Voice[i].TotalDuration;
293 }
294 }
295 return BB_TotalDuration;
296 }
297
298 //======================================
299 //InitVoices() needs to have been called once at some point before calling this...
BB_CalibrateVoice(int VoiceID)300 int BB_CalibrateVoice (int VoiceID)
301 {
302 int i = VoiceID;
303 int j;
304 int prevEntry,
305 nextEntry;
306
307 //reset total duration:
308 BB_Voice[i].TotalDuration = 0;
309
310 for (j = 0; j < BB_Voice[i].EntryCount; j++)
311 {
312 //increment voice's total duration:
313 BB_Voice[i].TotalDuration += BB_Voice[i].Entry[j].duration;
314
315 //Now save exact total schedule samplecount at end of entry:
316 BB_Voice[i].Entry[j].AbsoluteEnd_samples = (unsigned int) (BB_Voice[i].TotalDuration * BB_AUDIOSAMPLERATE); //should I round this?
317 }
318
319 //now figure TotalDuration, SampleCounts, Ends, and Spreads:
320 for (j = 0; j < BB_Voice[i].EntryCount; j++)
321 {
322 if ((nextEntry = j + 1) >= BB_Voice[i].EntryCount)
323 {
324 nextEntry = 0;
325 }
326 BB_Voice[i].Entry[j].beatfreq_end_HALF =
327 BB_Voice[i].Entry[nextEntry].beatfreq_start_HALF;
328 BB_Voice[i].Entry[j].beatfreq_spread_HALF =
329 BB_Voice[i].Entry[j].beatfreq_end_HALF -
330 BB_Voice[i].Entry[j].beatfreq_start_HALF;
331 BB_Voice[i].Entry[j].basefreq_end =
332 BB_Voice[i].Entry[nextEntry].basefreq_start;
333 BB_Voice[i].Entry[j].basefreq_spread =
334 BB_Voice[i].Entry[j].basefreq_end - BB_Voice[i].Entry[j].basefreq_start;
335 BB_Voice[i].Entry[j].volL_end = BB_Voice[i].Entry[nextEntry].volL_start;
336 BB_Voice[i].Entry[j].volL_spread =
337 BB_Voice[i].Entry[j].volL_end - BB_Voice[i].Entry[j].volL_start;
338 BB_Voice[i].Entry[j].volR_end = BB_Voice[i].Entry[nextEntry].volR_start;
339 BB_Voice[i].Entry[j].volR_spread =
340 BB_Voice[i].Entry[j].volR_end - BB_Voice[i].Entry[j].volR_start;
341
342 if ((prevEntry = j - 1) < 0)
343 BB_Voice[i].Entry[j].AbsoluteStart_samples = 0;
344 else
345 BB_Voice[i].Entry[j].AbsoluteStart_samples =
346 BB_Voice[i].Entry[prevEntry].AbsoluteEnd_samples;
347 }
348
349 //NOTE: User must be sure to zero BB_TotalDuration if resetting all voices
350 if (BB_TotalDuration < BB_Voice[i].TotalDuration)
351 {
352 BB_TotalDuration = BB_Voice[i].TotalDuration;
353 }
354 return TRUE;
355 }
356
357 //======================================
BB_CleanupVoices()358 void BB_CleanupVoices ()
359 {
360 int i;
361 for (i = 0; i < BB_VoiceCount; i++)
362 {
363 if (BB_Voice[i].Entry != NULL)
364 {
365 free (BB_Voice[i].Entry);
366 BB_Voice[i].Entry = NULL;
367 }
368
369 if (BB_Voice[i].Drop != NULL)
370 {
371 free (BB_Voice[i].Drop);
372 BB_Voice[i].Drop = NULL;
373 }
374 //IMPORTANT: User needs to free this elsewhere; it merely gets NULL'd in BB_InitVoices() now
375 // BB_Voice[i].PCM_samples = NULL;
376 // BB_Voice[i].PCM_samples_size = 0;
377 // BB_Voice[i].PCM_samples_currentcount = 0;
378 }
379 if (BB_Voice != NULL)
380 {
381 free (BB_Voice);
382 }
383
384 BB_VoiceCount = 0;
385 BB_Voice = NULL;
386 }
387
388 //======================================
389 //////////////////////////////////////////////////
390 //BB_MainLoop() -- the big one.
391 //Give this an array (in any unit) pSoundBuffer of length
392 //(in bytes) bufferLen, and it fills it with 32-bit stereo
393 //data (alternating left-right, each 16 bits), while internally
394 //keeping track of where it last stopped in the
395 //previous call.
396 //IMPORTANT: you can set pSoundBuffer to any unit, but bufferLen must always be in bytes
397 //Extra info: BB_UPDATEPERIOD_SAMPLES sets the period of update;
398 //Fill sound buffer. BB_UPDATEPERIOD_SAMPLES sets the period of update;
399 //the higher it is, the less often periodic precalculating is done
400 //(determining entry, changing frequency, etc.).
BB_MainLoop(void * pSoundBuffer,long bufferLen)401 void BB_MainLoop (void *pSoundBuffer, long bufferLen)
402 {
403 static int updateperiod = 1; //critical: initialize as 1 so decrements to zero and resets
404
405 // static int noizval1 = 1;
406 // static int noizval2 = 1;
407 BB_PRECISION_TYPE sumL = 0,
408 sumR = 0;
409 BB_PRECISION_TYPE Sample_left,
410 Sample_right;
411 int k;
412 int voice;
413
414 // Cast whatever form pSoundBuffer came in to short ints (16 bits), since
415 // each 32 bit frame will consist of two 16bit mono waveforms, alternating
416 // left and right stereo data: [see the Java version for a byte-tailored approach]
417 signed short *pSample = (signed short int *) pSoundBuffer;
418
419 //Generally speaking, this is what I am doing:
420 //long nbSample = bufferLen / (sizeof(int));
421 //But since I always know bufferlen in in chars, I just divide by four:
422 long nbSample = bufferLen >> 2;
423
424 //-------------------------------------------
425 //START Fill sound buffer
426 //OUTER LOOP: do everything in this loop for every sample in pSoundBuffer to be filled:
427 for (k = 0; k < nbSample; k++)
428 {
429 --updateperiod;
430 //zero-out the current sample values:
431 sumL = sumR = 0;
432 if (BB_PauseFlag != TRUE && BB_Voice != NULL) //a20070730 -- critical bug fix
433 for (voice = 0; voice < BB_VoiceCount; voice++)
434 {
435 Sample_left = Sample_right = 0;
436 BB_InCriticalLoopFlag = TRUE; //added 20070803
437 //##### START Periodic stuff (the stuff NOT done every cycle)
438 if (updateperiod == 0)
439 {
440 //Should not need this, will eventually drop it:
441 while ((BB_Voice[voice].CurEntry >= BB_Voice[voice].EntryCount))
442 {
443 BB_DBGOUT_INT ("Resetting Voices: CurEntry:", BB_Voice[voice].CurEntry);
444 BB_DBGOUT_INT ("Resetting Voices: EntryCount:",
445 BB_Voice[voice].EntryCount);
446 BB_DBGOUT_INT ("Resetting Voices: Voice:", voice);
447 BB_ResetAllVoices ();
448 }
449
450 //First figure out which Entry we're at for this voice.
451 //20070728: big changes to make CurEntry persistent, to obviate need for
452 //each voice to start from zero every time (CPU load would progressively
453 //go sour with lots of entries). Method: don't zero CurEntry, instead only
454 //increment it if totalsamples is now greater than sched entry's endtime/
455 //20080218: The above method turns out not to account for when user sets
456 //BB_CurrentSampleCount manually to place BEFORE CurEntry. Fixed with this:
457 //See if totalsamples is LESS than CurEntry (very rare event):
458 while (BB_CurrentSampleCount <
459 BB_Voice[voice].Entry[BB_Voice[voice].
460 CurEntry].AbsoluteStart_samples)
461 {
462 BB_InfoFlag |= BB_NEWENTRY;
463 --BB_Voice[voice].CurEntry;
464 if (BB_Voice[voice].CurEntry < 0)
465 {
466 BB_Voice[voice].CurEntry = 0;
467 }
468 }
469
470 //Now see if totalsamples is Greater than CurEntry (common event):
471 while (BB_CurrentSampleCount >
472 BB_Voice[voice].Entry[BB_Voice[voice].
473 CurEntry].AbsoluteEnd_samples)
474 {
475 BB_InfoFlag |= BB_NEWENTRY;
476 ++BB_Voice[voice].CurEntry;
477 if (BB_Voice[voice].CurEntry >= BB_Voice[voice].EntryCount)
478 {
479 // BB_DBGOUT_INT ("Completed loop", 1 + BB_Loops - BB_LoopCount);
480 BB_CurrentSampleCountLooped += BB_CurrentSampleCount;
481 BB_CurrentSampleCount = 0;
482 //Zero CurEntry for ALL voices:
483 BB_ResetAllVoices ();
484 BB_InfoFlag |= BB_NEWLOOP;
485 if (--BB_LoopCount == 0)
486 { //tell user Schedule is totally done
487 BB_InfoFlag |= BB_COMPLETED;
488 BB_DBGOUT ("Schedule complete");
489 }
490 break;
491 }
492 }
493
494 //Now that entry housecleaning is done, start actual signal processing:
495 //NOTE: I wanted to put next line at start of voice loop, but can't
496 //because any voice can end schedule, even if muted -- so all voice
497 //must get checked.
498 if (BB_Voice[voice].mute == FALSE)
499 { //START "Voice NOT muted"
500 //this just to make BB_Voice[voice].CurEntry more handy:
501 int entry = BB_Voice[voice].CurEntry;
502
503 //First come up with a factor describing exact point in the schedule
504 //by dividing exact point in period by total period time:
505 //[NOTE: critically, duration should never be able to == 0 here because the
506 //entry "for" loop above only gets here if BB_Voice[voice].Entry[entry].AbsoluteEnd_samples
507 //is GREATER than 0]:
508 //if (BB_Voice[voice].Entry[entry].duration == 0) BB_BB_DBGOUT("BUG: duration == 0");
509 BB_PRECISION_TYPE factor;
510
511 if (0 != BB_Voice[voice].Entry[entry].duration)
512 {
513 factor =
514 (BB_CurrentSampleCount -
515 BB_Voice[voice].Entry[entry].AbsoluteStart_samples) /
516 (BB_Voice[voice].Entry[entry].duration * BB_AUDIOSAMPLERATE);
517 }
518 else
519 {
520 //NOTE: Interestingly, it actually almost never gets here unless it is first-DP, because
521 //because otherwise it is a lotto pick that BB_CurrentSampleCount would land on that DP
522 factor = 0;
523 BB_DBGOUT ("Duration == 0!");
524 }
525 //now determine volumes for this slice, since all voices use volume:
526 BB_Voice[voice].CurVolL =
527 (BB_Voice[voice].Entry[entry].volL_spread * factor) +
528 BB_Voice[voice].Entry[entry].volL_start;
529 BB_Voice[voice].CurVolR =
530 (BB_Voice[voice].Entry[entry].volR_spread * factor) +
531 BB_Voice[voice].Entry[entry].volR_start;
532
533 //Now do stuff that must be figured out at Entry level:
534 //now figure out what sort of voice it is, to do it's particular processing:
535 switch (BB_Voice[voice].type)
536 {
537 //---------A-------------
538 case BB_VOICETYPE_BINAURALBEAT:
539 //first determine base frequency to be used for this slice:
540 BB_Voice[voice].cur_basefreq =
541 (BB_Voice[voice].Entry[entry].basefreq_spread * factor) +
542 BB_Voice[voice].Entry[entry].basefreq_start;
543
544 //20071010 NOTE: heavily changed to optimize calculations and avail instantaneous BeatFreq
545 // It is now assumed that all beatfreqs are symmetric around the basefreq.
546 //now that more difficult one, calculating partially factored beat freqs:
547 //Left Freq is equal to frequency spread from Left Start to Left End (next
548 //schedule's Left Start) multiplied by above factor. Then add FreqBase.
549 BB_Voice[voice].cur_beatfreqL_factor =
550 BB_Voice[voice].cur_beatfreqR_factor =
551 (BB_Voice[voice].Entry[entry].beatfreq_spread_HALF * factor);
552
553 //get current beatfreq in Hz (for user external use):
554 BB_PRECISION_TYPE old_beatfreq = BB_Voice[voice].cur_beatfreq;
555 BB_PRECISION_TYPE new_beatfreq =
556 BB_Voice[voice].cur_beatfreq =
557 (BB_Voice[voice].cur_beatfreqL_factor +
558 BB_Voice[voice].Entry[entry].beatfreq_start_HALF) * 2;
559
560 //NOTE: BB_SAMPLE_FACTOR == 2*PI/sample_rate
561 BB_Voice[voice].cur_beatfreqL_factor =
562 (BB_Voice[voice].cur_basefreq +
563 BB_Voice[voice].Entry[entry].beatfreq_start_HALF +
564 BB_Voice[voice].cur_beatfreqL_factor) * BB_SAMPLE_FACTOR;
565
566 BB_Voice[voice].cur_beatfreqR_factor =
567 (BB_Voice[voice].cur_basefreq -
568 BB_Voice[voice].Entry[entry].beatfreq_start_HALF -
569 BB_Voice[voice].cur_beatfreqR_factor) * BB_SAMPLE_FACTOR;
570
571 //extract phase info for external stimulus cue:
572 //must have a lower limit for beatfreq or else we have divide by zero issues
573 if (new_beatfreq < .0001)
574 {
575 new_beatfreq = .0001;
576 }
577 if (old_beatfreq != new_beatfreq)
578 {
579 BB_PRECISION_TYPE phasefactor =
580 (BB_Voice[voice].cur_beatfreq_phasesamplecount /
581 (BB_PRECISION_TYPE)
582 BB_Voice[voice].cur_beatfreq_phasesamplecount_start);
583 BB_Voice[voice].cur_beatfreq_phasesamplecount_start =
584 (int) (BB_AUDIOSAMPLERATE_HALF / new_beatfreq);
585 BB_Voice[voice].cur_beatfreq_phasesamplecount =
586 BB_Voice[voice].cur_beatfreq_phasesamplecount_start * phasefactor;
587 }
588 break;
589
590 //---------A-------------
591 case BB_VOICETYPE_PINKNOISE:
592 break;
593
594 //---------A-------------
595 case BB_VOICETYPE_PCM:
596 if (NULL != BB_Voice[voice].PCM_samples)
597 {
598 BB_Voice[voice].PCM_samples_currentcount = BB_CurrentSampleCount;
599 if (BB_Voice[voice].PCM_samples_currentcount >=
600 BB_Voice[voice].PCM_samples_size)
601 {
602 BB_Voice[voice].PCM_samples_currentcount =
603 BB_CurrentSampleCount % (BB_Voice[voice].PCM_samples_size);
604 }
605 }
606 break;
607
608 //---------A-------------
609 case BB_VOICETYPE_ISOPULSE:
610 case BB_VOICETYPE_ISOPULSE_ALT:
611 {
612 //in isochronic tones, the beat frequency purely affects base
613 //frequency pulse on/off duration, not its frequency:
614 //New way starting 20110119:
615 //The approach here is to re-scale however much time was left in
616 //the old beatfreq's pulse to how much would be left in the new
617 //one's. Otherwise each pulse would have to time-out before a
618 //new beatfreq could be modulated - unacceptable in many ways.
619 //first get the exact base frequency for this slice:
620 BB_Voice[voice].cur_basefreq =
621 (BB_Voice[voice].Entry[entry].basefreq_spread * factor) +
622 BB_Voice[voice].Entry[entry].basefreq_start;
623
624 //Now get current beatfreq in Hz for this slice:
625 // ("half" works because period alternates silence and tone for this kind of voice)
626 BB_PRECISION_TYPE old_beatfreq = BB_Voice[voice].cur_beatfreq;
627 BB_Voice[voice].cur_beatfreq =
628 ((BB_Voice[voice].Entry[entry].beatfreq_spread_HALF * factor) +
629 BB_Voice[voice].Entry[entry].beatfreq_start_HALF) * 2;
630
631 //must have a lower limit for beatfreq or else we have divide by zero issues
632 if (BB_Voice[voice].cur_beatfreq < .0001)
633 {
634 BB_Voice[voice].cur_beatfreq = .0001;
635 }
636
637 //Set both channels to the same base frequency:
638 //NOTE: BB_SAMPLE_FACTOR == 2*PI/sample_rate
639 BB_Voice[voice].cur_beatfreqR_factor =
640 BB_Voice[voice].cur_beatfreqL_factor =
641 BB_Voice[voice].cur_basefreq * BB_SAMPLE_FACTOR;
642
643 //if this is a new beatfreq, adjust phase accordingly
644 if (old_beatfreq != BB_Voice[voice].cur_beatfreq)
645 {
646 BB_PRECISION_TYPE phasefactor =
647 (BB_Voice[voice].cur_beatfreq_phasesamplecount /
648 (BB_PRECISION_TYPE)
649 BB_Voice[voice].cur_beatfreq_phasesamplecount_start);
650 BB_Voice[voice].cur_beatfreq_phasesamplecount_start =
651 (int) (BB_AUDIOSAMPLERATE_HALF / BB_Voice[voice].cur_beatfreq);
652 BB_Voice[voice].cur_beatfreq_phasesamplecount =
653 BB_Voice[voice].cur_beatfreq_phasesamplecount_start * phasefactor;
654 }
655 }
656 break;
657
658 //---------A-------------
659 //Waterdrops: unless user really knows what they're doing,
660 //they should leave both base and beat freq at 0 to
661 //get raindrop defaults. Otherwise, this is the equation:
662 //Drop count(set only at start) == beatfreq_start_HALF * 2
663 //Random Threshold == basefreq_start
664 //The default values are 2 and 1/ 2834) respectively.
665 //Note: a Drop that's supposed to exist is found to be
666 //NULL that's the signal to set up the whole shebang here:
667 case BB_VOICETYPE_WATERDROPS: //20110516
668 {
669 if (NULL == BB_Voice[voice].Drop)
670 {
671 if (NULL == BB_DropMother)
672 {
673 BB_DropMother = BB_WaterInit (BB_DROPLEN, 600);
674 }
675 BB_WaterVoiceInit (voice);
676 }
677
678 //determine base frequency to be used for this slice:
679 BB_Voice[voice].cur_basefreq =
680 (BB_Voice[voice].Entry[entry].basefreq_spread * factor) +
681 BB_Voice[voice].Entry[entry].basefreq_start;
682 }
683 break;
684
685 //---------A-------------
686 case BB_VOICETYPE_RAIN: //20110520
687 {
688 if (NULL == BB_Voice[voice].Drop)
689 {
690 if (NULL == BB_RainMother)
691 {
692 BB_RainMother = BB_WaterInit (BB_RAINLEN, 3.4);
693 }
694 BB_WaterVoiceInit (voice);
695 }
696
697 //determine base frequency to be used for this slice:
698 BB_Voice[voice].cur_basefreq =
699 (BB_Voice[voice].Entry[entry].basefreq_spread * factor) +
700 BB_Voice[voice].Entry[entry].basefreq_start;
701 }
702 break;
703
704 default:
705 break;
706 } //END voicetype switch
707 } //END "Voice NOT muted"
708 }
709 //##### END Periodic stuff (the stuff NOT done every cycle)
710
711 //####START high priority calculations (done for every sample)
712 if (BB_Voice[voice].mute == FALSE)
713 { //START "Voice NOT muted"
714 //now figure out what sort of voice it is, to do it's particular processing:
715 switch (BB_Voice[voice].type)
716 {
717 //---------B-------------
718 case BB_VOICETYPE_BINAURALBEAT:
719 //advance to the next sample for each channel:
720 BB_Voice[voice].sinPosL += BB_Voice[voice].cur_beatfreqL_factor;
721 if (BB_Voice[voice].sinPosL >= BB_TWO_PI)
722 {
723 BB_Voice[voice].sinPosL -= BB_TWO_PI;
724 }
725 BB_Voice[voice].sinPosR += BB_Voice[voice].cur_beatfreqR_factor;
726 if (BB_Voice[voice].sinPosR >= BB_TWO_PI)
727 {
728 BB_Voice[voice].sinPosR -= BB_TWO_PI;
729 }
730
731 //there are probably shortcuts to avoid doing a sine for every voice, but I don't know them:
732 BB_Voice[voice].sinL = sin (BB_Voice[voice].sinPosL);
733 Sample_left = BB_Voice[voice].sinL * BB_SIN_SCALER;
734 BB_Voice[voice].sinR = sin (BB_Voice[voice].sinPosR);
735 Sample_right = BB_Voice[voice].sinR * BB_SIN_SCALER;
736
737 //extract external stimuli cue:
738 if (1 > --BB_Voice[voice].cur_beatfreq_phasesamplecount)
739 {
740 BB_Voice[voice].cur_beatfreq_phasesamplecount =
741 BB_Voice[voice].cur_beatfreq_phasesamplecount_start;
742 if (0 != BB_Voice[voice].cur_beatfreq_phaseflag)
743 {
744 BB_Voice[voice].cur_beatfreq_phaseflag = 0;
745 }
746 else
747 {
748 BB_Voice[voice].cur_beatfreq_phaseflag = 1;
749 }
750 if (NULL != BB_UserFunc)
751 {
752 BB_UserFunc (voice);
753 }
754 BB_Voice[voice].cur_beatfreq_phaseenvelope = 0;
755 }
756 break;
757
758 //---------B-------------
759 case BB_VOICETYPE_PINKNOISE:
760 /*
761 //i put the following in an equation to get ready to make
762 //other colors of noise:
763 //NOTE: the following odd equation is a fast way
764 //of simulating "pink noise" from white:
765 BB_Voice[voice].noiseL =
766 ((BB_Voice[voice].noiseL * 31) + (BB_Rand () >> 15)) >> 5;
767 Sample_left = BB_Voice[voice].noiseL;
768 BB_Voice[voice].noiseR =
769 ((BB_Voice[voice].noiseR * 31) + (BB_Rand () >> 15)) >> 5;
770 Sample_right = BB_Voice[voice].noiseR;
771 */
772 Sample_left = BB_LoPass (&BB_Voice[voice].noiseL, BB_Rand () >> 15);
773 Sample_right = BB_LoPass (&BB_Voice[voice].noiseR, BB_Rand () >> 15);
774 //Sample_right = BB_PowerLaw (BB_Rand (), 0x7fffffff, 0x7fff);
775 break;
776
777 case BB_VOICETYPE_PCM:
778 {
779 if (NULL != BB_Voice[voice].PCM_samples)
780 {
781 if (BB_Voice[voice].PCM_samples_currentcount >=
782 BB_Voice[voice].PCM_samples_size)
783 {
784 BB_Voice[voice].PCM_samples_currentcount =
785 BB_CurrentSampleCount % (BB_Voice[voice].PCM_samples_size);
786 }
787 Sample_left =
788 ((short)
789 ((BB_Voice[voice].PCM_samples
790 [BB_Voice[voice].PCM_samples_currentcount]) >> 16));
791 Sample_right =
792 ((short)
793 (BB_Voice[voice].PCM_samples
794 [BB_Voice[voice].PCM_samples_currentcount]));
795 ++BB_Voice[voice].PCM_samples_currentcount;
796 }
797 }
798 break;
799
800 //---------B-------------
801 case BB_VOICETYPE_ISOPULSE:
802 case BB_VOICETYPE_ISOPULSE_ALT:
803 {
804 int iso_alternating = 0;
805 if (BB_VOICETYPE_ISOPULSE_ALT == BB_Voice[voice].type)
806 {
807 iso_alternating = 1;
808 }
809 //New way starting 20110119:
810 //advance to the next sample for each channel:
811 BB_Voice[voice].sinPosL += BB_Voice[voice].cur_beatfreqL_factor;
812 if (BB_Voice[voice].sinPosL >= BB_TWO_PI)
813 {
814 BB_Voice[voice].sinPosL -= BB_TWO_PI;
815 }
816 BB_Voice[voice].sinPosR = BB_Voice[voice].sinPosL;
817
818 //now determine whether tone or silence:
819 //Set toggle-time for current beat polarity (for user external use)
820 if (1 > --BB_Voice[voice].cur_beatfreq_phasesamplecount)
821 {
822 BB_Voice[voice].cur_beatfreq_phasesamplecount =
823 BB_Voice[voice].cur_beatfreq_phasesamplecount_start;
824 if (0 != BB_Voice[voice].cur_beatfreq_phaseflag)
825 {
826 BB_Voice[voice].cur_beatfreq_phaseflag = 0;
827 }
828 else
829 {
830 BB_Voice[voice].cur_beatfreq_phaseflag = 1;
831 }
832
833 if (NULL != BB_UserFunc)
834 {
835 BB_UserFunc (voice);
836 }
837 BB_Voice[voice].cur_beatfreq_phaseenvelope = 0;
838 }
839
840 //there are probably shortcuts to avoid doing a sine for every sample, but I don't know them:
841 BB_Voice[voice].sinR =
842 BB_Voice[voice].sinL = sin (BB_Voice[voice].sinPosL);
843
844 if (0 != BB_Voice[voice].cur_beatfreq_phaseflag)
845 {
846 Sample_left =
847 BB_Voice[voice].sinL * BB_SIN_SCALER *
848 (1.0 - BB_Voice[voice].cur_beatfreq_phaseenvelope);
849
850 //Decide if it is alternating or not:
851 if (0 == iso_alternating)
852 {
853 Sample_right = Sample_left;
854 }
855 else
856 {
857 Sample_right = BB_Voice[voice].sinL * BB_SIN_SCALER *
858 BB_Voice[voice].cur_beatfreq_phaseenvelope;
859 }
860 }
861 else
862 {
863 Sample_left =
864 BB_Voice[voice].sinL * BB_SIN_SCALER *
865 BB_Voice[voice].cur_beatfreq_phaseenvelope;
866 if (0 == iso_alternating)
867 {
868 Sample_right = Sample_left;
869 }
870 else
871 {
872 Sample_right = BB_Voice[voice].sinL * BB_SIN_SCALER *
873 (1.0 - BB_Voice[voice].cur_beatfreq_phaseenvelope);
874 }
875 }
876
877 //cur_beatfreq_data is used arbitrarily as a Modulator here (to reduce harmonics in transition between on and off pulses)
878 if ((BB_Voice[voice].cur_beatfreq_phaseenvelope += .01) > 1)
879 BB_Voice[voice].cur_beatfreq_phaseenvelope = 1;
880 }
881 break;
882
883 //---------B-------------
884 case BB_VOICETYPE_WATERDROPS:
885 {
886 BB_Water (voice, BB_DropMother, BB_DROPLEN, 8.f);
887
888 Sample_left = BB_Voice[voice].cur_beatfreq_phasesamplecount;
889 Sample_right = BB_Voice[voice].cur_beatfreq_phasesamplecount_start;
890 }
891 break;
892
893 //---------B-------------
894 //see waterdrops for explanation
895 case BB_VOICETYPE_RAIN:
896 {
897 BB_Water (voice, BB_RainMother, BB_RAINLEN, .15f);
898
899 Sample_left = BB_Voice[voice].cur_beatfreq_phasesamplecount;
900 Sample_right = BB_Voice[voice].cur_beatfreq_phasesamplecount_start;
901 }
902 break;
903
904 default:
905 break;
906 }
907 //handle stereo/mono mixing:
908 if (TRUE != BB_Voice[voice].mono)
909 {
910 sumL += (Sample_left * BB_Voice[voice].CurVolL);
911 sumR += (Sample_right * BB_Voice[voice].CurVolR);
912 }
913 else
914 {
915 Sample_left = (Sample_left + Sample_right) * 0.5;
916 sumL += (Sample_left * BB_Voice[voice].CurVolL);
917 sumR += (Sample_left * BB_Voice[voice].CurVolR);
918 }
919 } //END "Voice NOT muted"
920 //####END high priority calculations (done for every sample)
921 } //END Voices loop
922
923 BB_InCriticalLoopFlag = FALSE;
924
925 //Finally, load the array with the mixed audio:
926 //In C, this is the approach:
927 if (TRUE == BB_Mono)
928 {
929 sumL = .5 * (sumL + sumR);
930 sumR = sumL;
931 }
932
933 int peakL,
934 peakR;
935 if (FALSE == BB_StereoSwap)
936 {
937 *pSample++ = peakL = (signed short) (sumL * BB_VolumeOverall_left);
938 *pSample++ = peakR = (signed short) (sumR * BB_VolumeOverall_right);
939 }
940 else
941 {
942 *pSample++ = peakL = (signed short) (sumR * BB_VolumeOverall_right);
943 *pSample++ = peakR = (signed short) (sumL * BB_VolumeOverall_left);
944 }
945
946 //20101014: attempt at external volume monitoring:
947 if (abs (peakL) > BB_PeakL)
948 {
949 BB_PeakL = abs (peakL);
950 //BB_DBGOUT_INT ("BB_PeakL:", BB_PeakL);
951 }
952 if (abs (peakR) > BB_PeakR)
953 {
954 BB_PeakR = abs (peakR);
955 //BB_DBGOUT_INT ("BB_PeakR:", BB_PeakR);
956 }
957
958 //In Java, this is the equivalent:
959 //pSample[pSample_index++] = (byte) (((short)sumL) & 0xFF);
960 //pSample[pSample_index++] = (byte) (((short)sumL) >> 8);
961 //pSample[pSample_index++] = (byte) (((short)sumR) & 0xFF);
962 //pSample[pSample_index++] = (byte) (((short)sumR) >> 8);
963
964 if (updateperiod == 0)
965 {
966 updateperiod = BB_UPDATEPERIOD_SAMPLES;
967 BB_CurrentSampleCount += BB_UPDATEPERIOD_SAMPLES; // NOTE: I could also just do BB_CurrentSampleCount++ for each sample...
968 }
969 } //END samplecount
970 // END Fill sound buffer
971 }
972
973 //======================================
BB_Reset()974 void BB_Reset ()
975 {
976 BB_CurrentSampleCount = BB_CurrentSampleCountLooped = 0;
977 BB_InfoFlag &= ~BB_COMPLETED;
978 BB_LoopCount = BB_Loops;
979 BB_ResetAllVoices ();
980 }
981
982 //======================================
BB_ResetAllVoices()983 inline void BB_ResetAllVoices ()
984 {
985 if (BB_Voice != NULL)
986 {
987 int i;
988
989 for (i = 0; i < BB_VoiceCount; i++)
990 {
991 BB_Voice[i].CurEntry = 0;
992 }
993 }
994 }
995
996 //======================================
997 // I need to add two size parameters when I am done- in the simplified case of 44100
998 // 2 channel, I can basically sum the size of WAVheader in to total data size, then
999 // subtract 8 (god knows why - RIFF is insane)
BB_WriteWAVFile(char * szFilename)1000 int BB_WriteWAVFile (char *szFilename)
1001 {
1002 FILE *stream;
1003
1004 if ((stream = fopen (szFilename, "wb")) == NULL)
1005 {
1006 return 0;
1007 }
1008
1009 BB_WriteWAVToStream (stream);
1010 //now that data has been written, write those two damn header values correctly this time:
1011 rewind (stream);
1012 BB_WriteWAVHeaderToStream (stream);
1013 fclose (stream);
1014 return 1;
1015 }
1016
1017 //======================================
1018 //writes a basic 16bit 44100hz stereo WAV file to whatever stream you give it (stdout, file, etc.)
1019 //it is up to the user to ensure that the stream is writable and in binary mode.
BB_WriteWAVHeaderToStream(FILE * stream)1020 void BB_WriteWAVHeaderToStream (FILE * stream)
1021 {
1022 struct WAVheader
1023 {
1024 char ckID[4]; // chunk id 'RIFF'
1025 unsigned int ckSize; // chunk size [it is total filesize-8]
1026 char wave_ckID[4]; // wave chunk id 'WAVE'
1027 char fmt_ckID[4]; // format chunk id 'fmt '
1028 unsigned int fmt_ckSize; // format chunk size
1029 unsigned short formatTag; // format tag currently pcm
1030 unsigned short nChannels; // number of channels
1031 unsigned int nSamplesPerSec; // sample rate in hz
1032 unsigned int nAvgBytesPerSec; // average bytes per second
1033 unsigned short nBlockAlign; // number of bytes per sample
1034 unsigned short nBitsPerSample; // number of bits in a sample
1035 char data_ckID[4]; // data chunk id 'data'
1036 unsigned int data_ckSize; // length of data chunk [byte count of actual data (not descriptors)]
1037 }
1038 wavh;
1039
1040 wavh.ckID[0] = 'R';
1041 wavh.ckID[1] = 'I';
1042 wavh.ckID[2] = 'F';
1043 wavh.ckID[3] = 'F';
1044 wavh.ckSize = BB_FileByteCount + sizeof (wavh) - 8; //ultimately needs to be accurate
1045 wavh.wave_ckID[0] = 'W';
1046 wavh.wave_ckID[1] = 'A';
1047 wavh.wave_ckID[2] = 'V';
1048 wavh.wave_ckID[3] = 'E';
1049 wavh.fmt_ckID[0] = 'f';
1050 wavh.fmt_ckID[1] = 'm';
1051 wavh.fmt_ckID[2] = 't';
1052 wavh.fmt_ckID[3] = ' ';
1053 wavh.fmt_ckSize = 16;
1054 wavh.formatTag = 1;
1055 wavh.nChannels = 2;
1056 wavh.nSamplesPerSec = 44100;
1057 wavh.nAvgBytesPerSec = 176400; //nAvgBytesPerSec= nSamplesPerSec* nBitsPerSample/8* nChannels
1058 wavh.nBlockAlign = 4;
1059 wavh.nBitsPerSample = 16;
1060 wavh.data_ckID[0] = 'd';
1061 wavh.data_ckID[1] = 'a';
1062 wavh.data_ckID[2] = 't';
1063 wavh.data_ckID[3] = 'a';
1064 wavh.data_ckSize = BB_FileByteCount; //ultimately needs to be accurate
1065
1066 //create the header:
1067 fwrite (&wavh, sizeof (wavh), 1, stream);
1068 }
1069
1070 //======================================
1071 //writes a basic 16bit 44100hz stereo WAV file to whatever stream you give it (stdout, file, etc.)
1072 //it is up to the user to ensure that the stream is writable and in binary mode.
BB_WriteWAVToStream(FILE * stream)1073 int BB_WriteWAVToStream (FILE * stream)
1074 {
1075 #define WRITESIZE 4
1076 signed short buff[WRITESIZE];
1077
1078 //20051129 - I need to estimate final size of file for stream/piping use,
1079 //and so something is in there in case user cancels mid-write:
1080 BB_FileByteCount = (unsigned int) (BB_Loops * BB_TotalDuration * 176400);
1081
1082 BB_WriteWAVHeaderToStream (stream);
1083
1084 BB_FileByteCount = 0; //now reset FileByteCount of estimate in order to have it count real samples
1085 BB_WriteStopFlag = 0;
1086
1087 BB_Reset (); //make sure we start at absolute beginning
1088
1089 // BB_WriteStopFlag = 0;
1090 while (!(BB_InfoFlag & BB_COMPLETED) && FALSE == BB_WriteStopFlag)
1091 {
1092 BB_MainLoop (buff, WRITESIZE);
1093 fwrite (buff, WRITESIZE, 1, stream);
1094 BB_FileByteCount += WRITESIZE;
1095 }
1096
1097 return 1;
1098 }
1099
1100 //======================================
1101 //this function is to assist user in cleaning up any PCM data
1102 //they opened to use here; when voice PCM_samples == NULL, it gets
1103 //ignored by audio engine.
BB_NullAllPCMData()1104 void BB_NullAllPCMData ()
1105 {
1106 int i;
1107
1108 for (i = 0; i < BB_VoiceCount; i++)
1109 {
1110 BB_Voice[i].PCM_samples = NULL;
1111 BB_Voice[i].PCM_samples_size = 1; //this is set to 1 simply so that there is never a divide by zero situation.
1112 BB_Voice[i].PCM_samples_currentcount = 0;
1113 }
1114 }
1115
1116 //################################################
1117 //START PSEUDORANDOM NUMBER GENERATOR SECTION
1118 //Make a choice.
1119 //=============================================
1120 //~ The McGill Super-Duper Random Number Generator
1121 //~ G. Marsaglia, K. Ananthanarayana, N. Paul
1122 //~ Incorporating the Ziggurat method of sampling from decreasing
1123 //~ or symmetric unimodal density functions.
1124 //~ G. Marsaglia, W.W. Tsang
1125 //~ Rewritten into C by E. Schneider
1126 //~ [Date last modified: 05-Jul-1997]
1127 //=============================================
1128 //These being longs are the key to the long between-repeat period:
1129 unsigned long BB_mcgn = 3677;
1130 unsigned long BB_srgn = 127;
1131
1132 #define ML_MULT 69069L
1133 //IMPORTANT OBSERVATION: when using a fixed i2, for some
1134 //reason Seed pairs for i1 like this:
1135 // even
1136 // even+1
1137 //produce idential sequences when r2 returned (r1 >> 12).
1138 //Practically, this means that 2 and 3 produce one landscape;
1139 //likewise 6 and 7, 100 and 101, etc.
1140 //This is why i do the dopey "add 1" to i2
1141 //ALSO, JUST DON'T USE 0 FOR i1 or i2.
BB_SeedRand(unsigned int i1,unsigned int i2)1142 void BB_SeedRand (unsigned int i1, unsigned int i2)
1143 {
1144 if (i2 == (unsigned int) -1)
1145 {
1146 i2 = i1 + 1; //yech
1147 }
1148 BB_mcgn = (unsigned long) ((i1 == 0L) ? 0L : i1 | 1L);
1149 BB_srgn = (unsigned long) ((i2 == 0L) ? 0L : (i2 & 0x7FFL) | 1L);
1150 BB_DBGOUT_INT ("BB_mcgn:", (int) BB_mcgn);
1151 BB_DBGOUT_INT ("BB_srgn:", (int) BB_srgn);
1152 }
1153
1154 /*
1155 //these lines are useful for debugging Rand():
1156 int test = r1;
1157 if (test > 0 && test < 0xffff) BB_DBGOUT_INT("Got a positive: ", test);
1158 if (test < 0 && test > -0xffff) BB_DBGOUT_INT("Got a negative: ", test);
1159 */
1160
1161 //======================================
1162 //This returns an int from -2^31 to +2^31;
BB_Rand()1163 int BB_Rand ()
1164 {
1165 unsigned long r0,
1166 r1;
1167
1168 r0 = (BB_srgn >> 15);
1169 r1 = BB_srgn ^ r0;
1170 r0 = (r1 << 17);
1171 BB_srgn = r0 ^ r1;
1172 BB_mcgn = ML_MULT * BB_mcgn;
1173 r1 = BB_mcgn ^ BB_srgn;
1174 return r1;
1175 }
1176
1177 ///////////////////////////////////////////
1178 //returns a random double between -1 and 1
BB_Rand_pm()1179 double BB_Rand_pm ()
1180 {
1181 // return (BB_Rand () / (double) (1 << 31));
1182 //20100604: discovered bug, was sizeof(long), needed to be sizeof(int):
1183 return (BB_Rand () / (double) (1 << ((sizeof (int) * 8) - 1)));
1184 }
1185
1186 //=========================================
1187 //unconscionably shorthand way to lo-pass
1188 //noiz "pink": given a persistent variable
1189 //you maintain, and an int of audio data
1190 //this func smoothes it a LOT:
BB_LoPass(int * staticvar,int value)1191 inline int BB_LoPass (int *staticvar, int value)
1192 {
1193 return ((*staticvar) = (((*staticvar) * 31) + value) >> 5);
1194 //NOTE: i benchmarked it against this and above was still faster:
1195 //((((*staticvar) << 5)-(*staticvar)) + value) >> 5);
1196 }
1197
1198 //=========================================
BB_PowerLaw(int randomnumber,int rand_max,int max_out)1199 inline int BB_PowerLaw (int randomnumber, int rand_max, int max_out)
1200 {
1201 float upper = .1;
1202 float lower = .01; //varying this between .999 and .01 is interesting
1203 float r = randomnumber / (float) rand_max;
1204 //return the rare stuff:
1205 if (upper > r && lower < r)
1206 {
1207 return (int) (lower * max_out / r);
1208 }
1209 //discard the common and more-rare stuff:
1210 return 0;
1211 }
1212
1213 //END PSEUDORANDOM NUMBER GENERATOR SECTION
1214 //################################################
1215
1216 //--------------------------------
1217 //20100522
1218 //called second, before BB_Water()
1219 //if droparray == null, it gets allotted and returned.
1220 //droparray is the single drop array that all drops use
1221 //if BB_Voice[voice].Drop == null it gets allotted;
1222 //
BB_WaterVoiceInit(int voice)1223 void BB_WaterVoiceInit (int voice)
1224 {
1225 if (NULL == BB_Voice[voice].Drop)
1226 {
1227 BB_Voice[voice].PCM_samples_size =
1228 (int) (BB_Voice[voice].Entry[0].beatfreq_start_HALF * 2);
1229 if (1 > BB_Voice[voice].PCM_samples_size)
1230 BB_Voice[voice].PCM_samples_size = 2; //default drops is 2
1231 if (100 < BB_Voice[voice].PCM_samples_size)
1232 BB_Voice[voice].PCM_samples_size = 100;
1233 BB_Voice[voice].Drop =
1234 (BB_Waterdrop *) calloc (BB_Voice[voice].PCM_samples_size,
1235 sizeof (BB_Waterdrop));
1236 int i;
1237 for (i = 0; i < BB_Voice[voice].PCM_samples_size; i++)
1238 {
1239 BB_Voice[voice].Drop[i].count = 0;
1240 BB_Voice[voice].Drop[i].decrement = 1;
1241 BB_Voice[voice].Drop[i].stereoMix = 0.5f;
1242 }
1243 }
1244 }
1245
1246 // =========================================
1247 // 20110616
1248 //called first, before BB_WaterVoiceInit()
1249 //creates an array with a single drop of sound
1250 //and returns it
BB_WaterInit(int arraylen,float pitch)1251 short *BB_WaterInit (int arraylen, float pitch)
1252 {
1253 short *array;
1254 array = (short *) calloc (arraylen, sizeof (short));
1255
1256 double p = 0;
1257 double q = 1.0 / pitch;
1258 double r = 0;
1259 double s = 0x7fff / (double) arraylen;
1260 int i;
1261 for (i = 0; i < arraylen; i++)
1262 {
1263 array[i] = (short) (r * sin (p * M_PI * 2.));
1264 p += q;
1265 r += s;
1266 }
1267 return array;
1268 }
1269
1270 //===============================
1271 //the big one of the water family.
1272 //Waterdrops: two parameters are adjustable:
1273 //1) Drop count, set only once, taken from very first
1274 //beatfreq_start_HALF multiplied by 2
1275 //2)Random Threshold, continuously varying as from
1276 //basefreq_start
1277 //Sort of ugly, but i had to
1278 //make cur_beatfreq_phasesamplecount == left channel result and
1279 //cur_beatfreq_phasesamplecount_start == right channel result.
BB_Water(int voice,short * array,int arraylen,float Lowcut)1280 void BB_Water (int voice, short *array, int arraylen, float Lowcut)
1281 {
1282 if (NULL == BB_Voice[voice].Drop)
1283 return;
1284
1285 const int Window = 126;
1286 float dropthresh = BB_Voice[voice].cur_basefreq;
1287
1288 // make water:
1289 int p,
1290 mixL = 0,
1291 mixR = 0;
1292 for (p = 0; p < BB_Voice[voice].PCM_samples_size; p++)
1293 {
1294 if (0 <= BB_Voice[voice].Drop[p].count)
1295 {
1296 if (TRUE == BB_Voice[voice].mono)
1297 {
1298 mixL += array[(int) BB_Voice[voice].Drop[p].count];
1299 mixR += array[(int) BB_Voice[voice].Drop[p].count];
1300 }
1301 else
1302 {
1303 mixL +=
1304 (int) (array[(int) BB_Voice[voice].Drop[p].count] *
1305 BB_Voice[voice].Drop[p].stereoMix);
1306 mixR +=
1307 (int) (array[(int) BB_Voice[voice].Drop[p].count] *
1308 (1.0f - BB_Voice[voice].Drop[p].stereoMix));
1309 }
1310 BB_Voice[voice].Drop[p].count -= BB_Voice[voice].Drop[p].decrement;
1311 //} else if (0 == (int) ((Math.random() * Rarity))) {
1312 }
1313 // else if (0 == (rand () >> 20)) //shortcut to default
1314 else if (dropthresh > (rand () / (float) RAND_MAX))
1315 {
1316 // load up a drop:
1317 BB_Voice[voice].Drop[p].count = arraylen - 1;
1318 // give it a random pitch:
1319 BB_Voice[voice].Drop[p].decrement =
1320 (float) (((rand () / (double) RAND_MAX) * Window) + Lowcut);
1321 //place it somewhere in the stereo mix:
1322 BB_Voice[voice].Drop[p].stereoMix = rand () / (float) RAND_MAX;
1323 }
1324 }
1325
1326 // do just a touch of lo-pass filtering on it and return in java friendly way:
1327 BB_Voice[voice].cur_beatfreq_phasesamplecount =
1328 BB_LoPass (&(BB_Voice[voice].noiseL), mixL);
1329 BB_Voice[voice].cur_beatfreq_phasesamplecount_start =
1330 BB_LoPass (&(BB_Voice[voice].noiseR), mixR);
1331 }
1332