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= &adj[a-1];
1635 p1= &adj[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", &, &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, &, &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", &, &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, &, &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, &, &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, &, &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, &, &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, &, &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