1 //
2 //	SBaGen - Sequenced Binaural Beat Generator
3 //
4 //	(c) 1999-2011 Jim Peters <jim@uazu.net>.  All Rights Reserved.
5 //	For latest version see http://sbagen.sf.net/ or
6 //	http://uazu.net/sbagen/.  Released under the GNU GPL version 2.
7 //	Use at your own risk.
8 //
9 //	" This program is free software; you can redistribute it and/or modify
10 //	  it under the terms of the GNU General Public License as published by
11 //	  the Free Software Foundation, version 2.
12 //
13 //	  This program is distributed in the hope that it will be useful,
14 //	  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //	  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //	  GNU General Public License for more details. "
17 //
18 //	See the file COPYING for details of this license.
19 //
20 //	- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
21 //
22 //	Some code fragments in the Win32 audio handling are based on
23 //	code from PLIB (c) 2001 by Steve Baker, originally released
24 //	under the LGPL (slDSP.cxx and sl.h).  For the original source,
25 //	see the PLIB project: http://plib.sf.net
26 //
27 //	The code for the Mac audio output was based on code from the
28 //	FINK project's patches to ESounD, by Shawn Hsiao and Masanori
29 //	Sekino.  See: http://fink.sf.net
30 
31 #define VERSION "1.4.5"
32 
33 // This should be built with one of the following target macros
34 // defined, which selects options for that platform, or else with some
35 // of the individual named flags #defined as listed later.
36 //
37 //  T_LINUX	To build the LINUX version with /dev/dsp support
38 //  T_MINGW	To build for Windows using MinGW and Win32 calls
39 //  T_MSVC	To build for Windows using MSVC and Win32 calls
40 //  T_MACOSX	To build for MacOSX using CoreAudio
41 //  T_POSIX	To build for simple file output on any Posix-compliant OS
42 //
43 // Ogg and MP3 support is handled separately from the T_* macros.
44 
45 // Define OSS_AUDIO to use /dev/dsp for audio output
46 // Define WIN_AUDIO to use Win32 calls
47 // Define MAC_AUDIO to use Mac CoreAudio calls
48 // Define NO_AUDIO if no audio output device is usable
49 // Define UNIX_TIME to use UNIX calls for getting time
50 // Define WIN_TIME to use Win32 calls for getting time
51 // Define ANSI_TTY to use ANSI sequences to clear/redraw lines
52 // Define UNIX_MISC to use UNIX calls for various miscellaneous things
53 // Define WIN_MISC to use Windows calls for various miscellaneous things
54 // Define EXIT_KEY to require the user to hit RETURN before exiting after error
55 
56 // Define OGG_DECODE to include OGG support code
57 // Define MP3_DECODE to include MP3 support code
58 
59 #ifdef T_LINUX
60 #define OSS_AUDIO
61 #define UNIX_TIME
62 #define UNIX_MISC
63 #define ANSI_TTY
64 #endif
65 
66 #ifdef T_MINGW
67 #define WIN_AUDIO
68 #define WIN_TIME
69 #define WIN_MISC
70 #define EXIT_KEY
71 #endif
72 
73 #ifdef T_MSVC
74 #define WIN_AUDIO
75 #define WIN_TIME
76 #define WIN_MISC
77 #define EXIT_KEY
78 #endif
79 
80 #ifdef T_MACOSX
81 #define MAC_AUDIO
82 #define UNIX_TIME
83 #define UNIX_MISC
84 #define ANSI_TTY
85 #endif
86 
87 #ifdef T_POSIX
88 #define NO_AUDIO
89 #define UNIX_TIME
90 #define UNIX_MISC
91 #endif
92 
93 // Make sure NO_AUDIO is set if necessary
94 #ifndef OSS_AUDIO
95 #ifndef MAC_AUDIO
96 #ifndef WIN_AUDIO
97 #define NO_AUDIO
98 #endif
99 #endif
100 #endif
101 
102 // Make sure one of the _TIME macros is set
103 #ifndef UNIX_TIME
104 #ifndef WIN_TIME
105 #error UNIX_TIME or WIN_TIME not defined.  Maybe you did not define one of T_LINUX/T_MINGW/T_MACOSX/etc ?
106 #endif
107 #endif
108 
109 // Make sure one of the _MISC macros is set
110 #ifndef UNIX_MISC
111 #ifndef WIN_MISC
112 #error UNIX_MISC or WIN_MISC not defined.  Maybe you did not define one of T_LINUX/T_MINGW/T_MACOSX/etc ?
113 #endif
114 #endif
115 
116 #include <stdio.h>
117 #include <math.h>
118 #include <stdarg.h>
119 #include <stdlib.h>
120 #include <string.h>
121 #include <errno.h>
122 #include <ctype.h>
123 #include <sys/types.h>
124 #include <sys/stat.h>
125 #include <fcntl.h>
126 #include <time.h>
127 
128 #ifdef T_MSVC
129  #include <io.h>
130  #define write _write
131  #define vsnprintf _vsnprintf
132  typedef long long S64;		// I have no idea if this is correct for MSVC
133 #else
134  #include <unistd.h>
135  #include <sys/time.h>
136  typedef long long S64;
137 #endif
138 
139 #ifdef T_MINGW
140  #define vsnprintf _vsnprintf
141 #endif
142 
143 #ifdef OSS_AUDIO
144  #include <sys/soundcard.h>
145  //WAS: #include <sys/soundcard.h>
146 #endif
147 #ifdef WIN_AUDIO
148  #include <windows.h>
149  #include <mmsystem.h>
150 #endif
151 #ifdef MAC_AUDIO
152  #include <Carbon.h>
153  #include <CoreAudio/CoreAudio.h>
154 #endif
155 #ifdef UNIX_TIME
156  #include <sys/ioctl.h>
157  #include <sys/times.h>
158 #endif
159 #ifdef UNIX_MISC
160  #include <pthread.h>
161 #endif
162 
163 typedef struct Channel Channel;
164 typedef struct Voice Voice;
165 typedef struct Period Period;
166 typedef struct NameDef NameDef;
167 typedef struct BlockDef BlockDef;
168 typedef unsigned char uchar;
169 
170 int inbuf_loop(void *vp) ;
171 int inbuf_read(int *dst, int dlen) ;
172 void inbuf_start(int(*rout)(int*,int), int len) ;
173 inline int t_per24(int t0, int t1) ;
174 inline int t_per0(int t0, int t1) ;
175 inline int t_mid(int t0, int t1) ;
176 int main(int argc, char **argv) ;
177 void status(char *) ;
178 void dispCurrPer( FILE* ) ;
179 void init_sin_table() ;
180 void debug(char *fmt, ...) ;
181 void warn(char *fmt, ...) ;
182 void * Alloc(size_t len) ;
183 char * StrDup(char *str) ;
184 static inline int calcNow() ;
185 void loop() ;
186 void outChunk() ;
187 void corrVal(int ) ;
188 int readLine() ;
189 char * getWord() ;
190 void badSeq() ;
191 void readSeqImm(int ac, char **av) ;
192 void readSeq(int ac, char **av) ;
193 void readPreProg(int ac, char **av) ;
194 void correctPeriods();
195 void setup_device(void) ;
196 void readNameDef();
197 void readTimeLine();
198 int voicesEq(Voice *, Voice *);
199 void error(char *fmt, ...) ;
200 int sprintTime(char *, int);
201 int sprintVoice(char *, Voice *, Voice *);
202 int readTime(char *, int *);
203 void writeWAV();
204 void writeOut(char *, int);
205 void sinc_interpolate(double *, int, int *);
206 inline int userTime();
207 void find_wav_data_start(FILE *in);
208 int raw_mix_in(int *dst, int dlen);
209 int scanOptions(int *acp, char ***avp);
210 void handleOptions(char *p);
211 void setupOptC(char *spec) ;
212 extern int out_rate, out_rate_def;
213 void create_drop(int ac, char **av);
214 void create_slide(int ac, char **av);
215 
216 #define ALLOC_ARR(cnt, type) ((type*)Alloc((cnt) * sizeof(type)))
217 #define uint unsigned int
218 
219 #ifdef OGG_DECODE
220 #include "oggdec.c"
221 #endif
222 #ifdef MP3_DECODE
223 #include "mp3dec.c"
224 #endif
225 
226 #ifdef WIN_AUDIO
227 void CALLBACK win32_audio_callback(HWAVEOUT, UINT, DWORD, DWORD, DWORD);
228 #endif
229 #ifdef MAC_AUDIO
230 OSStatus mac_callback(AudioDeviceID, const AudioTimeStamp *, const AudioBufferList *,
231 		      const AudioTimeStamp *, AudioBufferList *, const AudioTimeStamp *,
232 		      void *inClientData);
233 #endif
234 
235 #define NL "\n"
236 
237 void
help()238 help() {
239    printf("SBaGen - Sequenced Binaural Beat Generator, version " VERSION
240 	  NL "Copyright (c) 1999-2011 Jim Peters, http://uazu.net/, all rights "
241 	  NL "  reserved, released under the GNU GPL v2.  See file COPYING."
242 	  NL
243 	  NL "Usage: sbagen [options] seq-file ..."
244 	  NL "       sbagen [options] -i tone-specs ..."
245 	  NL "       sbagen [options] -p pre-programmed-sequence-specs ..."
246 	  NL
247 	  NL "Options:  -h        Display this help-text"
248 	  NL "          -Q        Quiet - don't display running status"
249 	  NL "          -D        Display the full interpreted sequence instead of playing it"
250 	  NL "          -i        Immediate.  Take the remainder of the command line to be"
251 	  NL "                     tone-specifications, and play them continuously"
252 	  NL "          -p        Pre-programmed sequence.  Take the remainder of the command"
253 	  NL "                     line to be a type and arguments, e.g. \"drop 00ds+\""
254 	  NL "          -q mult   Quick.  Run through quickly (real time x 'mult') from the"
255 	  NL "                     start time, rather than wait for real time to pass"
256 	  NL
257 	  NL "          -r rate   Select the output rate (default is 44100 Hz, or from -m)"
258 #ifndef MAC_AUDIO
259 	  NL "          -b bits   Select the number bits for output (8 or 16, default 16)"
260 #endif
261 	  NL "          -L time   Select the length of time (hh:mm or hh:mm:ss) to output"
262 	  NL "                     for.  Default is to output forever."
263 	  NL "          -S        Output from the first tone-set in the sequence (Start),"
264 	  NL "                     instead of working in real-time.  Equivalent to '-q 1'."
265 	  NL "          -E        Output until the last tone-set in the sequence (End),"
266 	  NL "                     instead of outputting forever."
267 	  NL "          -T time   Start at the given clock-time (hh:mm)"
268 	  NL
269 	  NL "          -o file   Output raw data to the given file instead of /dev/dsp"
270 	  NL "          -O        Output raw data to the standard output"
271 	  NL "          -W        Output a WAV-format file instead of raw data"
272 	  NL "          -m file   Read audio data from the given file and mix it with the"
273 	  NL "                      generated binaural beats; may be "
274 #ifdef OGG_DECODE
275 	  "ogg/"
276 #endif
277 #ifdef MP3_DECODE
278 	  "mp3/"
279 #endif
280 	  "wav/raw format"
281 	  NL "          -M        Read raw audio data from the standard input and mix it"
282 	  NL "                      with the generated binaural beats (raw only)"
283 	  NL
284 	  NL "          -R rate   Select rate in Hz that frequency changes are recalculated"
285 	  NL "                     (for file/pipe output only, default is 10Hz)"
286 	  NL "          -F fms    Fade in/out time in ms (default 60000ms, or 1min)"
287 #ifdef OSS_AUDIO
288 	  NL "          -d dev    Select a different output device instead of /dev/dsp"
289 #endif
290 	  NL "          -c spec   Compensate for low-frequency headphone roll-off; see docs"
291 	  NL
292 	  );
293    exit(0);
294 }
295 
296 void
usage()297 usage() {
298   error("SBaGen - Sequenced Binaural Beat Generator, version " VERSION
299 	NL "Copyright (c) 1999-2011 Jim Peters, http://uazu.net/, all rights "
300 	NL "  reserved, released under the GNU GPL v2.  See file COPYING."
301 	NL
302 	NL "Usage: sbagen [options] seq-file ..."
303 	NL "       sbagen [options] -i tone-specs ..."
304 	NL "       sbagen [options] -p pre-programmed-sequence-specs ..."
305 	NL
306 	NL "For full usage help, type 'sbagen -h'.  For latest version see"
307 	NL "http://uazu.net/sbagen/ or http://sbagen.sf.net/"
308 #ifdef EXIT_KEY
309 	NL
310 	NL "Windows users please note that this utility is designed to be run as the"
311 	NL "associated application for SBG files.  This should have been set up for you by"
312 	NL "the installer.  You can run all the SBG files directly from the desktop by"
313 	NL "double-clicking on them, and edit them using NotePad from the right-click menu."
314 	NL "Alternatively, SBaGen may be run from the MS-DOS prompt (CMD on WinXP), or from"
315 	NL "BAT files.  SBaGen is powerful software -- it is worth the effort of figuring"
316 	NL "all this out.  See SBAGEN.TXT for the full documentation."
317 	NL
318 	NL "Editing the SBG files gives you access to the full tweakable power of SBaGen, "
319 	NL "but if you want a simple GUI interface to the most basic features, you could "
320 	NL "look at a user-contributed tool called SBaGUI:"
321 	NL
322 	NL "  http://sbagen.opensrc.org/wiki.php?page=SBaGUI"
323 #endif
324 	NL);
325 }
326 
327 
328 #define DEBUG_CHK_UTIME 0	// Check how much user time is being consumed
329 #define DEBUG_DUMP_WAVES 0	// Dump out wave tables (to plot with gnuplot)
330 #define DEBUG_DUMP_AMP 0	// Dump output amplitude to stdout per chunk
331 #define N_CH 16			// Number of channels
332 
333 struct Voice {
334   int typ;			// Voice type: 0 off, 1 binaural, 2 pink noise, 3 bell, 4 spin,
335    				//   5 mix, 6 mixspin, 7 mixbeat, -1 to -100 wave00 to wave99
336   double amp;			// Amplitude level (0-4096 for 0-100%)
337   double carr;			// Carrier freq (for binaural/bell), width (for spin)
338   double res;			// Resonance freq (-ve or +ve) (for binaural/spin)
339 };
340 
341 struct Channel {
342   Voice v;			// Current voice setting (updated from current period)
343   int typ;			// Current type: 0 off, 1 binaural, 2 pink noise, 3 bell, 4 spin,
344    				//   5 mix, 6 mixspin, 7 mixbeat, -1 to -100 wave00 to wave99
345   int amp, amp2;		// Current state, according to current type
346   int inc1, off1;		//  ::  (for binaural tones, offset + increment into sine
347   int inc2, off2;		//  ::   table * 65536)
348 };
349 
350 struct Period {
351   Period *nxt, *prv;		// Next/prev in chain
352   int tim;			// Start time (end time is ->nxt->tim)
353   Voice v0[N_CH], v1[N_CH];	// Start and end voices
354   int fi, fo;			// Temporary: Fade-in, fade-out modes
355 };
356 
357 struct NameDef {
358   NameDef *nxt;
359   char *name;			// Name of definition
360   BlockDef *blk;		// Non-zero for block definition
361   Voice vv[N_CH];		// Voice-set for it (unless a block definition)
362 };
363 
364 struct BlockDef {
365   BlockDef *nxt;		// Next in chain
366   char *lin;			// StrDup'd line
367 };
368 
369 #define ST_AMP 0x7FFFF		// Amplitude of wave in sine-table
370 #define NS_ADJ 12		// Noise is generated internally with amplitude ST_AMP<<NS_ADJ
371 #define NS_DITHER 16		// How many bits right to shift the noise for dithering
372 #define NS_AMP (ST_AMP<<NS_ADJ)
373 #define ST_SIZ 16384		// Number of elements in sine-table (power of 2)
374 int *sin_table;
375 #define AMP_DA(pc) (40.96 * (pc))	// Display value (%age) to ->amp value
376 #define AMP_AD(amp) ((amp) / 40.96)	// Amplitude value to display %age
377 int *waves[100];		// Pointers are either 0 or point to a sin_table[]-style array of int
378 
379 Channel chan[N_CH];		// Current channel states
380 int now;			// Current time (milliseconds from midnight)
381 Period *per= 0;			// Current period
382 NameDef *nlist;			// Full list of name definitions
383 
384 int *tmp_buf;			// Temporary buffer for 20-bit mix values
385 short *out_buf;			// Output buffer
386 int out_bsiz;			// Output buffer size (bytes)
387 int out_blen;			// Output buffer length (samples) (1.0* or 0.5* out_bsiz)
388 int out_bps;			// Output bytes per sample (2 or 4)
389 int out_buf_ms;			// Time to output a buffer-ful in ms
390 int out_buf_lo;			// Time to output a buffer-ful, fine-tuning in ms/0x10000
391 int out_fd;			// Output file descriptor
392 int out_rate= 44100;		// Sample rate
393 int out_rate_def= 1;		// Sample rate is default value, not set by user
394 int out_mode= 1;		// Output mode: 0 unsigned char[2], 1 short[2], 2 swapped short[2]
395 int out_prate= 10;		// Rate of parameter change (for file and pipe output only)
396 int fade_int= 60000;		// Fade interval (ms)
397 FILE *in;			// Input sequence file
398 int in_lin;			// Current input line
399 char buf[4096];			// Buffer for current line
400 char buf_copy[4096];		// Used to keep unmodified copy of line
401 char *lin;			// Input line (uses buf[])
402 char *lin_copy;			// Copy of input line
403 double spin_carr_max;		// Maximum 'carrier' value for spin (really max width in us)
404 
405 #define NS_BIT 10
406 int ns_tbl[1<<NS_BIT];
407 int ns_off= 0;
408 
409 int fast_tim0= -1;		// First time mentioned in the sequence file (for -q and -S option)
410 int fast_tim1= -1;		// Last time mentioned in the sequence file (for -E option)
411 int fast_mult= 0;		// 0 to sync to clock (adjusting as necessary), or else sync to
412 				//  output rate, with the multiplier indicated
413 S64 byte_count= -1;		// Number of bytes left to output, or -1 if unlimited
414 int tty_erase;			// Chars to erase from current line (for ESC[K emulation)
415 
416 int opt_D;
417 int opt_M;
418 int opt_Q;
419 int opt_S;
420 int opt_E;
421 int opt_W;
422 int opt_O;
423 int opt_L= -1;			// Length in ms, or -1
424 int opt_T= -1;			// Start time in ms, or -1
425 char *opt_o;			// File name to output to, or 0
426 char *opt_m;			// File name to read mix data from, or 0
427 char *opt_d= "/dev/dsp";	// Output device
428 
429 FILE *mix_in;			// Input stream for mix sound data, or 0
430 int mix_cnt;			// Version number from mix filename (#<digits>), or -1
431 int bigendian;			// Is this platform Big-endian?
432 int mix_flag= 0;		// Has 'mix/*' been used in the sequence?
433 
434 int opt_c;			// Number of -c option points provided (max 16)
435 struct AmpAdj {
436    double freq, adj;
437 } ampadj[16];			// List of maximum 16 (freq,adj) pairs, freq-increasing order
438 
439 char *pdir;			// Program directory (used as second place to look for -m files)
440 
441 #ifdef WIN_AUDIO
442  #define BUFFER_COUNT 8
443  #define BUFFER_SIZE 8192*4
444  HWAVEOUT aud_handle;
445  WAVEHDR *aud_head[BUFFER_COUNT];
446  int aud_current;		// Current header
447  int aud_cnt;			// Number of headers in use
448 #endif
449 
450 #ifdef MAC_AUDIO
451  #define BUFFER_COUNT 8
452  #define BUFFER_SIZE 4096*4
453  char aud_buf[BUFFER_COUNT][BUFFER_SIZE];
454  int aud_rd;	// Next buffer to read out of list (to send to device)
455  int aud_wr;	// Next buffer to write.  aud_rd==aud_wr means empty buffer list
456  static AudioDeviceID aud_dev;
457 #endif
458 
459 //
460 //	Delay for a short period of time (in ms)
461 //
462 
463 #ifdef UNIX_MISC
464 void
delay(int ms)465 delay(int ms) {
466    struct timespec ts;
467    ts.tv_sec= ms / 1000;
468    ts.tv_nsec= (ms % 1000) * 1000000;
469    nanosleep(&ts, 0);
470 }
471 #endif
472 #ifdef WIN_MISC
473 void
delay(int ms)474 delay(int ms) {
475    Sleep(ms);
476 }
477 #endif
478 
479 
480 //
481 //	WAV/OGG/MP3 input data buffering
482 //
483 
484 int *inbuf;		// Buffer for input data (as 20-bit samples)
485 int ib_len;		// Length of input buffer (in ints)
486 volatile int ib_rd;	// Read-offset in inbuf
487 volatile int ib_wr;	// Write-offset in inbuf
488 volatile int ib_eof;	// End of file flag
489 int ib_cycle= 100;	// Time in ms for a complete loop through the buffer
490 int (*ib_read)(int*,int);  // Routine to refill buffer
491 
492 int
inbuf_loop(void * vp)493 inbuf_loop(void *vp) {
494    int now= -1;
495    int waited= 0;	// Used to bail out if the main thread dies for some reason
496    int a;
497 
498    while (1) {
499       int rv;
500       int rd= ib_rd;
501       int wr= ib_wr;
502       int cnt= (rd-1-wr) & (ib_len-1);
503       if (cnt > ib_len-wr) cnt= ib_len-wr;
504       if (cnt > ib_len/8) cnt= ib_len/8;
505 
506       // Choose to only work in ib_len/8 units, although this is not
507       // 100% necessary
508       if (cnt < ib_len/8) {
509 	 // Wait a little while for the buffer to empty (minimum 1ms)
510 	 if (waited > 10000 + ib_cycle)
511 	    error("Mix stream halted for more than 10 seconds; aborting");
512 	 delay(a= 1+ib_cycle/4);
513 	 waited += a;
514 	 continue;
515       }
516       waited= 0;
517 
518       rv= ib_read(inbuf+wr, cnt);
519       //debug("ib_read %d-%d (%d) -> %d", wr, wr+cnt-1, cnt, rv);
520       if (rv != cnt) {
521 	 ib_eof= 1;
522 	 return 0;
523       }
524 
525       ib_wr= (wr + rv) & (ib_len-1);
526 
527       // Whenever we roll over, recalculate 'ib_cycle'
528       if (ib_wr < wr) {
529 	 int prev= now;
530 	 now= calcNow();
531 	 if (prev >= 0 && now > prev)
532 	    ib_cycle= now - prev;
533 	 //debug("Input buffer cycle duration is now %dms", ib_cycle);
534       }
535    }
536    return 0;
537 }
538 
539 //
540 //	Read a chunk of int data from the input buffer.  This will
541 //	always return enough data unless we have hit the end of the
542 //	file, in which case it returns a lower number or 0.  If not
543 //	enough data has been read by the input thread, then this
544 //	thread pauses until data is ready -- but this should hopefully
545 //	never happen.
546 //
547 
548 int
inbuf_read(int * dst,int dlen)549 inbuf_read(int *dst, int dlen) {
550    int rv= 0;
551    int waited= 0;	// As a precaution, bail out if other thread hangs for some reason
552    int a;
553 
554    while (dlen > 0) {
555       int rd= ib_rd;
556       int wr= ib_wr;
557       int avail= (wr-rd) & (ib_len-1);
558       int toend= ib_len-rd;
559       if (avail > toend) avail= toend;
560       if (avail > dlen) avail= dlen;
561 
562       if (avail == 0) {
563 	 if (ib_eof) return rv;
564 
565 	 // Necessary to wait for incoming mix data.  This should
566 	 // never happen in normal running, though, unless we are
567 	 // outputting to a file
568 	 if (waited > 10000)
569 	    error("Mix stream problem; waited more than 10 seconds for data; aborting");
570 	 //debug("Waiting for input thread (%d)", ib_eof);
571 	 delay(a= ib_cycle/4 > 100 ? 100 : 1+ib_cycle/4);
572 	 waited += a;
573 	 continue;
574       }
575       waited= 0;
576 
577       memcpy(dst, inbuf+rd, avail * sizeof(int));
578       dst += avail;
579       dlen -= avail;
580       rv += avail;
581       ib_rd= (rd + avail) & (ib_len-1);
582    }
583    return rv;
584 }
585 
586 //
587 //	Start off the thread that fills the buffer
588 //
589 
590 void
inbuf_start(int (* rout)(int *,int),int len)591 inbuf_start(int(*rout)(int*,int), int len) {
592    if (0 != (len & (len-1)))
593       error("inbuf_start() called with length not a power of two");
594 
595    ib_read= rout;
596    ib_len= len;
597    inbuf= ALLOC_ARR(ib_len, int);
598    ib_rd= 0;
599    ib_wr= 0;
600    ib_eof= 0;
601    if (!opt_Q) warn("Initialising %d-sample buffer for mix stream", ib_len/2);
602 
603    // Preload 75% of the buffer -- or at least attempt to do so;
604    // errors/eof/etc will be picked up in the inbuf_loop() routine
605    ib_wr= ib_read(inbuf, ib_len*3/4);
606 
607    // Start the thread off
608 #ifdef UNIX_MISC
609    {
610       pthread_t thread;
611       if (0 != pthread_create(&thread, NULL, (void*)&inbuf_loop, NULL))
612 	 error("Failed to start input buffering thread");
613    }
614 #endif
615 #ifdef WIN_MISC
616    {
617       DWORD tmp;
618       if (0 == CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&inbuf_loop, 0, 0, &tmp))
619 	 error("Failed to start input buffering thread");
620    }
621 #endif
622 }
623 
624 
625 //
626 //	Time-keeping functions
627 //
628 
629 #define H24 (86400000)			// 24 hours
630 #define H12 (43200000)			// 12 hours
631 
t_per24(int t0,int t1)632 inline int t_per24(int t0, int t1) {		// Length of period starting at t0, ending at t1.
633   int td= t1 - t0;				// NB for t0==t1 this gives 24 hours, *NOT 0*
634   return td > 0 ? td : td + H24;
635 }
t_per0(int t0,int t1)636 inline int t_per0(int t0, int t1) {		// Length of period starting at t0, ending at t1.
637   int td= t1 - t0;				// NB for t0==t1 this gives 0 hours
638   return td >= 0 ? td : td + H24;
639 }
t_mid(int t0,int t1)640 inline int t_mid(int t0, int t1) {		// Midpoint of period from t0 to t1
641   return ((t1 < t0) ? (H24 + t0 + t1) / 2 : (t0 + t1) / 2) % H24;
642 }
643 
644 //
645 //	M A I N
646 //
647 
648 int
main(int argc,char ** argv)649 main(int argc, char **argv) {
650    short test= 0x1100;
651    int rv;
652    char *p;
653 
654    pdir= StrDup(argv[0]);
655    p= strchr(pdir, 0);
656    while (p > pdir && p[-1] != '/' && p[-1] != '\\') *--p= 0;
657 
658    argc--; argv++;
659    init_sin_table();
660    bigendian= ((char*)&test)[0] != 0;
661 
662    // Process all the options
663    rv= scanOptions(&argc, &argv);
664 
665    if (argc < 1) usage();
666 
667    if (rv == 'i') {
668       // Immediate mode
669       readSeqImm(argc, argv);
670    } else if (rv == 'p') {
671       // Pre-programmed sequence
672       readPreProg(argc, argv);
673    } else {
674       // Sequenced mode -- sequence may include options, so options
675       // are not settled until below this point
676       if (argc < 1) usage();
677       readSeq(argc, argv);
678    }
679 
680    if (opt_W && !opt_o && !opt_O)
681       error("Use -o or -O with the -W option");
682    if (opt_W && opt_L < 0 && !opt_E) {
683       fprintf(stderr, "*** The length has not been specified for the -W option; assuming 1 hour ***\n");
684       fprintf(stderr, "(Use -L or -E with the -W option to control the length of the WAV file)\n\n");
685       opt_L= 60*60*1000;
686    }
687 
688    mix_in= 0;
689    if (opt_M || opt_m) {
690       char *p;
691       char tmp[4];
692       int raw= 1;
693       if (opt_M) {
694 	 mix_in= stdin;
695 	 tmp[0]= 0;
696       }
697       if (opt_m) {
698 	 // Pick up #<digits> on end of filename
699 	 p= strchr(opt_m, 0);
700 	 mix_cnt= -1;
701 	 if (p > opt_m && isdigit(p[-1])) {
702 	    mix_cnt= 0;
703 	    while (p > opt_m && isdigit(p[-1]))
704 	       mix_cnt= mix_cnt * 10 + *--p - '0';
705 	    if (p > opt_m && p[-1] == '#')
706 	       *--p= 0;
707 	    else {
708 	       p= strchr(opt_m, 0);
709 	       mix_cnt= -1;
710 	    }
711 	 }
712 	 // p points to end of filename (NUL)
713 
714 	 // Open file
715 	 mix_in= fopen(opt_m, "rb");
716 	 if (!mix_in && opt_m[0] != '/') {
717 	    int len= strlen(opt_m) + strlen(pdir) + 1;
718 	    char *tmp= ALLOC_ARR(len, char);
719 	    strcpy(tmp, pdir);
720 	    strcat(tmp, opt_m);
721 	    mix_in= fopen(tmp, "rb");
722 	    free(tmp);
723 	 }
724 	 if (!mix_in)
725 	    error("Can't open -m option mix input file: %s", opt_m);
726 
727 	 // Pick up extension
728 	 if (p-opt_m >= 4 && p[-4] == '.') {
729 	    tmp[0]= tolower(p[-3]);
730 	    tmp[1]= tolower(p[-2]);
731 	    tmp[2]= tolower(p[-1]);
732 	    tmp[3]= 0;
733 	 }
734       }
735       if (0 == strcmp(tmp, "wav"))	// Skip header on WAV files
736 	 find_wav_data_start(mix_in);
737       if (0 == strcmp(tmp, "ogg")) {
738 #ifdef OGG_DECODE
739 	 ogg_init(); raw= 0;
740 #else
741 	 error("Sorry: Ogg support wasn't compiled into this executable");
742 #endif
743       }
744       if (0 == strcmp(tmp, "mp3")) {
745 #ifdef MP3_DECODE
746 	 mp3_init(); raw= 0;
747 #else
748 	 error("Sorry: MP3 support wasn't compiled into this executable");
749 #endif
750       }
751       // If this is a raw/wav data stream, setup a 256*1024-int
752       // buffer (3s@44.1kHz)
753       if (raw) inbuf_start(raw_mix_in, 256*1024);
754    }
755 
756    loop();
757    return 0;
758 }
759 
760 //
761 //	Scan options.  Returns a flag indicating what is expected to
762 //	interpret the rest of the arguments: 0 normal, 'i' immediate
763 //	(-i option), 'p' -p option.
764 //
765 
766 int
scanOptions(int * acp,char *** avp)767 scanOptions(int *acp, char ***avp) {
768    int argc= *acp;
769    char **argv= *avp;
770    int val;
771    char dmy;
772    int rv= 0;
773 
774    // Scan options
775    while (argc > 0 && argv[0][0] == '-' && argv[0][1]) {
776       char opt, *p= 1 + *argv++; argc--;
777       while ((opt= *p++)) {
778 	 // Check options that are available on both
779 	 switch (opt) {
780 	  case 'Q': opt_Q= 1; break;
781 	  case 'E': opt_E= 1; break;
782 	  case 'm':
783 	     if (argc-- < 1) error("-m option expects filename");
784 	     // Earliest takes precedence, so command-line overrides sequence file
785 	     if (!opt_m) opt_m= *argv++;
786 	     break;
787 	  case 'S': opt_S= 1;
788 	     if (!fast_mult) fast_mult= 1; 		// Don't try to sync with real time
789 	     break;
790 	  case 'L':
791 	     if (argc-- < 1 || 0 == (val= readTime(*argv, &opt_L)) ||
792 		 1 == sscanf(*argv++ + val, " %c", &dmy))
793 		error("-L expects hh:mm or hh:mm:ss time");
794 	     break;
795 	  case 'T':
796 	     if (argc-- < 1 || 0 == (val= readTime(*argv, &opt_T)) ||
797 		 1 == sscanf(*argv++ + val, " %c", &dmy))
798 		error("-T expects hh:mm or hh:mm:ss time");
799 	     if (!fast_mult) fast_mult= 1;		// Don't try to sync with real time
800 	     break;
801 	  case 'F':
802 	     if (argc-- < 1 || 1 != sscanf(*argv++, "%d %c", &fade_int, &dmy))
803 		error("-F expects fade-time in ms");
804 	     break;
805 	  case 'c':
806 	     if (argc-- < 1) error("-c expects argument");
807 	     setupOptC(*argv++);
808 	     break;
809 	  case 'i': rv= 'i'; break;
810 	  case 'p': rv= 'p'; break;
811 	  case 'h': help(); break;
812 	  case 'D': opt_D= 1; break;
813 	  case 'M': opt_M= 1; break;
814 	  case 'O': opt_O= 1;
815 	     if (!fast_mult) fast_mult= 1; 		// Don't try to sync with real time
816 	     break;
817 	  case 'W': opt_W= 1;
818 	     if (!fast_mult) fast_mult= 1; 		// Don't try to sync with real time
819 	     break;
820 	  case 'q':
821 	     opt_S= 1;
822 	     if (argc-- < 1 || 1 != sscanf(*argv++, "%d %c", &fast_mult, &dmy))
823 		error("Expecting an integer after -q");
824 	     if (fast_mult < 1) fast_mult= 1;
825 	     break;
826 	  case 'r':
827 	     if (argc-- < 1 || 1 != sscanf(*argv++, "%d %c", &out_rate, &dmy))
828 		error("Expecting an integer after -r");
829 	     out_rate_def= 0;
830 	     break;
831 #ifndef MAC_AUDIO
832 	  case 'b':
833 	     if (argc-- < 1 ||
834 		 1 != sscanf(*argv++, "%d %c", &val, &dmy) ||
835 		 !(val == 8 || val == 16))
836 		error("Expecting -b 8 or -b 16");
837 	     out_mode= (val == 8) ? 0 : 1;
838 	     break;
839 #endif
840 	  case 'o':
841 	     if (argc-- < 1) error("Expecting filename after -o");
842 	     opt_o= *argv++;
843 	     if (!fast_mult) fast_mult= 1;		// Don't try to sync with real time
844 	     break;
845 #ifdef OSS_AUDIO
846 	  case 'd':
847 	     if (argc-- < 1) error("Expecting device filename after -d");
848 	     opt_d= *argv++;
849 	     break;
850 #endif
851 	  case 'R':
852 	     if (argc-- < 1 || 1 != sscanf(*argv++, "%d %c", &out_prate, &dmy))
853 		error("Expecting integer after -R");
854 	     break;
855 	  default:
856 	     error("Option -%c not known; run 'sbagen -h' for help", opt);
857 	 }
858       }
859    }
860 
861    *acp= argc;
862    *avp= argv;
863    return rv;
864 }
865 
866 //
867 //	Handle an option string, breaking it into an (argc/argv) list
868 //	for scanOptions.
869 //
870 
871 void
handleOptions(char * str0)872 handleOptions(char *str0) {
873    // Always StrDup() string and don't bother to free(), as normal
874    // argv[] strings stick around for the life of the program
875    char *str= StrDup(str0);
876    int const max_argc= 32;
877    char *argv[max_argc+1];
878    int argc= 0;
879 
880    while (*str) {
881       if (argc >= max_argc)
882 	 error("Too many options at line: %d\n  %s", in_lin, lin_copy);
883       argv[argc++]= str;
884       while (*str && !isspace(*str)) str++;
885       if (!*str) continue;
886       *str++= 0;	// NUL-term this word
887       while (isspace(*str)) str++;
888    }
889    argv[argc]= 0;	// Terminate argv list with a NULL
890 
891    // Process the options
892    {
893       char **av= argv;
894       int ac= argc;
895       int rv;
896 
897       rv= scanOptions(&ac, &av);
898 
899       if (rv == 'i') {
900 	 // Immediate mode
901 	 readSeqImm(ac, av);
902       } else if (rv == 'p') {
903 	 // Pre-programmed sequence
904 	 readPreProg(ac, av);
905       } else if (ac)
906 	 error("Trailing garbage after options at line: %d\n  %s", in_lin, lin_copy);
907    }
908 }
909 
910 //
911 //	Setup the ampadj[] array from the given -c spec-string
912 //
913 
914 void
setupOptC(char * spec)915 setupOptC(char *spec) {
916    char *p= spec, *q;
917    int a, b;
918 
919    while (1) {
920       while (isspace(*p) || *p == ',') p++;
921       if (!*p) break;
922 
923       if (opt_c >= sizeof(ampadj) / sizeof(ampadj[0]))
924 	 error("Too many -c option frequencies; maxmimum is %d",
925 	       sizeof(ampadj) / sizeof(ampadj[0]));
926 
927       ampadj[opt_c].freq= strtod(p, &q);
928       if (p == q) goto bad;
929       if (*q++ != '=') goto bad;
930       ampadj[opt_c].adj= strtod(q, &p);
931       if (p == q) goto bad;
932       opt_c++;
933    }
934 
935    // Sort the list
936    for (a= 0; a<opt_c; a++)
937       for (b= a+1; b<opt_c; b++)
938 	 if (ampadj[a].freq > ampadj[b].freq) {
939 	    double tmp;
940 	    tmp= ampadj[a].freq; ampadj[a].freq= ampadj[b].freq; ampadj[b].freq= tmp;
941 	    tmp= ampadj[a].adj; ampadj[a].adj= ampadj[b].adj; ampadj[b].adj= tmp;
942 	 }
943    return;
944 
945  bad:
946    error("Bad -c option spec; expecting <freq>=<amp>[,<freq>=<amp>]...:\n  %s", spec);
947 }
948 
949 
950 //
951 //	If this is a WAV file we've been given, skip forward to the
952 //	'data' section.  Don't bother checking any of the 'fmt '
953 //	stuff.  If they didn't give us a valid 16-bit stereo file at
954 //	the right rate, then tough!
955 //
956 
957 void
find_wav_data_start(FILE * in)958 find_wav_data_start(FILE *in) {
959    unsigned char buf[16];
960 
961    if (1 != fread(buf, 12, 1, in)) goto bad;
962    if (0 != memcmp(buf, "RIFF", 4)) goto bad;
963    if (0 != memcmp(buf+8, "WAVE", 4)) goto bad;
964 
965    while (1) {
966       int len;
967       if (1 != fread(buf, 8, 1, in)) goto bad;
968       if (0 == memcmp(buf, "data", 4)) return;		// We're in the right place!
969       len= buf[4] + (buf[5]<<8) + (buf[6]<<16) + (buf[7]<<24);
970       if (len & 1) len++;
971       if (out_rate_def && 0 == memcmp(buf, "fmt ", 4)) {
972 	 // Grab the sample rate to use as the default if available
973 	 if (1 != fread(buf, 8, 1, in)) goto bad;
974 	 len -= 8;
975 	 out_rate= buf[4] + (buf[5]<<8) + (buf[6]<<16) + (buf[7]<<24);
976 	 out_rate_def= 0;
977       }
978       if (0 != fseek(in, len, SEEK_CUR)) goto bad;
979    }
980 
981  bad:
982    warn("WARNING: Not a valid WAV file, treating as RAW");
983    rewind(in);
984 }
985 
986 //
987 //	Input raw audio data from the 'mix_in' stream, and convert to
988 //	32-bit values (max 'dlen')
989 //
990 
991 int
raw_mix_in(int * dst,int dlen)992 raw_mix_in(int *dst, int dlen) {
993    short *tmp= (short*)(dst + dlen/2);
994    int a, rv;
995 
996    rv= fread(tmp, 2, dlen, mix_in);
997    if (rv == 0) {
998       if (feof(mix_in))
999 	 return 0;
1000       error("Read error on mix input:\n  %s", strerror(errno));
1001    }
1002 
1003    // Now convert 16-bit little-endian input data into 20-bit native
1004    // int values
1005    if (bigendian) {
1006       char *rd= (char*)tmp;
1007       for (a= 0; a<rv; a++) {
1008 	 *dst++= ((rd[0]&255) + (rd[1]<<8)) << 4;
1009 	 rd += 2;
1010       }
1011    } else {
1012       for (a= 0; a<rv; a++)
1013 	 *dst++= *tmp++ << 4;
1014    }
1015 
1016    return rv;
1017 }
1018 
1019 
1020 
1021 //
1022 //	Update a status line
1023 //
1024 
1025 void
status(char * err)1026 status(char *err) {
1027   int a;
1028   int nch= N_CH;
1029   char *p= buf, *p0, *p1;
1030 
1031   if (opt_Q) return;
1032 
1033 #ifdef ANSI_TTY
1034   if (tty_erase) p += sprintf(p, "\033[K");
1035 #endif
1036 
1037   p0= p;		// Start of line
1038   *p++= ' '; *p++= ' ';
1039   p += sprintTime(p, now);
1040   while (nch > 1 && chan[nch-1].v.typ == 0) nch--;
1041   for (a= 0; a<nch; a++)
1042     p += sprintVoice(p, &chan[a].v, 0);
1043   if (err) p += sprintf(p, " %s", err);
1044   p1= p;		// End of line
1045 
1046 #ifndef ANSI_TTY
1047   // Truncate line to 79 characters on Windows
1048   if (p1-p0 > 79) {
1049     p1 = p0 + 76;
1050     p1 += sprintf(p1, "...");
1051   }
1052 #endif
1053 
1054 #ifndef ANSI_TTY
1055   while (tty_erase > p-p0) *p++= ' ';
1056 #endif
1057 
1058   tty_erase= p1-p0;		// Characters that will need erasing
1059   fprintf(stderr, "%s\r", buf);
1060   fflush(stderr);
1061 }
1062 
1063 void 				// Display current period details
dispCurrPer(FILE * fp)1064 dispCurrPer(FILE *fp) {
1065   int a;
1066   Voice *v0, *v1;
1067   char *p0, *p1;
1068   int len0, len1;
1069   int nch= N_CH;
1070 
1071   if (opt_Q) return;
1072 
1073   p0= buf;
1074   p1= buf_copy;
1075 
1076   p0 += sprintf(p0, "* ");
1077   p0 += sprintTime(p0, per->tim);
1078   p1 += sprintf(p1, "  ");
1079   p1 += sprintTime(p1, per->nxt->tim);
1080 
1081   v0= per->v0; v1= per->v1;
1082   while (nch > 1 && v0[nch-1].typ == 0) nch--;
1083   for (a= 0; a<nch; a++, v0++, v1++) {
1084     p0 += len0= sprintVoice(p0, v0, 0);
1085     p1 += len1= sprintVoice(p1, v1, v0);
1086     while (len0 < len1) { *p0++= ' '; len0++; }
1087     while (len1 < len0) { *p1++= ' '; len1++; }
1088   }
1089   *p0= 0; *p1= 0;
1090   fprintf(fp, "%s\n%s\n", buf, buf_copy);
1091   fflush(fp);
1092 }
1093 
1094 int
sprintTime(char * p,int tim)1095 sprintTime(char *p, int tim) {
1096   return sprintf(p, "%02d:%02d:%02d",
1097 		 tim % 86400000 / 3600000,
1098 		 tim % 3600000 / 60000,
1099 		 tim % 60000 / 1000);
1100 }
1101 
1102 int
sprintVoice(char * p,Voice * vp,Voice * dup)1103 sprintVoice(char *p, Voice *vp, Voice *dup) {
1104    switch (vp->typ) {
1105     case 0:
1106        return sprintf(p, " -");
1107     case 1:
1108        if (dup && vp->carr == dup->carr && vp->res == dup->res && vp->amp == dup->amp)
1109 	  return sprintf(p, "  ::");
1110        return sprintf(p, " %.2f%+.2f/%.2f", vp->carr, vp->res, AMP_AD(vp->amp));
1111     case 2:
1112        if (dup && vp->amp == dup->amp)
1113 	  return sprintf(p, "  ::");
1114        return sprintf(p, " pink/%.2f", AMP_AD(vp->amp));
1115     case 3:
1116        if (dup && vp->carr == dup->carr && vp->amp == dup->amp)
1117 	  return sprintf(p, "  ::");
1118        return sprintf(p, " bell%+.2f/%.2f", vp->carr, AMP_AD(vp->amp));
1119     case 4:
1120        if (dup && vp->carr == dup->carr && vp->res == dup->res && vp->amp == dup->amp)
1121 	  return sprintf(p, "  ::");
1122        return sprintf(p, " spin:%.2f%+.2f/%.2f", vp->carr, vp->res, AMP_AD(vp->amp));
1123     case 5:
1124        if (dup && vp->amp == dup->amp)
1125 	  return sprintf(p, "  ::");
1126        return sprintf(p, " mix/%.2f", AMP_AD(vp->amp));
1127     default:
1128        if (vp->typ < -100 || vp->typ > -1)
1129 	  return sprintf(p, " ERROR");
1130        if (dup && vp->typ == dup->typ &&
1131 	   vp->carr == dup->carr && vp->res == dup->res && vp->amp == dup->amp)
1132 	  return sprintf(p, "  ::");
1133        return sprintf(p, " wave%02d:%.2f%+.2f/%.2f", -1-vp->typ, vp->carr, vp->res, AMP_AD(vp->amp));
1134    }
1135 }
1136 
1137 void
init_sin_table()1138 init_sin_table() {
1139   int a;
1140   int *arr= (int*)Alloc(ST_SIZ * sizeof(int));
1141 
1142   for (a= 0; a<ST_SIZ; a++)
1143     arr[a]= (int)(ST_AMP * sin((a * 3.14159265358979323846 * 2) / ST_SIZ));
1144 
1145   sin_table= arr;
1146 }
1147 
1148 void
error(char * fmt,...)1149 error(char *fmt, ...) {
1150   va_list ap; va_start(ap, fmt);
1151   vfprintf(stderr, fmt, ap);
1152   fprintf(stderr, "\n");
1153 #ifdef EXIT_KEY
1154   fprintf(stderr, "Press <RETURN> to continue: ");
1155   fflush(stderr);
1156   getchar();
1157 #endif
1158   exit(1);
1159 }
1160 
1161 void
debug(char * fmt,...)1162 debug(char *fmt, ...) {
1163   va_list ap; va_start(ap, fmt);
1164   vfprintf(stderr, fmt, ap);
1165   fprintf(stderr, "\n");
1166 }
1167 
1168 void
warn(char * fmt,...)1169 warn(char *fmt, ...) {
1170   va_list ap; va_start(ap, fmt);
1171   vfprintf(stderr, fmt, ap);
1172   fprintf(stderr, "\n");
1173 }
1174 
1175 void *
Alloc(size_t len)1176 Alloc(size_t len) {
1177   void *p= calloc(1, len);
1178   if (!p) error("Out of memory");
1179   return p;
1180 }
1181 
1182 char *
StrDup(char * str)1183 StrDup(char *str) {
1184   char *rv= strdup(str);
1185   if (!rv) error("Out of memory");
1186   return rv;
1187 }
1188 
1189 #ifdef UNIX_TIME
1190 // Precalculate a reference timestamp to accelerate calcNow().  This
1191 // can be any recent time.  We recalculate it every 10 minutes.  The
1192 // only reason for doing this is to cope with clocks going forwards or
1193 // backwards when entering or leaving summer time so that people wake
1194 // up on time on these two dates; an hour of the sequence will be
1195 // repeated or skipped.  The 'time_ref*' variables will be initialised
1196 // on the first call to calcNow().
1197 
1198 static int time_ref_epoch= 0;	// Reference time compared to UNIX epoch
1199 static int time_ref_ms;		// Reference time in sbagen 24-hour milliseconds
1200 
1201 void
setupRefTime()1202 setupRefTime() {
1203   struct tm *tt;
1204   time_t tim= time(0);
1205   tt= localtime(&tim);
1206   time_ref_epoch= tim;
1207   time_ref_ms= 1000*tt->tm_sec + 60000*tt->tm_min + 3600000*tt->tm_hour;
1208 }
1209 
1210 static inline int
calcNow()1211 calcNow() {
1212   struct timeval tv;
1213   if (0 != gettimeofday(&tv, 0)) error("Can't get current time");
1214   if (tv.tv_sec - time_ref_epoch > 600) setupRefTime();
1215   return (time_ref_ms + (tv.tv_sec - time_ref_epoch) * 1000 + tv.tv_usec / 1000) % H24;
1216 }
1217 #endif
1218 
1219 #ifdef WIN_TIME
1220 inline int
calcNow()1221 calcNow() {
1222   SYSTEMTIME st;
1223   GetLocalTime(&st);
1224   return st.wMilliseconds + 1000*st.wSecond + 60000*st.wMinute + 3600000*st.wHour;
1225 }
1226 #endif
1227 
1228 #if DEBUG_CHK_UTIME
1229 inline int
userTime()1230 userTime() {
1231   struct tms buf;
1232   times(&buf);
1233   return buf.tms_utime;
1234 }
1235 #else
1236 // Dummy to avoid complaints on MSVC
userTime()1237 int userTime() { return 0; }
1238 #endif
1239 
1240 //
1241 //	Simple random number generator.  Generates a repeating
1242 //	sequence of 65536 odd numbers in the range -65535->65535.
1243 //
1244 //	Based on ZX Spectrum random number generator:
1245 //	  seed= (seed+1) * 75 % 65537 - 1
1246 //
1247 
1248 #define RAND_MULT 75
1249 
1250 static int seed= 2;
1251 
1252 //inline int qrand() {
1253 //  return (seed= seed * 75 % 131074) - 65535;
1254 //}
1255 
1256 //
1257 //	Generate next sample for simulated pink noise, with same
1258 //	scaling as the sin_table[].  This version uses an inlined
1259 //	random number generator, and smooths the lower frequency bands
1260 //	as well.
1261 //
1262 
1263 #define NS_BANDS 9
1264 typedef struct Noise Noise;
1265 struct Noise {
1266   int val;		// Current output value
1267   int inc;		// Increment
1268 };
1269 Noise ntbl[NS_BANDS];
1270 int nt_off;
1271 int noise_buf[256];
1272 uchar noise_off= 0;
1273 
1274 static inline int
noise2()1275 noise2() {
1276   int tot;
1277   int off= nt_off++;
1278   int cnt= 1;
1279   Noise *ns= ntbl;
1280   Noise *ns1= ntbl + NS_BANDS;
1281 
1282   tot= ((seed= seed * RAND_MULT % 131074) - 65535) * (NS_AMP / 65535 / (NS_BANDS + 1));
1283 
1284   while ((cnt & off) && ns < ns1) {
1285     int val= ((seed= seed * RAND_MULT % 131074) - 65535) * (NS_AMP / 65535 / (NS_BANDS + 1));
1286     tot += ns->val += ns->inc= (val - ns->val) / (cnt += cnt);
1287     ns++;
1288   }
1289 
1290   while (ns < ns1) {
1291     tot += (ns->val += ns->inc);
1292     ns++;
1293   }
1294 
1295   return noise_buf[noise_off++]= (tot >> NS_ADJ);
1296 }
1297 
1298 //	//
1299 //	//	Generate next sample for simulated pink noise, scaled the same
1300 //	//	as the sin_table[].  This version uses a library random number
1301 //	//	generator, and no smoothing.
1302 //	//
1303 //
1304 //	inline double
1305 //	noise() {
1306 //	  int tot= 0;
1307 //	  int bit= ~0;
1308 //	  int a;
1309 //	  int off;
1310 //
1311 //	  ns_tbl[ns_off]= (rand() - (RAND_MAX / 2)) / (NS_BIT + 1);
1312 //	  off= ns_off;
1313 //	  for (a= 0; a<=NS_BIT; a++, bit <<= 1) {
1314 //	    off &= bit;
1315 //	    tot += ns_tbl[off];
1316 //	  }
1317 //	  ns_off= (ns_off + 1) & ((1<<NS_BIT) - 1);
1318 //
1319 //	  return tot * (ST_AMP / (RAND_MAX * 0.5));
1320 //	}
1321 
1322 //
1323 //	Play loop
1324 //
1325 
1326 void
loop()1327 loop() {
1328   int c, cnt;
1329   int err;		// Error to add to 'now' until next cnt==0
1330   int fast= fast_mult != 0;
1331   int vfast= fast_mult > 20;		// Very fast - update status line often
1332   int utime= 0;
1333   int now_lo= 0;			// Low-order 16 bits of 'now' (fractional)
1334   int err_lo= 0;
1335   int ms_inc;
1336 
1337   setup_device();
1338   spin_carr_max= 127.0 / 1E-6 / out_rate;
1339   cnt= 1 + 1999 / out_buf_ms;	// Update every 2 seconds or so
1340   now= opt_S ? fast_tim0 : calcNow();
1341   if (opt_T != -1) now= opt_T;
1342   err= fast ? out_buf_ms * (fast_mult - 1) : 0;
1343   if (opt_L)
1344     byte_count= out_bps * (S64)(opt_L * 0.001 * out_rate);
1345   if (opt_E)
1346     byte_count= out_bps * (S64)(t_per0(now, fast_tim1) * 0.001 * out_rate /
1347 				(fast ? fast_mult : 1));
1348 
1349   // Do byte-swapping if bigendian and outputting to a file or stream
1350   if ((opt_O || opt_o) &&
1351       out_mode == 1 && bigendian)
1352      out_mode= 2;
1353 
1354   if (opt_W)
1355     writeWAV();
1356 
1357   if (!opt_Q) fprintf(stderr, "\n");
1358   corrVal(0);		// Get into correct period
1359   dispCurrPer(stderr);	// Display
1360   status(0);
1361 
1362   while (1) {
1363     for (c= 0; c < cnt; c++) {
1364       corrVal(1);
1365       outChunk();
1366       ms_inc= out_buf_ms + err;
1367       now_lo += out_buf_lo + err_lo;
1368       if (now_lo >= 0x10000) { ms_inc += now_lo >> 16; now_lo &= 0xFFFF; }
1369       now += ms_inc;
1370       if (now > H24) now -= H24;
1371       if (vfast && (c&1)) status(0);
1372     }
1373 
1374     if (fast) {
1375       if (!vfast) status(0);
1376     }
1377     else {
1378       // Synchronize with real clock, gently over the next second or so
1379       char buf[32];
1380       int diff= calcNow() - now;
1381       if (abs(diff) > H12) diff= 0;
1382       sprintf(buf, "(%d)", diff);
1383 
1384       err_lo= diff * 0x10000 / cnt;
1385       err= err_lo >> 16;
1386       err_lo &= 0xFFFF;
1387 
1388       if (DEBUG_CHK_UTIME) {
1389 	int prev= utime;
1390 	utime= userTime();
1391 	sprintf(buf, "%d ticks", utime-prev);		// Replaces standard message
1392       }
1393       status(buf);
1394     }
1395   }
1396 }
1397 
1398 
1399 //
1400 //	Output a chunk of sound (a buffer-ful), then return
1401 //
1402 //	Note: Optimised for 16-bit output.  Eight-bit output is
1403 //	slower, but then it probably won't have to run at as high a
1404 //	sample rate.
1405 //
1406 
1407 int rand0, rand1;
1408 
1409 void
outChunk()1410 outChunk() {
1411    int off= 0;
1412 
1413    if (mix_in) {
1414       int rv= inbuf_read(tmp_buf, out_blen);
1415       if (rv == 0) {
1416 	 if (!opt_Q) warn("\nEnd of mix input audio stream");
1417 	 exit(0);
1418       }
1419       while (rv < out_blen) tmp_buf[rv++]= 0;
1420    }
1421 
1422    while (off < out_blen) {
1423       int ns= noise2();		// Use same pink noise source for everything
1424       int tot1, tot2;		// Left and right channels
1425       int mix1, mix2;		// Incoming mix signals
1426       int val, a;
1427       Channel *ch;
1428       int *tab;
1429 
1430       mix1= tmp_buf[off];
1431       mix2= tmp_buf[off+1];
1432 
1433       // Do default mixing at 100% if no mix/* stuff is present
1434       if (!mix_flag) {
1435 	 tot1= mix1 << 12;
1436 	 tot2= mix2 << 12;
1437       } else {
1438 	 tot1= tot2= 0;
1439       }
1440 
1441       ch= &chan[0];
1442       for (a= 0; a<N_CH; a++, ch++) switch (ch->typ) {
1443        case 0:
1444 	  break;
1445        case 1:	// Binaural tones
1446 	  ch->off1 += ch->inc1;
1447 	  ch->off1 &= (ST_SIZ << 16) - 1;
1448 	  tot1 += ch->amp * sin_table[ch->off1 >> 16];
1449 	  ch->off2 += ch->inc2;
1450 	  ch->off2 &= (ST_SIZ << 16) - 1;
1451 	  tot2 += ch->amp2 * sin_table[ch->off2 >> 16];
1452 	  break;
1453        case 2:	// Pink noise
1454 	  val= ns * ch->amp;
1455 	  tot1 += val;
1456 	  tot2 += val;
1457 	  break;
1458        case 3:	// Bell
1459 	  if (ch->off2) {
1460 	     ch->off1 += ch->inc1;
1461 	     ch->off1 &= (ST_SIZ << 16) - 1;
1462 	     val= ch->off2 * sin_table[ch->off1 >> 16];
1463 	     tot1 += val; tot2 += val;
1464 	     if (--ch->inc2 < 0) {
1465 		ch->inc2= out_rate/20;
1466 		ch->off2 -= 1 + ch->off2 / 12;	// Knock off 10% each 50 ms
1467 	     }
1468 	  }
1469 	  break;
1470        case 4:	// Spinning pink noise
1471 	  ch->off1 += ch->inc1;
1472 	  ch->off1 &= (ST_SIZ << 16) - 1;
1473 	  val= (ch->inc2 * sin_table[ch->off1 >> 16]) >> 24;
1474 	  tot1 += ch->amp * noise_buf[(uchar)(noise_off+128+val)];
1475 	  tot2 += ch->amp * noise_buf[(uchar)(noise_off+128-val)];
1476 	  break;
1477        case 5:	// Mix level
1478 	  tot1 += mix1 * ch->amp;
1479 	  tot2 += mix2 * ch->amp;
1480 	  break;
1481        default:	// Waveform-based binaural tones
1482 	  tab= waves[-1 - ch->typ];
1483 	  ch->off1 += ch->inc1;
1484 	  ch->off1 &= (ST_SIZ << 16) - 1;
1485 	  tot1 += ch->amp * tab[ch->off1 >> 16];
1486 	  ch->off2 += ch->inc2;
1487 	  ch->off2 &= (ST_SIZ << 16) - 1;
1488 	  tot2 += ch->amp * tab[ch->off2 >> 16];
1489 	  break;
1490       }
1491 
1492 
1493       // // Add pink noise as dithering
1494       // tot1 += (ns >> NS_DITHER) + 0x8000;
1495       // tot2 += (ns >> NS_DITHER) + 0x8000;
1496 
1497       // // Add white noise as dithering
1498       // tot1 += (seed >> 1) + 0x8000;
1499       // tot2 += (seed >> 1) + 0x8000;
1500 
1501       // White noise dither; you could also try (rand0-rand1) for a
1502       // dither with more high frequencies
1503       rand0= rand1;
1504       rand1= (rand0 * 0x660D + 0xF35F) & 0xFFFF;
1505       if (tot1 <= 0x7FFF0000) tot1 += rand0;
1506       if (tot2 <= 0x7FFF0000) tot2 += rand0;
1507 
1508       out_buf[off++]= tot1 >> 16;
1509       out_buf[off++]= tot2 >> 16;
1510   }
1511 
1512   // Generate debugging amplitude output
1513   if (DEBUG_DUMP_AMP) {
1514     short *sp= out_buf;
1515     short *end= out_buf + out_blen;
1516     int max= 0;
1517     while (sp < end) {
1518        int val= (int)sp[0] + (int)sp[1]; sp += 2;
1519        if (val < 0) val= -val;
1520        if (val > max) max= val;
1521     }
1522     max /= 328;
1523     while (max-- > 0) putc('#', stdout);
1524     printf("\n"); fflush(stdout);
1525   }
1526 
1527   // Rewrite buffer for 8-bit mode
1528   if (out_mode == 0) {
1529     short *sp= out_buf;
1530     short *end= out_buf + out_blen;
1531     char *cp= (char*)out_buf;
1532     while (sp < end) *cp++= (*sp++ >> 8) + 128;
1533   }
1534 
1535   // Rewrite buffer for 16-bit byte-swapping
1536   if (out_mode == 2) {
1537     char *cp= (char*)out_buf;
1538     char *end= (char*)(out_buf + out_blen);
1539     while (cp < end) { char tmp= *cp++; cp[-1]= cp[0]; *cp++= tmp; }
1540   }
1541 
1542   // Check and update the byte count if necessary
1543   if (byte_count > 0) {
1544     if (byte_count <= out_bsiz) {
1545       writeOut((char*)out_buf, byte_count);
1546       exit(0);		// All done
1547     }
1548     else {
1549       writeOut((char*)out_buf, out_bsiz);
1550       byte_count -= out_bsiz;
1551     }
1552   }
1553   else
1554     writeOut((char*)out_buf, out_bsiz);
1555 }
1556 
1557 void
writeOut(char * buf,int siz)1558 writeOut(char *buf, int siz) {
1559   int rv;
1560 
1561 #ifdef WIN_AUDIO
1562   if (out_fd == -9999) {
1563      // Win32 output: write it to a header and send it off
1564      MMRESULT rv;
1565 
1566      //debug_win32_buffer_status();
1567 
1568      //while (aud_cnt == BUFFER_COUNT) {
1569      //while (aud_head[aud_current]->dwFlags & WHDR_INQUEUE) {
1570      while (!(aud_head[aud_current]->dwFlags & WHDR_DONE)) {
1571 	//debug("SLEEP %d", out_buf_ms / 2 + 1);
1572 	Sleep(out_buf_ms / 2 + 1);
1573 	//debug_win32_buffer_status();
1574      }
1575 
1576      memcpy(aud_head[aud_current]->lpData, buf, siz);
1577      aud_head[aud_current]->dwBufferLength= (DWORD)siz;
1578 
1579      //debug("Output buffer %d", aud_current);
1580      rv= waveOutWrite(aud_handle, aud_head[aud_current], sizeof(WAVEHDR));
1581 
1582      if (rv != MMSYSERR_NOERROR) {
1583         char buf[255];
1584         waveOutGetErrorText(rv, buf, sizeof(buf)-1);
1585         error("Error writing a fragment to the audio device:\n  %s", buf);
1586      }
1587 
1588      aud_cnt++;
1589      aud_current++;
1590      aud_current %= BUFFER_COUNT;
1591 
1592      return;
1593   }
1594 #endif
1595 
1596 #ifdef MAC_AUDIO
1597   if (out_fd == -9999) {
1598     int new_wr= (aud_wr + 1) % BUFFER_COUNT;
1599 
1600     // Wait until there is space
1601     while (new_wr == aud_rd) delay(20);
1602 
1603     memcpy(aud_buf[aud_wr], buf, siz);
1604     aud_wr= new_wr;
1605 
1606     return;
1607   }
1608 #endif
1609 
1610   while (-1 != (rv= write(out_fd, buf, siz))) {
1611     if (0 == (siz -= rv)) return;
1612     buf += rv;
1613   }
1614   error("Output error");
1615 }
1616 
1617 //
1618 //	Calculate amplitude adjustment factor for frequency 'freq'
1619 //
1620 
1621 double
ampAdjust(double freq)1622 ampAdjust(double freq) {
1623    int a;
1624    struct AmpAdj *p0, *p1;
1625 
1626    if (!opt_c) return 1.0;
1627    if (freq <= ampadj[0].freq) return ampadj[0].adj;
1628    if (freq >= ampadj[opt_c-1].freq) return ampadj[opt_c-1].adj;
1629 
1630    for (a= 1; a<opt_c; a++)
1631       if (freq < ampadj[a].freq)
1632 	 break;
1633 
1634    p0= &ampadj[a-1];
1635    p1= &ampadj[a];
1636 
1637    return p0->adj + (p1->adj - p0->adj) * (freq - p0->freq) / (p1->freq - p0->freq);
1638 }
1639 
1640 
1641 //
1642 //	Correct channel values and types according to current period,
1643 //	and current time
1644 //
1645 
1646 void
corrVal(int running)1647 corrVal(int running) {
1648    int a;
1649    int t0= per->tim;
1650    int t1= per->nxt->tim;
1651    Channel *ch;
1652    Voice *v0, *v1, *vv;
1653    double rat0, rat1;
1654    int trigger= 0;
1655 
1656    // Move to the correct period
1657    while ((now >= t0) ^ (now >= t1) ^ (t1 > t0)) {
1658       per= per->nxt;
1659       t0= per->tim;
1660       t1= per->nxt->tim;
1661       if (running) {
1662 	 if (tty_erase) {
1663 #ifdef ANSI_TTY
1664 	    fprintf(stderr, "\033[K");
1665 #else
1666 	    fprintf(stderr, "%*s\r", tty_erase, "");
1667 	    tty_erase= 0;
1668 #endif
1669 	 }
1670 	 dispCurrPer(stderr); status(0);
1671       }
1672       trigger= 1;		// Trigger bells or whatever
1673    }
1674 
1675    // Run through to calculate voice settings for current time
1676    rat1= t_per0(t0, now) / (double)t_per24(t0, t1);
1677    rat0= 1 - rat1;
1678    for (a= 0; a<N_CH; a++) {
1679       ch= &chan[a];
1680       v0= &per->v0[a];
1681       v1= &per->v1[a];
1682       vv= &ch->v;
1683 
1684       if (vv->typ != v0->typ) {
1685 	 switch (vv->typ= ch->typ= v0->typ) {
1686 	  case 1:
1687 	     ch->off1= ch->off2= 0; break;
1688 	  case 2:
1689 	     break;
1690 	  case 3:
1691 	     ch->off1= ch->off2= 0; break;
1692 	  case 4:
1693 	     ch->off1= ch->off2= 0; break;
1694 	  case 5:
1695 	     break;
1696 	  default:
1697 	     ch->off1= ch->off2= 0; break;
1698 	 }
1699       }
1700 
1701       // Setup vv->*
1702       switch (vv->typ) {
1703        case 1:
1704 	  vv->amp= rat0 * v0->amp + rat1 * v1->amp;
1705 	  vv->carr= rat0 * v0->carr + rat1 * v1->carr;
1706 	  vv->res= rat0 * v0->res + rat1 * v1->res;
1707 	  break;
1708        case 2:
1709 	  vv->amp= rat0 * v0->amp + rat1 * v1->amp;
1710 	  break;
1711        case 3:
1712 	  vv->amp= v0->amp;		// No need to slide, as bell only rings briefly
1713 	  vv->carr= v0->carr;
1714 	  break;
1715        case 4:
1716 	  vv->amp= rat0 * v0->amp + rat1 * v1->amp;
1717 	  vv->carr= rat0 * v0->carr + rat1 * v1->carr;
1718 	  vv->res= rat0 * v0->res + rat1 * v1->res;
1719 	  if (vv->carr > spin_carr_max) vv->carr= spin_carr_max; // Clipping sweep width
1720 	  if (vv->carr < -spin_carr_max) vv->carr= -spin_carr_max;
1721 	  break;
1722        case 5:
1723 	  vv->amp= rat0 * v0->amp + rat1 * v1->amp;
1724 	  break;
1725        default:		// Waveform based binaural
1726 	  vv->amp= rat0 * v0->amp + rat1 * v1->amp;
1727 	  vv->carr= rat0 * v0->carr + rat1 * v1->carr;
1728 	  vv->res= rat0 * v0->res + rat1 * v1->res;
1729 	  break;
1730       }
1731    }
1732 
1733    // Check and limit amplitudes if -c option in use
1734    if (opt_c) {
1735       double tot_beat= 0, tot_other= 0;
1736       for (a= 0; a<N_CH; a++) {
1737 	 vv= &chan[a].v;
1738 	 if (vv->typ == 1) {
1739 	    double adj1= ampAdjust(vv->carr + vv->res/2);
1740 	    double adj2= ampAdjust(vv->carr - vv->res/2);
1741 	    if (adj2 > adj1) adj1= adj2;
1742 	    tot_beat += vv->amp * adj1;
1743 	 } else if (vv->typ) {
1744 	    tot_other += vv->amp;
1745 	 }
1746       }
1747       if (tot_beat + tot_other > 4096) {
1748 	 double adj_beat= (tot_beat > 4096) ? 4096 / tot_beat : 1.0;
1749 	 double adj_other= (4096 - tot_beat * adj_beat) / tot_other;
1750 	 for (a= 0; a<N_CH; a++) {
1751 	    vv= &chan[a].v;
1752 	    if (vv->typ == 1)
1753 	       vv->amp *= adj_beat;
1754 	    else if (vv->typ)
1755 	       vv->amp *= adj_other;
1756 	 }
1757       }
1758    }
1759 
1760    // Setup Channel data from Voice data
1761    for (a= 0; a<N_CH; a++) {
1762       ch= &chan[a];
1763       vv= &ch->v;
1764 
1765       // Setup ch->* from vv->*
1766       switch (vv->typ) {
1767 	 double freq1, freq2;
1768        case 1:
1769 	  freq1= vv->carr + vv->res/2;
1770 	  freq2= vv->carr - vv->res/2;
1771 	  if (opt_c) {
1772 	     ch->amp= vv->amp * ampAdjust(freq1);
1773 	     ch->amp2= vv->amp * ampAdjust(freq2);
1774 	  } else
1775 	     ch->amp= ch->amp2= (int)vv->amp;
1776 	  ch->inc1= (int)(freq1 / out_rate * ST_SIZ * 65536);
1777 	  ch->inc2= (int)(freq2 / out_rate * ST_SIZ * 65536);
1778 	  break;
1779        case 2:
1780 	  ch->amp= (int)vv->amp;
1781 	  break;
1782        case 3:
1783 	  ch->amp= (int)vv->amp;
1784 	  ch->inc1= (int)(vv->carr / out_rate * ST_SIZ * 65536);
1785 	  if (trigger) {		// Trigger the bell only on entering the period
1786 	     ch->off2= ch->amp;
1787 	     ch->inc2= out_rate/20;
1788 	  }
1789 	  break;
1790        case 4:
1791 	  ch->amp= (int)vv->amp;
1792 	  ch->inc1= (int)(vv->res / out_rate * ST_SIZ * 65536);
1793 	  ch->inc2= (int)(vv->carr * 1E-6 * out_rate * (1<<24) / ST_AMP);
1794 	  break;
1795        case 5:
1796 	  ch->amp= (int)vv->amp;
1797 	  break;
1798        default:		// Waveform based binaural
1799 	  ch->amp= (int)vv->amp;
1800 	  ch->inc1= (int)((vv->carr + vv->res/2) / out_rate * ST_SIZ * 65536);
1801 	  ch->inc2= (int)((vv->carr - vv->res/2) / out_rate * ST_SIZ * 65536);
1802 	  if (ch->inc1 > ch->inc2)
1803 	     ch->inc2= -ch->inc2;
1804 	  else
1805 	     ch->inc1= -ch->inc1;
1806 	  break;
1807       }
1808    }
1809 }
1810 
1811 //
1812 //	Setup audio device
1813 //
1814 
1815 void
setup_device(void)1816 setup_device(void) {
1817 
1818   // Handle output to files and pipes
1819   if (opt_O || opt_o) {
1820     if (opt_O)
1821       out_fd= 1;		// stdout
1822     else {
1823       FILE *out;		// Need to create a stream to set binary mode for DOS
1824       if (!(out= fopen(opt_o, "wb")))
1825 	error("Can't open \"%s\", errno %d", opt_o, errno);
1826       out_fd= fileno(out);
1827     }
1828     out_blen= out_rate * 2 / out_prate;		// 10 fragments a second by default
1829     while (out_blen & (out_blen-1)) out_blen &= out_blen-1;		// Make power of two
1830     out_bsiz= out_blen * (out_mode ? 2 : 1);
1831     out_bps= out_mode ? 4 : 2;
1832     out_buf= (short*)Alloc(out_blen * sizeof(short));
1833     out_buf_lo= (int)(0x10000 * 1000.0 * 0.5 * out_blen / out_rate);
1834     out_buf_ms= out_buf_lo >> 16;
1835     out_buf_lo &= 0xFFFF;
1836     tmp_buf= (int*)Alloc(out_blen * sizeof(int));
1837 
1838     if (!opt_Q && !opt_W)		// Informational message for opt_W is written later
1839        warn("Outputting %d-bit raw audio data at %d Hz with %d-sample blocks, %d ms per block",
1840 	    out_mode ? 16 : 8, out_rate, out_blen/2, out_buf_ms);
1841     return;
1842   }
1843 
1844 #ifdef OSS_AUDIO
1845   // Normal /dev/dsp output
1846   {
1847     int stereo, rate, fragsize, numfrags, enc;
1848     int targ_ms= 400;	// How much buffering we want, ideally
1849     int afmt_req, afmt;
1850     int test= 1;
1851     audio_buf_info info;
1852     int retry= 0;
1853 
1854     fragsize= 14;  // Ask for fragments of 2^14 == 16384 bytes == 4096 samples
1855 
1856     while (1) {
1857        if (0 > (out_fd= open(opt_d, O_WRONLY)))
1858 	  error("Can't open %s, errno %d", opt_d, errno);
1859 
1860        afmt= afmt_req= ((out_mode == 0) ? AFMT_U8 :
1861 			((char*)&test)[0] ? AFMT_S16_LE : AFMT_S16_BE);
1862        stereo= 1;
1863        rate= out_rate;
1864        numfrags= (out_rate * 4 * targ_ms / 1000) >> fragsize;
1865        if (numfrags < 1) numfrags= 1;
1866        enc= (numfrags<<16) | fragsize;
1867 
1868        if (0 > ioctl(out_fd, SNDCTL_DSP_SETFRAGMENT, &enc) ||
1869 	   0 > ioctl(out_fd, SNDCTL_DSP_SAMPLESIZE, &afmt) ||
1870 	   0 > ioctl(out_fd, SNDCTL_DSP_STEREO, &stereo) ||
1871 	   0 > ioctl(out_fd, SNDCTL_DSP_SPEED, &rate))
1872 	  error("Can't configure %s, errno %d", opt_d, errno);
1873 
1874        if (afmt != afmt_req)
1875 	  error("Can't open device in %d-bit mode", out_mode ? 16 : 8);
1876        if (!stereo)
1877 	  error("Can't open device in stereo");
1878 
1879        out_rate= rate;
1880 
1881        if (-1 == ioctl(out_fd, SNDCTL_DSP_GETOSPACE, &info))
1882 	  error("Can't get audio buffer info, errno %d", errno);
1883 
1884        if (!retry && info.fragsize != (1<<fragsize)) {
1885 	  // We've received a different fragment size to what we asked
1886 	  // for.  This means that the numfrags calculation is wrong.
1887 	  // Re-open based on this fragsize.
1888 	  close(out_fd);
1889 	  for (fragsize= 1; (1<<fragsize) < info.fragsize; fragsize++) ;
1890 	  retry= 1;
1891 	  //warn("Retrying /dev/dsp open for fragsize %d", fragsize);
1892 	  continue;
1893        }
1894        break;
1895     }
1896 
1897     out_bsiz= info.fragsize;
1898     out_blen= out_mode ? out_bsiz/2 : out_bsiz;
1899     out_bps= out_mode ? 4 : 2;
1900     out_buf= (short*)Alloc(out_blen * sizeof(short));
1901     out_buf_lo= (int)(0x10000 * 1000.0 * 0.5 * out_blen / out_rate);
1902     out_buf_ms= out_buf_lo >> 16;
1903     out_buf_lo &= 0xFFFF;
1904     tmp_buf= (int*)Alloc(out_blen * sizeof(int));
1905 
1906     if (!opt_Q)
1907        warn("Outputting %d-bit audio at %d Hz with %d %d-sample fragments, %d ms per fragment",
1908 	    out_mode ? 16 : 8, out_rate, info.fragstotal, out_blen/2, out_buf_ms);
1909   }
1910 #endif
1911 #ifdef WIN_AUDIO
1912   // Output using Win32 calls
1913   {
1914      MMRESULT rv;
1915      WAVEFORMATEX fmt;
1916      int a;
1917 
1918      fmt.wFormatTag= WAVE_FORMAT_PCM;
1919      fmt.nChannels= 2;
1920      fmt.nSamplesPerSec= out_rate;
1921      fmt.wBitsPerSample= out_mode ? 16 : 8;
1922      fmt.nBlockAlign= fmt.nChannels * (fmt.wBitsPerSample/8);
1923      fmt.nAvgBytesPerSec= fmt.nSamplesPerSec * fmt.nBlockAlign;
1924      fmt.cbSize= 0;
1925      aud_handle= NULL;
1926 
1927      // if (MMSYSERR_NOERROR !=
1928      //    waveOutOpen(&aud_handle, WAVE_MAPPER, &fmt, 0,
1929      //                0L, WAVE_FORMAT_QUERY))
1930      //    error("Windows is rejecting our audio request (%d-bit stereo, %dHz)",
1931      //          out_mode ? 16 : 8, out_rate);
1932 
1933      if (MMSYSERR_NOERROR !=
1934 	 (rv= waveOutOpen(&aud_handle, WAVE_MAPPER,
1935 			  (WAVEFORMATEX*)&fmt, (DWORD)win32_audio_callback,
1936 			  (DWORD)0, CALLBACK_FUNCTION))) {
1937 	char buf[255];
1938 	waveOutGetErrorText(rv, buf, sizeof(buf)-1);
1939 	error("Can't open audio device (%d-bit stereo, %dHz):\n  %s",
1940                out_mode ? 16 : 8, out_rate, buf);
1941      }
1942 
1943      if (fmt.nChannels != 2)
1944 	error("Can't open audio device in stereo");
1945      if (fmt.wBitsPerSample != (out_mode ? 16 : 8))
1946 	error("Can't open audio device in %d-bit mode", out_mode ? 16 : 8);
1947 
1948      aud_current= 0;
1949      aud_cnt= 0;
1950 
1951      for (a= 0; a<BUFFER_COUNT; a++) {
1952 	char *p= (char *)Alloc(sizeof(WAVEHDR) + BUFFER_SIZE);
1953 	WAVEHDR *w= aud_head[a]= (WAVEHDR*)p;
1954 
1955 	w->lpData= (LPSTR)p + sizeof(WAVEHDR);
1956 	w->dwBufferLength= (DWORD)BUFFER_SIZE;
1957 	w->dwBytesRecorded= 0L;
1958 	w->dwUser= 0;
1959 	w->dwFlags= 0;
1960 	w->dwLoops= 0;
1961 	w->lpNext= 0;
1962 	w->reserved= 0;
1963 
1964 	rv= waveOutPrepareHeader(aud_handle, w, sizeof(WAVEHDR));
1965 	if (rv != MMSYSERR_NOERROR) {
1966 	   char buf[255];
1967 	   waveOutGetErrorText(rv, buf, sizeof(buf)-1);
1968 	   error("Can't setup a wave header %d:\n  %s", a, buf);
1969 	}
1970 	w->dwFlags |= WHDR_DONE;
1971      }
1972 
1973      out_rate= fmt.nSamplesPerSec;
1974      out_bsiz= BUFFER_SIZE;
1975      out_blen= out_mode ? out_bsiz/2 : out_bsiz;
1976      out_bps= out_mode ? 4 : 2;
1977      out_buf= (short*)Alloc(out_blen * sizeof(short));
1978      out_buf_lo= (int)(0x10000 * 1000.0 * 0.5 * out_blen / out_rate);
1979      out_buf_ms= out_buf_lo >> 16;
1980      out_buf_lo &= 0xFFFF;
1981      out_fd= -9999;
1982      tmp_buf= (int*)Alloc(out_blen * sizeof(int));
1983 
1984      if (!opt_Q)
1985 	warn("Outputting %d-bit audio at %d Hz with %d %d-sample fragments, "
1986 	     "%d ms per fragment", out_mode ? 16 : 8,
1987 	     out_rate, BUFFER_COUNT, out_blen/2, out_buf_ms);
1988   }
1989 #endif
1990 #ifdef MAC_AUDIO
1991   // Mac CoreAudio for OS X
1992   {
1993     char deviceName[256];
1994     OSStatus err;
1995     UInt32 propertySize, bufferByteCount;
1996     struct AudioStreamBasicDescription streamDesc;
1997     int old_out_rate= out_rate;
1998 
1999     out_bsiz= BUFFER_SIZE;
2000     out_blen= out_mode ? out_bsiz/2 : out_bsiz;
2001     out_bps= out_mode ? 4 : 2;
2002     out_buf= (short*)Alloc(out_blen * sizeof(short));
2003     out_buf_lo= (int)(0x10000 * 1000.0 * 0.5 * out_blen / out_rate);
2004     out_buf_ms= out_buf_lo >> 16;
2005     out_buf_lo &= 0xFFFF;
2006     tmp_buf= (int*)Alloc(out_blen * sizeof(int));
2007 
2008     // N.B.  Both -r and -b flags are totally ignored for CoreAudio --
2009     // we just use whatever the default device is set to, and feed it
2010     // floats.
2011     out_mode= 1;
2012     out_fd= -9999;
2013 
2014     // Find default device
2015     propertySize= sizeof(aud_dev);
2016     if ((err= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
2017 				       &propertySize, &aud_dev)))
2018       error("Get default output device failed, status = %d", (int)err);
2019 
2020     if (aud_dev == kAudioDeviceUnknown)
2021       error("No default audio device found");
2022 
2023     // Get device name
2024     propertySize= sizeof(deviceName);
2025     if ((err= AudioDeviceGetProperty(aud_dev, 1, 0,
2026 				     kAudioDevicePropertyDeviceName,
2027 				     &propertySize, deviceName)))
2028       error("Get audio device name failed, status = %d", (int)err);
2029 
2030     // Get device properties
2031     propertySize= sizeof(streamDesc);
2032     if ((err= AudioDeviceGetProperty(aud_dev, 1, 0,
2033 				     kAudioDevicePropertyStreamFormat,
2034 				     &propertySize, &streamDesc)))
2035       error("Get audio device properties failed, status = %d", (int)err);
2036 
2037     out_rate= (int)streamDesc.mSampleRate;
2038 
2039     if (streamDesc.mChannelsPerFrame != 2)
2040       error("SBaGen requires a stereo output device -- \n"
2041 	    "default output has %d channels",
2042 	    streamDesc.mChannelsPerFrame);
2043 
2044     if (streamDesc.mFormatID != kAudioFormatLinearPCM ||
2045 	!(streamDesc.mFormatFlags & kLinearPCMFormatFlagIsFloat))
2046       error("Expecting a 32-bit float linear PCM output stream -- \n"
2047 	    "default output uses another format");
2048 
2049     // Set buffer size
2050     bufferByteCount= BUFFER_SIZE / 2 * sizeof(float);
2051     propertySize= sizeof(bufferByteCount);
2052     if ((err= AudioDeviceSetProperty(aud_dev, 0, 0, 0,
2053 				     kAudioDevicePropertyBufferSize,
2054 				     propertySize, &bufferByteCount)))
2055       error("Set audio output buffer size failed, status = %d", (int)err);
2056 
2057     // Setup callback and start it
2058     err= AudioDeviceAddIOProc(aud_dev, mac_callback, (void *)1);
2059     err= AudioDeviceStart(aud_dev, mac_callback);
2060 
2061     // Report settings
2062     if (!opt_Q) {
2063        if (old_out_rate != out_rate && !out_rate_def)
2064 	  warn("*** WARNING: Non-default sampling rates not yet supported on OS X ***");
2065        warn("Outputting %d-bit audio at %d Hz to \"%s\",\n"
2066 	    "  using %d %d-sample fragments, %d ms per fragment",
2067 	    (int)streamDesc.mBitsPerChannel, out_rate, deviceName,
2068 	    BUFFER_COUNT, out_blen/2, out_buf_ms);
2069     }
2070   }
2071 #endif
2072 #ifdef NO_AUDIO
2073   error("Direct output to soundcard not supported on this platform.\n"
2074 	"Use -o or -O to write raw data, or -Wo or -WO to write a WAV file.");
2075 #endif
2076 }
2077 
2078 //
2079 //	Audio callback for Win32
2080 //
2081 
2082 #ifdef WIN_AUDIO
2083 void CALLBACK
win32_audio_callback(HWAVEOUT hand,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)2084 win32_audio_callback(HWAVEOUT hand, UINT uMsg,
2085 		     DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) {
2086    switch (uMsg) {
2087     case WOM_CLOSE:
2088        break;
2089     case WOM_OPEN:
2090        break;
2091     case WOM_DONE:
2092        aud_cnt--;
2093        //debug("Buffer done (cnt==%d)", aud_cnt);
2094        //debug_win32_buffer_status();
2095        break;
2096    }
2097 }
2098 
debug_win32_buffer_status()2099 void debug_win32_buffer_status() {
2100    char tmp[80];
2101    char *p= tmp;
2102    int a;
2103    for (a= 0; a<BUFFER_COUNT; a++) {
2104       *p++= (aud_head[a]->dwFlags & WHDR_INQUEUE) ? 'I' : '-';
2105       *p++= (aud_head[a]->dwFlags & WHDR_DONE) ? 'D' : '-';
2106       *p++= ' ';
2107    }
2108    p[-1]= 0;
2109    debug(tmp);
2110 }
2111 #endif
2112 
2113 //
2114 //	Audio callback for Mac OS X
2115 //
2116 
2117 #ifdef MAC_AUDIO
mac_callback(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * inInputData,const AudioTimeStamp * inInputTime,AudioBufferList * outOutputData,const AudioTimeStamp * inOutputTime,void * inClientData)2118 OSStatus mac_callback(AudioDeviceID inDevice,
2119 		      const AudioTimeStamp *inNow,
2120 		      const AudioBufferList *inInputData,
2121 		      const AudioTimeStamp *inInputTime,
2122 		      AudioBufferList *outOutputData,
2123 		      const AudioTimeStamp *inOutputTime,
2124 		      void *inClientData)
2125 {
2126   float *fp= outOutputData->mBuffers[0].mData;
2127   int cnt= BUFFER_SIZE / 2;
2128   short *sp;
2129 
2130   if (aud_rd == aud_wr) {
2131     // Nothing in buffer list, so fill with silence
2132     while (cnt-- > 0) *fp++= 0.0;
2133   } else {
2134     // Consume a buffer
2135     sp= (short*)aud_buf[aud_rd];
2136     while (cnt-- > 0) *fp++= *sp++ * (1/32768.0);
2137     aud_rd= (aud_rd + 1) % BUFFER_COUNT;
2138   }
2139 
2140   return kAudioHardwareNoError;
2141 }
2142 #endif
2143 
2144 //
2145 //	Write a WAV header, and setup out_mode if byte-swapping is
2146 //	required.  'byte_count' should have been set up by this point.
2147 //
2148 
2149 #define addU4(xx) { int a= xx; *p++= a; *p++= (a >>= 8); *p++= (a >>= 8); *p++= (a >>= 8); }
2150 #define addStr(xx) { char *q= xx; *p++= *q++; *p++= *q++; *p++= *q++; *p++= *q++; }
2151 
2152 void
writeWAV()2153 writeWAV() {
2154   char buf[44], *p= buf;
2155 
2156   if (byte_count + 36 != (int)(byte_count + 36)) {
2157      int tmp;
2158      byte_count= 0xFFFFFFF8-36;
2159      tmp= byte_count/out_bps/out_rate;
2160      warn("WARNING: Selected length is too long for the WAV format; truncating to %dh%02dm%02ds",
2161 	  tmp/3600, tmp/60%60, tmp%60);
2162   }
2163 
2164   addStr("RIFF");
2165   addU4(byte_count + 36);
2166   addStr("WAVE");
2167   addStr("fmt ");
2168   addU4(16);
2169   addU4(0x00020001);
2170   addU4(out_rate);
2171   addU4(out_rate * out_bps);
2172   addU4(0x0004 + 0x10000*(out_bps*4));	// 2,4 -> 8,16 - always assume stereo
2173   addStr("data");
2174   addU4(byte_count);
2175   writeOut(buf, 44);
2176 
2177   if (!opt_Q)
2178      warn("Outputting %d-bit WAV data at %d Hz, file size %d bytes",
2179 	  out_mode ? 16 : 8, out_rate, byte_count + 44);
2180 }
2181 
2182 //
2183 //	Read a line, discarding blank lines and comments.  Rets:
2184 //	Another line?  Comments starting with '##' are displayed on
2185 //	stderr.
2186 //
2187 
2188 int
readLine()2189 readLine() {
2190    char *p;
2191    lin= buf;
2192 
2193    while (1) {
2194       if (!fgets(lin, sizeof(buf), in)) {
2195 	 if (feof(in)) return 0;
2196 	 error("Read error on sequence file");
2197       }
2198 
2199       in_lin++;
2200 
2201       while (isspace(*lin)) lin++;
2202       p= strchr(lin, '#');
2203       if (p && p[1] == '#') fprintf(stderr, "%s", p);
2204       p= p ? p : strchr(lin, 0);
2205       while (p > lin && isspace(p[-1])) p--;
2206       if (p != lin) break;
2207    }
2208    *p= 0;
2209    lin_copy= buf_copy;
2210    strcpy(lin_copy, lin);
2211    return 1;
2212 }
2213 
2214 //
2215 //	Get next word at '*lin', moving lin onwards, or return 0
2216 //
2217 
2218 char *
getWord()2219 getWord() {
2220   char *rv, *end;
2221   while (isspace(*lin)) lin++;
2222   if (!*lin) return 0;
2223 
2224   rv= lin;
2225   while (*lin && !isspace(*lin)) lin++;
2226   end= lin;
2227   if (*lin) lin++;
2228   *end= 0;
2229 
2230   return rv;
2231 }
2232 
2233 //
2234 //	Bad sequence file
2235 //
2236 
2237 void
badSeq()2238 badSeq() {
2239   error("Bad sequence file content at line: %d\n  %s", in_lin, lin_copy);
2240 }
2241 
2242 // Convenience for situations where buffer is being filled by
2243 // something other than readLine()
2244 void
readNameDef2()2245 readNameDef2() {
2246    lin= buf; lin_copy= buf_copy;
2247    strcpy(lin_copy, lin);
2248    readNameDef();
2249 }
2250 void
readTimeLine2()2251 readTimeLine2() {
2252    lin= buf; lin_copy= buf_copy;
2253    strcpy(lin_copy, lin);
2254    readTimeLine();
2255 }
2256 
2257 // Convenience for creating sequences on the fly
2258 void
formatNameDef(char * fmt,...)2259 formatNameDef(char *fmt, ...) {
2260    va_list ap;
2261    va_start(ap, fmt);
2262    vsnprintf(buf, sizeof(buf), fmt, ap);
2263    readNameDef2();
2264 }
2265 void
formatTimeLine(int tim,char * fmt,...)2266 formatTimeLine(int tim, char *fmt, ...) {
2267    va_list ap;
2268    char *p= buf + sprintf(buf, "%02d:%02d:%02d ", tim/3600, tim/60%60, tim%60);
2269    va_start(ap, fmt);
2270    vsnprintf(p, buf + sizeof(buf) - p, fmt, ap);
2271    readTimeLine2();
2272 }
2273 
2274 //
2275 //	Generate a list of Period structures, based on the tone-specs
2276 //	passed in (ac,av)
2277 //
2278 
2279 void
readSeqImm(int ac,char ** av)2280 readSeqImm(int ac, char **av) {
2281    char *p= buf;
2282 
2283    in_lin= 0;
2284    p += sprintf(p, "immediate:");
2285    while (ac-- > 0) p += sprintf(p, " %s", *av++);
2286    readNameDef2();
2287 
2288    strcpy(buf, "00:00 immediate");
2289    readTimeLine2();
2290 
2291    correctPeriods();
2292 }
2293 
2294 //
2295 //	Read a list of sequence files, and generate a list of Period
2296 //	structures
2297 //
2298 
2299 void
readSeq(int ac,char ** av)2300 readSeq(int ac, char **av) {
2301    // Setup a 'now' value to use for NOW in the sequence file
2302    now= calcNow();
2303 
2304    while (ac-- > 0) {
2305       char *fnam= *av++;
2306       int start= 1;
2307 
2308       in= (0 == strcmp("-", fnam)) ? stdin : fopen(fnam, "r");
2309       if (!in) error("Can't open sequence file: %s", fnam);
2310 
2311       in_lin= 0;
2312 
2313       while (readLine()) {
2314 	 char *p= lin;
2315 
2316 	 // Blank lines
2317 	 if (!*p) continue;
2318 
2319 	 // Look for options
2320 	 if (*p == '-') {
2321 	    if (!start)
2322 	       error("Options are only permitted at start of sequence file:\n  %s", p);
2323 	    handleOptions(p);
2324 	    continue;
2325 	 }
2326 
2327 	 // Check to see if it fits the form of <name>:<white-space>
2328 	 start= 0;
2329 	 if (!isalpha(*p))
2330 	    p= 0;
2331 	 else {
2332 	    while (isalnum(*p) || *p == '_' || *p == '-') p++;
2333 	    if (*p++ != ':' || !isspace(*p))
2334 	       p= 0;
2335 	 }
2336 
2337 	 if (p)
2338 	    readNameDef();
2339 	 else
2340 	    readTimeLine();
2341       }
2342 
2343       if (in != stdin) fclose(in);
2344    }
2345 
2346    correctPeriods();
2347 }
2348 
2349 
2350 //
2351 //	Fill in all the correct information for the Periods, assuming
2352 //	they have just been loaded using readTimeLine()
2353 //
2354 
2355 
2356 void
correctPeriods()2357 correctPeriods() {
2358   // Get times all correct
2359   {
2360     Period *pp= per;
2361     do {
2362       if (pp->fi == -2) {
2363 	pp->tim= pp->nxt->tim;
2364 	pp->fi= -1;
2365       }
2366 
2367       pp= pp->nxt;
2368     } while (pp != per);
2369   }
2370 
2371   // Make sure that the transitional periods each have enough time
2372   {
2373     Period *pp= per;
2374     do {
2375       if (pp->fi == -1) {
2376 	int per= t_per0(pp->tim, pp->nxt->tim);
2377 	if (per < fade_int) {
2378 	  int adj= (fade_int - per) / 2, adj0, adj1;
2379 	  adj0= t_per0(pp->prv->tim, pp->tim);
2380 	  adj0= (adj < adj0) ? adj : adj0;
2381 	  adj1= t_per0(pp->nxt->tim, pp->nxt->nxt->tim);
2382 	  adj1= (adj < adj1) ? adj : adj1;
2383 	  pp->tim= (pp->tim - adj0 + H24) % H24;
2384 	  pp->nxt->tim= (pp->nxt->tim + adj1) % H24;
2385 	}
2386       }
2387 
2388       pp= pp->nxt;
2389     } while (pp != per);
2390   }
2391 
2392   // Fill in all the voice arrays, and sort out details of
2393   // transitional periods
2394   {
2395     Period *pp= per;
2396     do {
2397       if (pp->fi < 0) {
2398 	int fo, fi;
2399 	int a;
2400 	int midpt= 0;
2401 
2402 	Period *qq= (Period*)Alloc(sizeof(*qq));
2403 	qq->prv= pp; qq->nxt= pp->nxt;
2404 	qq->prv->nxt= qq->nxt->prv= qq;
2405 
2406 	qq->tim= t_mid(pp->tim, qq->nxt->tim);
2407 
2408 	memcpy(pp->v0, pp->prv->v1, sizeof(pp->v0));
2409 	memcpy(qq->v1, qq->nxt->v0, sizeof(qq->v1));
2410 
2411 	// Special handling for bells
2412 	for (a= 0; a<N_CH; a++) {
2413 	  if (pp->v0[a].typ == 3 && pp->fi != -3)
2414 	    pp->v0[a].typ= 0;
2415 
2416 	  if (qq->v1[a].typ == 3 && pp->fi == -3)
2417 	    qq->v1[a].typ= 0;
2418 	}
2419 
2420 	fo= pp->prv->fo;
2421 	fi= qq->nxt->fi;
2422 
2423 	// Special handling for -> slides:
2424 	//   always slide, and stretch slide if possible
2425 	if (pp->fi == -3) {
2426 	  fo= fi= 2;		// Force slides for ->
2427 	  for (a= 0; a<N_CH; a++) {
2428 	    Voice *vp= &pp->v0[a];
2429 	    Voice *vq= &qq->v1[a];
2430 	    if (vp->typ == 0 && vq->typ != 0 && vq->typ != 3) {
2431 	      memcpy(vp, vq, sizeof(*vp)); vp->amp= 0;
2432 	    }
2433 	    else if (vp->typ != 0 && vq->typ == 0) {
2434 	      memcpy(vq, vp, sizeof(*vq)); vq->amp= 0;
2435 	    }
2436 	  }
2437 	}
2438 
2439 	memcpy(pp->v1, pp->v0, sizeof(pp->v1));
2440 	memcpy(qq->v0, qq->v1, sizeof(qq->v0));
2441 
2442 	for (a= 0; a<N_CH; a++) {
2443 	  Voice *vp= &pp->v1[a];
2444 	  Voice *vq= &qq->v0[a];
2445 	  if ((fo == 0 || fi == 0) ||		// Fade in/out to silence
2446 	      (vp->typ != vq->typ) ||		// Different types
2447 	      ((fo == 1 || fi == 1) &&		// Fade thru, but different pitches
2448 	       (vp->typ == 1 || vp->typ < 0) &&
2449 	       (vp->carr != vq->carr || vp->res != vq->res))
2450 	      ) {
2451 	    vp->amp= vq->amp= 0;		// To silence
2452 	    midpt= 1;				// Definitely need the mid-point
2453 
2454 	    if (vq->typ == 3) {	 		// Special handling for bells
2455 	      vq->amp= qq->v1[a].amp;
2456 	      qq->nxt->v0[a].typ= qq->nxt->v1[a].typ= 0;
2457 	    }
2458 	  }
2459 	  else if (vp->typ == 3) {		// Else smooth transition - for bells not so smooth
2460 	    qq->v0[a].typ= qq->v1[a].typ= 0;
2461 	  }
2462 	  else {				// Else smooth transition
2463 	    vp->amp= vq->amp= (vp->amp + vq->amp) / 2;
2464 	    if (vp->typ == 1 || vp->typ == 4 || vp->typ < 0) {
2465 	      vp->carr= vq->carr= (vp->carr + vq->carr) / 2;
2466 	      vp->res= vq->res= (vp->res + vq->res) / 2;
2467 	    }
2468 	  }
2469 	}
2470 
2471 	// If we don't really need the mid-point, then get rid of it
2472 	if (!midpt) {
2473 	  memcpy(pp->v1, qq->v1, sizeof(pp->v1));
2474 	  qq->prv->nxt= qq->nxt;
2475 	  qq->nxt->prv= qq->prv;
2476 	  free(qq);
2477 	}
2478 	else pp= qq;
2479       }
2480 
2481       pp= pp->nxt;
2482     } while (pp != per);
2483   }
2484 
2485   // Clear out zero length sections, and duplicate sections
2486   {
2487     Period *pp;
2488     while (per != per->nxt) {
2489       pp= per;
2490       do {
2491 	if (voicesEq(pp->v0, pp->v1) &&
2492 	    voicesEq(pp->v0, pp->nxt->v0) &&
2493 	    voicesEq(pp->v0, pp->nxt->v1))
2494 	  pp->nxt->tim= pp->tim;
2495 
2496 	if (pp->tim == pp->nxt->tim) {
2497 	  if (per == pp) per= per->prv;
2498 	  pp->prv->nxt= pp->nxt;
2499 	  pp->nxt->prv= pp->prv;
2500 	  free(pp);
2501 	  pp= 0;
2502 	  break;
2503 	}
2504 	pp= pp->nxt;
2505       } while (pp != per);
2506       if (pp) break;
2507     }
2508   }
2509 
2510   // Make sure that the total is 24 hours only (not more !)
2511   if (per->nxt != per) {
2512     int tot= 0;
2513     Period *pp= per;
2514 
2515     do {
2516       tot += t_per0(pp->tim, pp->nxt->tim);
2517       pp= pp->nxt;
2518     } while (pp != per);
2519 
2520     if (tot > H24) {
2521       warn("Total time is greater than 24 hours.  Probably two times are\n"
2522 	   "out of order.  Suspicious intervals are:\n");
2523       pp= per;
2524       do {
2525 	if (t_per0(pp->tim, pp->nxt->tim) >= H12)
2526 	   warn("  %02d:%02d:%02d -> %02d:%02d:%02d",
2527 		pp->tim % 86400000 / 3600000,
2528 		pp->tim % 3600000 / 60000,
2529 		pp->tim % 60000 / 1000,
2530 		pp->nxt->tim % 86400000 / 3600000,
2531 		pp->nxt->tim % 3600000 / 60000,
2532 		pp->nxt->tim % 60000 / 1000);
2533 	pp= pp->nxt;
2534       } while (pp != per);
2535       error("\nCheck the sequence around these times and try again");
2536     }
2537   }
2538 
2539   // Print the whole lot out
2540   if (opt_D) {
2541     Period *pp;
2542     if (per->nxt != per)
2543       while (per->prv->tim < per->tim) per= per->nxt;
2544 
2545     pp= per;
2546     do {
2547       dispCurrPer(stdout);
2548       per= per->nxt;
2549     } while (per != pp);
2550     printf("\n");
2551 
2552     exit(0);		// All done
2553   }
2554 }
2555 
2556 int
voicesEq(Voice * v0,Voice * v1)2557 voicesEq(Voice *v0, Voice *v1) {
2558   int a= N_CH;
2559 
2560   while (a-- > 0) {
2561     if (v0->typ != v1->typ) return 0;
2562     switch (v0->typ) {
2563      case 1:
2564      case 4:
2565      default:
2566        if (v0->amp != v1->amp ||
2567 	   v0->carr != v1->carr ||
2568 	   v0->res != v1->res)
2569 	 return 0;
2570        break;
2571      case 2:
2572      case 5:
2573        if (v0->amp != v1->amp)
2574 	 return 0;
2575        break;
2576      case 3:
2577        if (v0->amp != v1->amp ||
2578 	   v0->carr != v1->carr)
2579 	 return 0;
2580        break;
2581     }
2582     v0++; v1++;
2583   }
2584   return 1;
2585 }
2586 
2587 //
2588 //	Read a name definition
2589 //
2590 
2591 void
readNameDef()2592 readNameDef() {
2593   char *p, *q;
2594   NameDef *nd;
2595   int ch;
2596 
2597   if (!(p= getWord())) badSeq();
2598 
2599   q= strchr(p, 0) - 1;
2600   if (*q != ':') badSeq();
2601   *q= 0;
2602   for (q= p; *q; q++) if (!isalnum(*q) && *q != '-' && *q != '_')
2603     error("Bad name \"%s\" in definition, line %d:\n  %s", p, in_lin, lin_copy);
2604 
2605   // Waveform definition ?
2606   if (0 == memcmp(p, "wave", 4) &&
2607       isdigit(p[4]) &&
2608       isdigit(p[5]) &&
2609       !p[6]) {
2610      int ii= (p[4] - '0') * 10 + (p[5] - '0');
2611      int siz= ST_SIZ * sizeof(int);
2612      int *arr= (int*)Alloc(siz);
2613      double *dp0= (double*)arr;
2614      double *dp1= (double*)(siz + (char*)arr);
2615      double *dp= dp0;
2616      double dmax= 0, dmin= 1;
2617      int np;
2618 
2619      if (waves[ii])
2620 	error("Waveform %02d already defined, line %d:\n  %s",
2621 	      ii, in_lin, lin_copy);
2622      waves[ii]= arr;
2623 
2624      while ((p= getWord())) {
2625 	double dd;
2626 	char dmy;
2627 	if (1 != sscanf(p, "%lf %c", &dd, &dmy))
2628 	   error("Expecting floating-point numbers on this waveform "
2629 		 "definition line, line %d:\n  %s",
2630 		 in_lin, lin_copy);
2631 	if (dp >= dp1)
2632 	   error("Too many samples on line (maximum %d), line %d:\n  %s",
2633 		 dp1-dp0, in_lin, lin_copy);
2634 	*dp++= dd;
2635 	if (dmax < dmin) dmin= dmax= dd;
2636 	else {
2637 	   if (dd > dmax) dmax= dd;
2638 	   if (dd < dmin) dmin= dd;
2639 	}
2640      }
2641      dp1= dp;
2642      np= dp1 - dp0;
2643      if (np < 2)
2644 	error("Expecting at least two samples in the waveform, line %d:\n  %s",
2645 	      in_lin, lin_copy);
2646 
2647      // Adjust to range 0-1
2648      for (dp= dp0; dp < dp1; dp++)
2649 	*dp= (*dp - dmin) / (dmax - dmin);
2650 
2651      sinc_interpolate(dp0, np, arr);
2652 
2653      if (DEBUG_DUMP_WAVES) {
2654 	int a;
2655 	printf("Dumping wave%02d:\n", ii);
2656 	for (a= 0; a<ST_SIZ; a++)
2657 	   printf("%d %g\n", a, arr[a] * 1.0 / ST_AMP);
2658      }
2659      return;
2660   }
2661 
2662   // Must be block or tone-set, then, so put into a NameDef
2663   nd= (NameDef*)Alloc(sizeof(NameDef));
2664   nd->name= StrDup(p);
2665 
2666   // Block definition ?
2667   if (*lin == '{') {
2668     BlockDef *bd, **prvp;
2669     if (!(p= getWord()) ||
2670 	0 != strcmp(p, "{") ||
2671 	0 != (p= getWord()))
2672       badSeq();
2673 
2674     prvp= &nd->blk;
2675 
2676     while (readLine()) {
2677       if (*lin == '}') {
2678 	if (!(p= getWord()) ||
2679 	    0 != strcmp(p, "}") ||
2680 	    0 != (p= getWord()))
2681 	  badSeq();
2682 	if (!nd->blk) error("Empty blocks not permitted, line %d:\n  %s", in_lin, lin_copy);
2683 	nd->nxt= nlist; nlist= nd;
2684 	return;
2685       }
2686 
2687       if (*lin != '+')
2688 	error("All lines in the block must have relative time, line %d:\n  %s",
2689 	      in_lin, lin_copy);
2690 
2691       bd= (BlockDef*) Alloc(sizeof(*bd));
2692       *prvp= bd; prvp= &bd->nxt;
2693       bd->lin= StrDup(lin);
2694     }
2695 
2696     // Hit EOF before }
2697     error("End-of-file within block definition (missing '}')");
2698   }
2699 
2700   // Normal line-definition
2701   for (ch= 0; ch < N_CH && (p= getWord()); ch++) {
2702     char dmy;
2703     double amp, carr, res;
2704     int wave;
2705 
2706     // Interpret word into Voice nd->vv[ch]
2707     if (0 == strcmp(p, "-")) continue;
2708     if (1 == sscanf(p, "pink/%lf %c", &amp, &dmy)) {
2709        nd->vv[ch].typ= 2;
2710        nd->vv[ch].amp= AMP_DA(amp);
2711        continue;
2712     }
2713     if (2 == sscanf(p, "bell%lf/%lf %c", &carr, &amp, &dmy)) {
2714        nd->vv[ch].typ= 3;
2715        nd->vv[ch].carr= carr;
2716        nd->vv[ch].amp= AMP_DA(amp);
2717        continue;
2718     }
2719     if (1 == sscanf(p, "mix/%lf %c", &amp, &dmy)) {
2720        nd->vv[ch].typ= 5;
2721        nd->vv[ch].amp= AMP_DA(amp);
2722        mix_flag= 1;
2723        continue;
2724     }
2725     if (4 == sscanf(p, "wave%d:%lf%lf/%lf %c", &wave, &carr, &res, &amp, &dmy)) {
2726        if (wave < 0 || wave >= 100)
2727 	  error("Only wave00 to wave99 is permitted at line: %d\n  %s", in_lin, lin_copy);
2728        if (!waves[wave])
2729 	  error("Waveform %02d has not been defined, line: %d\n  %s", wave, in_lin, lin_copy);
2730        nd->vv[ch].typ= -1-wave;
2731        nd->vv[ch].carr= carr;
2732        nd->vv[ch].res= res;
2733        nd->vv[ch].amp= AMP_DA(amp);
2734        continue;
2735     }
2736     if (3 == sscanf(p, "%lf%lf/%lf %c", &carr, &res, &amp, &dmy)) {
2737       nd->vv[ch].typ= 1;
2738       nd->vv[ch].carr= carr;
2739       nd->vv[ch].res= res;
2740       nd->vv[ch].amp= AMP_DA(amp);
2741       continue;
2742     }
2743     if (2 == sscanf(p, "%lf/%lf %c", &carr, &amp, &dmy)) {
2744       nd->vv[ch].typ= 1;
2745       nd->vv[ch].carr= carr;
2746       nd->vv[ch].res= 0;
2747       nd->vv[ch].amp= AMP_DA(amp);
2748       continue;
2749     }
2750     if (3 == sscanf(p, "spin:%lf%lf/%lf %c", &carr, &res, &amp, &dmy)) {
2751       nd->vv[ch].typ= 4;
2752       nd->vv[ch].carr= carr;
2753       nd->vv[ch].res= res;
2754       nd->vv[ch].amp= AMP_DA(amp);
2755       continue;
2756     }
2757     badSeq();
2758   }
2759   nd->nxt= nlist; nlist= nd;
2760 }
2761 
2762 //
2763 //	Bad time
2764 //
2765 
2766 void
badTime(char * tim)2767 badTime(char *tim) {
2768   error("Badly constructed time \"%s\", line %d:\n  %s", tim, in_lin, lin_copy);
2769 }
2770 
2771 //
2772 //	Read a time-line of either type
2773 //
2774 
2775 void
readTimeLine()2776 readTimeLine() {
2777   char *p, *tim_p;
2778   int nn;
2779   int fo, fi;
2780   Period *pp;
2781   NameDef *nd;
2782   static int last_abs_time= -1;
2783   int tim, rtim = 0;
2784 
2785   if (!(p= getWord())) badSeq();
2786   tim_p= p;
2787 
2788   // Read the time represented
2789   tim= -1;
2790   if (0 == memcmp(p, "NOW", 3)) {
2791     last_abs_time= tim= now;
2792     p += 3;
2793   }
2794 
2795   while (*p) {
2796     if (*p == '+') {
2797       if (tim < 0) {
2798 	if (last_abs_time < 0)
2799 	  error("Relative time without previous absolute time, line %d:\n  %s", in_lin, lin_copy);
2800 	tim= last_abs_time;
2801       }
2802       p++;
2803     }
2804     else if (tim != -1) badTime(tim_p);
2805 
2806     if (0 == (nn= readTime(p, &rtim))) badTime(tim_p);
2807     p += nn;
2808 
2809     if (tim == -1)
2810       last_abs_time= tim= rtim;
2811     else
2812       tim= (tim + rtim) % H24;
2813   }
2814 
2815   if (fast_tim0 < 0) fast_tim0= tim;		// First time
2816   fast_tim1= tim;				// Last time
2817 
2818   if (!(p= getWord())) badSeq();
2819 
2820   fi= fo= 1;
2821   if (!isalpha(*p)) {
2822     switch (p[0]) {
2823      case '<': fi= 0; break;
2824      case '-': fi= 1; break;
2825      case '=': fi= 2; break;
2826      default: badSeq();
2827     }
2828     switch (p[1]) {
2829      case '>': fo= 0; break;
2830      case '-': fo= 1; break;
2831      case '=': fo= 2; break;
2832      default: badSeq();
2833     }
2834     if (p[2]) badSeq();
2835 
2836     if (!(p= getWord())) badSeq();
2837   }
2838 
2839   for (nd= nlist; nd && 0 != strcmp(p, nd->name); nd= nd->nxt) ;
2840   if (!nd) error("Name \"%s\" not defined, line %d:\n  %s", p, in_lin, lin_copy);
2841 
2842   // Check for block name-def
2843   if (nd->blk) {
2844     char *prep= StrDup(tim_p);		// Put this at the start of each line
2845     BlockDef *bd= nd->blk;
2846 
2847     while (bd) {
2848       lin= buf; lin_copy= buf_copy;
2849       sprintf(lin, "%s%s", prep, bd->lin);
2850       strcpy(lin_copy, lin);
2851       readTimeLine();		// This may recurse, and that's why we're StrDuping the string
2852       bd= bd->nxt;
2853     }
2854     free(prep);
2855     return;
2856   }
2857 
2858   // Normal name-def
2859   pp= (Period*)Alloc(sizeof(*pp));
2860   pp->tim= tim;
2861   pp->fi= fi;
2862   pp->fo= fo;
2863 
2864   memcpy(pp->v0, nd->vv, N_CH * sizeof(Voice));
2865   memcpy(pp->v1, nd->vv, N_CH * sizeof(Voice));
2866 
2867   if (!per)
2868     per= pp->nxt= pp->prv= pp;
2869   else {
2870     pp->nxt= per; pp->prv= per->prv;
2871     pp->prv->nxt= pp->nxt->prv= pp;
2872   }
2873 
2874   // Automatically add a transitional period
2875   pp= (Period*)Alloc(sizeof(*pp));
2876   pp->fi= -2;		// Unspecified transition
2877   pp->nxt= per; pp->prv= per->prv;
2878   pp->prv->nxt= pp->nxt->prv= pp;
2879 
2880   if (0 != (p= getWord())) {
2881     if (0 != strcmp(p, "->")) badSeq();
2882     pp->fi= -3;		// Special '->' transition
2883     pp->tim= tim;
2884   }
2885 }
2886 
2887 int
readTime(char * p,int * timp)2888 readTime(char *p, int *timp) {		// Rets chars consumed, or 0 error
2889   int nn, hh, mm, ss;
2890 
2891   if (3 > sscanf(p, "%2d:%2d:%2d%n", &hh, &mm, &ss, &nn)) {
2892     ss= 0;
2893     if (2 > sscanf(p, "%2d:%2d%n", &hh, &mm, &nn)) return 0;
2894   }
2895 
2896   if (hh < 0 || hh >= 24 ||
2897       mm < 0 || mm >= 60 ||
2898       ss < 0 || ss >= 60) return 0;
2899 
2900   *timp= ((hh * 60 + mm) * 60 + ss) * 1000;
2901   return nn;
2902 }
2903 
2904 //
2905 //	Takes a set of points and repeats them twice, inverting the
2906 //	second set, and then interpolates them using a periodic sinc
2907 //	function (see http://www-ccrma.stanford.edu/~jos/resample/)
2908 //	and writes them to arr[] in the same format as the sin_table[].
2909 //
2910 
sinc_interpolate(double * dp,int np,int * arr)2911 void sinc_interpolate(double *dp, int np, int *arr) {
2912    double *sinc;	// Temporary sinc-table
2913    double *out;		// Temporary output table
2914    int a, b;
2915    double dmax, dmin;
2916    double adj, off;
2917 
2918    // Generate a modified periodic sin(x)/x function to be used for
2919    // each of the points.  Really this should be sin(x)/x modified
2920    // by the sum of an endless series.  However, this doesn't
2921    // converge very quickly, so to save time I'm approximating this
2922    // series by 1-4*t*t where t ranges from 0 to 0.5 over the first
2923    // half of the periodic cycle.  If you do the maths, this is at
2924    // most 5% out.  This will have to do - it's smooth, and I don't
2925    // know enough maths to make this series converge quicker.
2926    sinc= (double *)Alloc(ST_SIZ * sizeof(double));
2927    sinc[0]= 1.0;
2928    for (a= ST_SIZ/2; a>0; a--) {
2929       double tt= a * 1.0 / ST_SIZ;
2930       double t2= tt*tt;
2931       double adj= 1 - 4 * t2;
2932       double xx= 2 * np * 3.14159265358979323846 * tt;
2933       double vv= adj * sin(xx) / xx;
2934       sinc[a]= vv;
2935       sinc[ST_SIZ-a]= vv;
2936    }
2937 
2938    // Build waveform into buffer
2939    out= (double *)Alloc(ST_SIZ * sizeof(double));
2940    for (b= 0; b<np; b++) {
2941       int off= b * ST_SIZ / np / 2;
2942       double val= dp[b];
2943       for (a= 0; a<ST_SIZ; a++) {
2944 	 out[(a + off)&(ST_SIZ-1)] += sinc[a] * val;
2945 	 out[(a + off + ST_SIZ/2)&(ST_SIZ-1)] -= sinc[a] * val;
2946       }
2947    }
2948 
2949    // Look for maximum for normalization
2950    dmax= dmin= 0;
2951    for (a= 0; a<ST_SIZ; a++) {
2952       if (out[a] > dmax) dmax= out[a];
2953       if (out[a] < dmin) dmin= out[a];
2954    }
2955 
2956    // Write out to output buffer
2957    off= -0.5 * (dmax + dmin);
2958    adj= ST_AMP / ((dmax - dmin) / 2);
2959    for (a= 0; a<ST_SIZ; a++)
2960       arr[a]= (int)((out[a] + off) * adj);
2961 
2962    free(sinc);
2963    free(out);
2964 }
2965 
2966 //
2967 //	Handling pre-programmed sequences
2968 //
2969 
2970 void
readPreProg(int ac,char ** av)2971 readPreProg(int ac, char **av) {
2972    if (ac < 1)
2973       error("Expecting a pre-programmed sequence description.  Examples:"
2974 	    NL "  drop 25ds+ pink/30"
2975 	    NL "  drop 25gs+/2 mix/60"
2976 	    );
2977 
2978    // Handle 'drop'
2979    if (0 == strcmp(av[0], "drop")) {
2980       ac--; av++;
2981       create_drop(ac, av);
2982       return;
2983    }
2984 
2985    // Handle 'slide'
2986    if (0 == strcmp(av[0], "slide")) {
2987       ac--; av++;
2988       create_slide(ac, av);
2989       return;
2990    }
2991 
2992    error("Unknown pre-programmed sequence type: %s", av[0]);
2993 }
2994 
2995 //
2996 //	Error for bad p-drop args
2997 //
2998 
2999 void
bad_drop()3000 bad_drop() {
3001    error("Bad arguments: expecting -p drop [<time-spec>] <drop-spec> [<tone-specs...>]"
3002 	 NL "<drop-spec> is <digit><digit>[.<digit>...]<a-l>[s|k][+][^][/<amp>]"
3003 	 NL "The optional <time-spec> is t<drop-time>,<hold-time>,<wake-time>, all times"
3004 	 NL "  in minutes (the default is equivalent to 't30,30,3')."
3005 	 NL "The optional <tone-specs...> let you mix other stuff with the drop"
3006 	 NL "  sequence like pink noise or a mix soundtrack, e.g 'pink/20' or 'mix/60'");
3007 }
3008 
3009 //
3010 //	Generate a p-drop sequence
3011 //
3012 //	Credits: Jonathan Bisson created the first version of this C
3013 //	code.  This is a rewrite to make it fit with the rest of the
3014 //	code better.
3015 //
3016 
3017 void
create_drop(int ac,char ** av)3018 create_drop(int ac, char **av) {
3019    char *fmt;
3020    char *p, *q;
3021    int a;
3022    int slide, n_step, islong, wakeup;
3023    double carr, amp, c0, c2;
3024    double beat_target;
3025    double beat[40];
3026    static double beat_targets[]= {
3027       4.4, 3.7, 3.1, 2.5, 2.0, 1.5, 1.2, 0.9, 0.7, 0.5, 0.4, 0.3
3028    };
3029    char extra[256];
3030    int len, len0= 1800, len1= 1800, len2= 180;
3031    int steplen, end;
3032 
3033 #define BAD bad_drop()
3034 
3035    // Pick up optional time-spec
3036    if (ac < 1) BAD;
3037    if (av[0][0] == 't') {
3038       double v0, v1, v2;
3039       char dmy;
3040       if (3 != sscanf(av[0]+1, "%lf,%lf,%lf %c", &v0, &v1, &v2, &dmy)) BAD;
3041       len0= 60 * (int)v0;	// Whole minutes only
3042       len1= 60 * (int)v1;
3043       len2= 60 * (int)v2;
3044       ac--; av++;
3045    }
3046 
3047    // Handle argument list
3048    if (ac < 1) BAD;
3049    fmt= *av++; ac--;
3050    p= extra; *p= 0;
3051    while (ac > 0) {
3052       if (p + strlen(av[0]) + 2 > extra + sizeof(extra))
3053 	 error("Too many extra tone-specs after -p drop");
3054       p += sprintf(p, " %s", av[0]);
3055       ac--; av++;
3056    }
3057 
3058    // Scan the format
3059    carr= 200 - 2 * strtod(fmt, &p);
3060    if (p == fmt || carr < 0) BAD;
3061 
3062    a= tolower(*p) - 'a'; p++;
3063    if (a < 0 || a >= sizeof(beat_targets) / sizeof(beat_targets[0])) BAD;
3064    beat_target= beat_targets[a];
3065 
3066    slide= 0;
3067    steplen= 180;
3068    if (*p == 's') { p++; slide= 1; steplen= 60; }
3069    else if (*p == 'k') { p++; steplen= 60; }
3070    n_step= 1 + (len0-1) / steplen;	// Round up
3071    len0= n_step * steplen;
3072    if (!slide) len1= (1 + (len1-1) / steplen) * steplen;
3073 
3074    islong= 0;
3075    if (*p == '+') { islong= 1; p++; }
3076 
3077    wakeup= 0;
3078    if (*p == '^') { wakeup= 1; p++; }
3079 
3080    amp= 1.0;
3081    if (*p == '/') {
3082       p++; q= p;
3083       amp= strtod(p, &p);
3084       if (p == q) BAD;
3085    }
3086 
3087    while (isspace(*p)) p++;
3088    if (*p) error("Trailing rubbish after -p drop spec: \"%s\"", p);
3089 
3090 #undef BAD
3091 
3092    // Sort out carriers
3093    len= islong ? len0 + len1 : len0;
3094    c0= carr + 5.0;
3095    c2= carr;
3096 
3097    // Calculate beats
3098    for (a= 0; a<n_step; a++)
3099       beat[a]= 10 * exp(log(beat_target/10) * a / (n_step-1));
3100 
3101    // Display summary
3102    warn("DROP summary:");
3103    if (slide) {
3104       warn(" Carrier slides from %gHz to %gHz over %d minutes",
3105 	   c0, c2, len/60);
3106       warn(" Beat frequency slides from %gHz to %gHz over %d minutes",
3107 	   beat[0], beat[n_step-1], len0/60);
3108    } else {
3109       warn(" Carrier steps from %gHz to %gHz over %d minutes",
3110 	   c0, c2, len/60);
3111       warn(" Beat frequency steps from %gHz to %gHz over %d minutes:",
3112 	   beat[0], beat[n_step-1], len0/60);
3113       fprintf(stderr, "   ");
3114       for (a= 0; a<n_step; a++) fprintf(stderr, " %.2f", beat[a]);
3115       fprintf(stderr, "\n");
3116    }
3117    if (wakeup) {
3118       warn(" Final wake-up of %d minutes, to return to initial frequencies", len2/60);
3119    }
3120 
3121    // Start generating sequence
3122    handleOptions("-SE");
3123    in_lin= 0;
3124 
3125    formatNameDef("off: -");
3126    formatTimeLine(86395, "== off ->");		// 23:59:55
3127 
3128    if (slide) {
3129       // Slide version
3130       for (a= 0; a<n_step; a++) {
3131 	 int tim= a * len0 / (n_step-1);
3132 	 formatNameDef("ts%02d: %g+%g/%g %s", a,
3133 		       c0 + (c2-c0) * tim * 1.0 / len,
3134 		       beat[a], amp, extra);
3135 	 formatTimeLine(tim, "== ts%02d ->", a);
3136       }
3137 
3138       if (islong) {
3139 	 formatNameDef("tsend: %g+%g/%g %s",
3140 		       c2, beat[n_step-1], amp, extra);
3141 	 formatTimeLine(len, "== tsend ->");
3142       }
3143       end= len;
3144    } else {
3145       // Step version
3146       int lim= len / steplen;
3147       int stepslide= steplen < 90 ? 5 : 10;    // Seconds slide between steps
3148       for (a= 0; a<lim; a++) {
3149 	 int tim0= a * steplen;
3150 	 int tim1= (a+1) * steplen;
3151 	 formatNameDef("ts%02d: %g+%g/%g %s", a,
3152 		       c0 + (c2-c0) * tim1/len,
3153 		       beat[(a>=n_step) ? n_step-1 : a],
3154 		       amp, extra);
3155 	 formatTimeLine(tim0, "== ts%02d ->", a);
3156 	 formatTimeLine(tim1-stepslide, "== ts%02d ->", a);
3157       }
3158       end= len-stepslide;
3159    }
3160 
3161    // Wake-up and ending
3162    if (wakeup) {
3163       formatNameDef("tswake: %g+%g/%g %s",
3164 		    c0, beat[0], amp, extra);
3165       formatTimeLine(end+len2, "== tswake ->");
3166       end += len2;
3167    }
3168    formatTimeLine(end+10, "== off");
3169 
3170    correctPeriods();
3171 }
3172 
3173 //
3174 //	Generate a -p slide sequence
3175 //
3176 //	The idea of this is to hold the beat frequency constant, but
3177 //	to slide down through the carrier frequencies from about 200Hz.
3178 //
3179 //	-p slide [t<duration-minutes>] <carr>+<beat>/<amp> [extra tone-sets]
3180 
3181 void
bad_slide()3182 bad_slide() {
3183    error("Bad arguments: expecting -p slide [<time-spec>] <slide-spec> [<tone-specs...>]"
3184 	 NL "<slide-spec> is just like a tone-spec: <carrier><sign><beat>/<amp>"
3185 	 NL "The optional <time-spec> is t<slide-time>, giving length of session in"
3186 	 NL "  minutes (the default is equivalent to 't30')."
3187 	 NL "The optional <tone-specs...> let you mix other stuff with the drop"
3188 	 NL "  sequence like pink noise or a mix soundtrack, e.g 'pink/20' or 'mix/60'");
3189 }
3190 
3191 void
create_slide(int ac,char ** av)3192 create_slide(int ac, char **av) {
3193    int len= 1800;
3194    char *p, dmy;
3195    double val, c0, c1, beat, amp;
3196    char extra[256];
3197 
3198 #define BAD bad_slide()
3199 
3200    // Handle arguments
3201    if (ac < 1) BAD;
3202    if (av[0][0] == 't') {
3203       val= strtod(av[0]+1, &p);
3204       if (p == av[0] + 1 || *p) BAD;
3205       len= 60.0 * val;
3206       ac--; av++;
3207    }
3208 
3209    if (ac < 1) BAD;
3210    if (3 != sscanf(av[0], "%lf%lf/%lf %c", &c0, &beat, &amp, &dmy)) BAD;
3211    c1= beat/2;
3212    ac--; av++;
3213 
3214 #undef BAD
3215 
3216    // Gather 'extra'
3217    p= extra; *p= 0;
3218    while (ac > 0) {
3219       if (p + strlen(av[0]) + 2 > extra + sizeof(extra))
3220 	 error("Too many extra tone-specs after -p slide");
3221       p += sprintf(p, " %s", av[0]);
3222       ac--; av++;
3223    }
3224 
3225    // Summary
3226    warn("SLIDE summary:");
3227    warn(" Sliding carrier from %gHz to %gHz over %g minutes",
3228 	c0, c1, len/60.0);
3229    warn(" Holding beat constant at %gHz", beat);
3230 
3231    // Generate sequence
3232    handleOptions("-SE");
3233    in_lin= 0;
3234 
3235    formatNameDef("off: -");
3236    formatTimeLine(86395, "== off ->");		// 23:59:55
3237    formatNameDef("ts0: %g%+g/%g %s", c0, beat, amp, extra);
3238    formatTimeLine(0, "== ts0 ->");
3239    formatNameDef("ts1: %g%+g/%g %s", c1, beat, amp, extra);
3240    formatTimeLine(len, "== ts1 ->");
3241    formatTimeLine(len+10, "== off");
3242 
3243    correctPeriods();
3244 }
3245 
3246 
3247 // END //
3248