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