1 //
2 //	OGG decoding using Tremor (libvorbisidec), with optional
3 //	looping.
4 //
5 //        (c) 1999-2004 Jim Peters <jim@uazu.net>.  All Rights Reserved.
6 //        For latest version see http://sbagen.sf.net/ or
7 //        http://uazu.net/sbagen/.  Released under the GNU GPL version 2.
8 //
9 //	See comments lower down for OGG looper parameters.
10 //
11 
12 #include "libs/ivorbiscodec.h"
13 #include "libs/ivorbisfile.h"
14 
15 extern FILE *mix_in;
16 extern int mix_cnt;
17 extern void *Alloc(size_t);
18 extern void error(char *fmt, ...);
19 extern int out_rate, out_rate_def;
20 
21 void ogg_init() ;
22 void ogg_term() ;
23 int ogg_read(int *dst, int dlen) ;
24 void looper_init() ;
25 void looper_term() ;
26 int looper_read(int *dst, int dlen) ;
27 static void looper_sched() ;
28 static void looper_sched2() ;
29 
30 static OggVorbis_File oggfile;
31 static short *ogg_buf0, *ogg_buf1, *ogg_rd, *ogg_end;
32 static int ogg_mult;
33 
34 void
35 ogg_init() {
36    vorbis_info *vi;
37    vorbis_comment *vc;
38    int len= 2048;
39    int a;
40 
41    // Setup OGG decoder
42    if (0 > ov_open(mix_in, &oggfile, NULL, 0))
43       error("Input does not appear to be an Ogg bitstream");
44 
45    // Check for ReplayGain
46    vc= ov_comment(&oggfile, -1);
47    ogg_mult= 16;
48    for (a= 0; a<vc->comments; a++) {
49       char *str= vc->user_comments[a];
50       if (0 == memcmp(str, "REPLAYGAIN_TRACK_GAIN=", 22)) {
51 	 char *end;
52 	 double val= strtod(str += 22, &end);
53 	 if (end == str)
54 	    warn("Ignoring bad REPLAYGAIN_TRACK_GAIN: %s", str);
55 	 else {
56 	    val -= 3;		// Adjust vorbisgain's 89dB to 86dB
57 	    ogg_mult= (int)(floor(0.5 + 16 * pow(10, val/20)));
58 	    warn("ReplayGain setting detected, Ogg scaling by %.2f", ogg_mult/16.0);
59 	 }
60       }
61    }
62 
63    // Check to see is this is a looping OGG
64    for (a= 0; a<vc->comments; a++) {
65       if (0 == memcmp(vc->user_comments[a], "SBAGEN_LOOPER=", 14)) {
66 	 vc= 0; break;
67       }
68    }
69    if (!vc) {
70       // This is a looping OGG.  Load the OGG into memory instead;
71       // handle with looper_* code.  ov_clear is called after because
72       // it closes mix_in.
73       looper_init();
74       ov_clear(&oggfile);
75       return;
76    }
77 
78    // Pick up sampling rate and override default if -r not used
79    vi= ov_info(&oggfile, -1);
80    if (out_rate_def) out_rate= vi->rate;
81    out_rate_def= 0;
82 
83    // Setup buffer so that we can be consistent in our calls to ov_read
84    ogg_buf0= ALLOC_ARR(len, short);
85    ogg_buf1= ogg_buf0 + len;
86    ogg_rd= ogg_end= ogg_buf0;
87 
88    // Start a thread to handle generation of the mix stream
89    inbuf_start(ogg_read, 256*1024);	// 1024K buffer: 3s@44.1kHz
90 }
91 
92 void
93 ogg_term() {
94    ov_clear(&oggfile);
95    if (ogg_buf0) { free(ogg_buf0); ogg_buf0= 0; }
96    looper_term();
97 }
98 
99 int
100 ogg_read(int *dst, int dlen) {
101    int *dst0= dst;
102    int *dst1= dst + dlen;
103 
104    while (dst < dst1) {
bits_of(const OnigCodePoint c,const int n)105       int rv, sect;
106 
107       // Copy data from buffer
108       if (ogg_rd != ogg_end) {
109 	 while (ogg_rd != ogg_end && dst != dst1)
110 	    *dst++= *ogg_rd++ * ogg_mult;
bits_at(const OnigCodePoint * c,const int n)111 	 continue;
112       }
113 
114       // Refill buffer
115       rv= ov_read(&oggfile, (char*)ogg_buf0, (ogg_buf1-ogg_buf0)*sizeof(short), &sect);
116       //debug("ov_read %d/%d", rv, (ogg_buf1-ogg_buf0)*sizeof(short));
code1_equal(const OnigCodePoint x,const OnigCodePoint y)117       if (rv < 0) {
118 	 warn("Recoverable error in Ogg stream  ");
119 	 continue;
120       }
121       if (rv == 0) 	// EOF
122 	 return dst-dst0;
123       if (rv & 3)
code2_equal(const OnigCodePoint * x,const OnigCodePoint * y)124 	 error("UNEXPECTED: ov_read() returned a partial sample count: %d", rv);
125       ogg_rd= ogg_buf0;
126       ogg_end= ogg_buf0 + (rv/2);
127    }
128    return dst-dst0;
129 }
130 
131 //
code3_equal(const OnigCodePoint * x,const OnigCodePoint * y)132 //	Looping OGG decoding using Tremor (libvorbisidec)
133 //
134 //        (c) 1999-2004 Jim Peters <jim@uazu.net>.  All Rights Reserved.
135 //        For latest version see http://sbagen.sf.net/ or
136 //        http://uazu.net/sbagen/.  Released under the GNU GPL version 2.
137 //
138 //	This code preloads the OGG file into memory, and loops and
139 //	cross-fades the audio in segments to provide an endless output
140 //	stream.
141 //
142 //	The type of cross-fading and looping for any particular OGG
143 //	file is controlled by a spec-string embedded in the file with
144 //	the tag "SBAGEN_LOOPER".  This may be set using the standard
145 //	OGG 'vorbiscomment' tool, for example:
146 //
147 //	  vorbiscomment -a -t "SBAGEN_LOOPER=s4-16 f0.2" in.ogg out.ogg
148 //
149 //	The tag contains entries as follows, optionally separated by
150 //	white space:
151 //
152 //	  s<dur>	Set segment size to given duration in seconds
153 //	  s<min>-<max>	Set segment size to randomly vary within given range
154 //	  f<dur>	Set duration for cross-fades
155 //	  c<cnt>	Number of channels: 1 or 2
156 //	  w<bool>	Swap stereo on second channel? 0 no, or 1 yes
157 //	  d<min>-<max>	Set part of OGG file data to use as source audio (in seconds)
158 //	  #<digits>	Following settings apply only to section <digits>
159 //
160 //	The default is something like "s99999999f1c1w1d0-99999999",
161 //	i.e. segments the full length of the audio, taken out of the
162 //	whole of the audio file, repeated forever with a 1 second
163 //	cross-fade at start/end.
164 //
165 //	The # part works as follows.  The .ogg filename on the command
166 //	line may be followed by #<digits>.  If this is missing, it is
167 //	equivalent to #0.  This allows different groups of settings to
168 //	be selected out of the SBAGEN_LOOPER string.  As an example
169 //	(spaced to make it more readable):
170 //
171 //	  SBAGEN_LOOPER=s4-16  #0 f0.2  #1 f0.5  #2 f1
172 //
173 //	The initial part is read in all cases, and then the #0, #1 and
174 //	#2 select different cross-fade times.
175 //
176 
177 static char *data;	// OGG data
178 static char *data_end;	// OGG data end +1
179 static int datlen;	// Length of OGG data in bytes (data_end-data)
180 static int datcnt;	// Length of OGG data in samples
181 static int datcnt0;	// Original datcnt value, before 'd' modifications
onigenc_unicode_is_code_ctype(OnigCodePoint code,unsigned int ctype,OnigEncoding enc ARG_UNUSED)182 static int datbase;	// Base sample offset for seeking
183 static int datrate;	// Sampling rate of file, even if the output rate has been overridden
184 
185 static int fade_cnt;	// Count for fade-in or fade-out in samples
186 static int seg0, seg1;	// Segment size range in samples (min/max) including fade in/out
187 static int ch2;		// Channel 2 mode: 0 off, 1 on
188 static int ch2_swap;	// Channel 2 swapped-stereo?  0 off, 1 on
189 static uint del_amp;	// Fade in/out delta in amplitude per sample
190 
191 typedef struct {
192    OggVorbis_File ogg;	// File
193    char *rd;		// Current read position in 'data'
194    int off;		// Sample-offset that we started playing at for this segment
195    int chan;		// Which channel do we below to?  0 or 1; if 1 then ch2_swap applies
196    int mode;		// Current mode: 0 inactive, 1 waiting, 2 fade-in, 3 hold, 4 fade-out
197    int cnt;		// Current count-down
198    int cnt_all;		// Total sample count for fade-in/hold/fade-out
199    uint amp;		// Current amplitude 0-0xFFFFFFFF
200    uint del;		// Current amplitude delta (i.e. increment)
onigenc_unicode_ctype_code_range(int ctype,const OnigCodePoint * ranges[])201    short *buf0, *buf1;	// Buffer for samples, buf0 to buf1-1
202    short *b_rd, *b_end;	// Buffer read position, end pos +1
203 } AStream;
204 AStream str[3];	// Three read streams from the data
205 
206 // Simple/crude 16-bit pseudo-random number generator, from ZX Spectrum
207 static unsigned short zxrand_seed;	// Current random seed
208 static int
209 zxrand_0_65536() {
210    zxrand_seed= (1 + (int)zxrand_seed) * 75 % 65537 - 1;
211    return zxrand_seed;
212 }
onigenc_utf16_32_get_ctype_code_range(OnigCtype ctype,OnigCodePoint * sb_out,const OnigCodePoint * ranges[],OnigEncoding enc ARG_UNUSED)213 static int 	// Returns crude pseudo-random value from 0 to mult-1
214 zxrand_0(int mult) {
215    long long tmp= mult;
216    tmp *= zxrand_0_65536();
217    tmp >>= 16;
218    return (int)tmp;
219 }
220 // Returns crude pseudo-random value from r0 to r1-1, or r0 if the range is invalid
221 static int
222 zxrand(int r0, int r1) {
223    if (r1 <= r0) return r0;
onigenc_unicode_property_name_to_ctype(OnigEncoding enc,const UChar * name,const UChar * end)224    return r0 + zxrand_0(r1-r0);
225 }
226 
227 // Return random value out of multiple ranges.  Each range is
228 // represented by two values (lo, hi), and it represents a range
229 // lo->(hi-1).  It is fine if any range is invalid (i.e. 0 or negative
230 // length), as it will be ignored.  However, if all ranges are
231 // invalid, then the default value 'def' is returned instead.
232 // 'fmt' is a string of format characters, indicating the arguments
233 // to follow:
234 //	'r' indicates a range (int lo, int hi), from lo->(hi-1)
235 //	'o' indicates a range (int lo, int hi) that will be used to
236 //	      limit all the following 'r' ranges
237 static int
238 zxrandM(int def, char *fmt, ...) {
239    va_list ap;
240    int cnt= 0;
241    int val;
242    char *p;
243    int olo, ohi;	// Overall limiting range
244 
245    va_start(ap, fmt);
246    olo= 0x80000000; ohi= 0x7FFFFFFF;
247    for (p= fmt; *p; p++) {
248       int lo= va_arg(ap, int);
249       int hi= va_arg(ap, int);
250       if (*p == 'o') { olo= lo; ohi= hi; }
251       else if (*p == 'r') {
252 	 if (lo < olo) lo= olo;
253 	 if (hi > ohi) hi= ohi;
254 	 if (hi-lo > 0) cnt += hi-lo;
255       } else
256 	 error("Bad zxrandM format: %s", fmt);
257    }
258    va_end(ap);
259 
260    if (!cnt) return def;
261    val= zxrand_0(cnt);
262 
263    va_start(ap, fmt);
264    olo= 0x80000000; ohi= 0x7FFFFFFF;
265    for (p= fmt; *p; p++) {
onigenc_unicode_mbc_case_fold(OnigEncoding enc,OnigCaseFoldType flag ARG_UNUSED,const UChar ** pp,const UChar * end,UChar * fold)266       int lo= va_arg(ap, int);
267       int hi= va_arg(ap, int);
268       if (*p == 'o') { olo= lo; ohi= hi; }
269       else if (*p == 'r') {
270 	 if (lo < olo) lo= olo;
271 	 if (hi > ohi) hi= ohi;
272 	 cnt= hi-lo;
273 	 if (cnt > 0) {
274 	    if (val < cnt) return lo + val;
275 	    val -= cnt;
276 	 }
277       }
278    }
279    va_end(ap);
280    return def;
281 }
282 
283 // File buffer operations
284 size_t
285 oc_read(void *ptr, size_t size, size_t nmemb, void *datasource) {
286    AStream *ss= (AStream*)datasource;
287    int len= size * nmemb;
288    if (len > data_end - ss->rd)
289       len= data_end - ss->rd;
290    if (len) {
291       memcpy(ptr, ss->rd, len);
292       ss->rd += len;
293    }
294    return len;
295 }
296 
297 int
298 oc_seek(void *datasource, ogg_int64_t offset, int whence) {
299    AStream *ss= (AStream*)datasource;
300    int pos= ss->rd - data;
301    switch (whence) {
302     case SEEK_SET:
303        pos= offset; break;
304     case SEEK_CUR:
305        pos += offset; break;
306     case SEEK_END:
307        pos= datlen += offset; break;
308    }
309    if (pos < 0) pos= 0;
310    if (pos > datlen) pos= datlen;
311    ss->rd= data + pos;
312    return pos;
313 }
314 
315 int
316 oc_close(void *datasource) {
317    return 0;
onigenc_unicode_apply_all_case_fold(OnigCaseFoldType flag,OnigApplyAllCaseFoldFunc f,void * arg,OnigEncoding enc ARG_UNUSED)318 }
319 
320 long
321 oc_tell(void *datasource) {
322    AStream *ss= (AStream*)datasource;
323    return ss->rd - data;
324 }
325 
326 // Initialise all
327 void
328 looper_init() {
329    vorbis_info *vi;
330    int a;
331    ov_callbacks oc;
332    vorbis_comment *vc;
333    char *looper;
334    int prev_flag= 0;
335    int on;
336 
337    // Init random seed
338    zxrand_seed= 0xFFFF & time(NULL);
339 
340    // Find the length of the OGG file and load it into memory
341    if (0 != fseek(mix_in, 0, SEEK_END) ||
342        0 > (datlen= ftell(mix_in)))
343       error("Can't determine length of OGG file: %s", strerror(errno));
344 
345    data= ALLOC_ARR(datlen, char);
346    data_end= data + datlen;
347    if (0 != fseek(mix_in, 0, SEEK_SET) ||
348        1 != fread(data, datlen, 1, mix_in))
349       error("Can't read loopable OGG file into memory: %s", strerror(errno));
350 
351    // Open each of the three OGG streamers
352    oc.read_func= oc_read;
353    oc.seek_func= oc_seek;
354    oc.close_func= oc_close;
355    oc.tell_func= oc_tell;
356    for (a= 0; a<3; a++) {
357       AStream *aa= &str[a];
358       aa->rd= data;
359       aa->mode= 0;
360       aa->buf0= ALLOC_ARR(2048, short);
361       aa->buf1= aa->buf0 + 2048;
362       aa->b_rd= aa->b_end= aa->buf0;
363       if (0 > ov_open_callbacks(aa, &aa->ogg, NULL, 0, oc))
364 	 error("Problem opening OGG bitstream");
365    }
366 
367    // Find the total length of the file
368    datcnt= ov_pcm_total(&str[0].ogg, -1);
369    datcnt0= datcnt;
370    datbase= 0;
371 
372    // Pick up sampling rate and override default if -r not used
373    vi= ov_info(&str[0].ogg, -1);
374    datrate= vi->rate;
375    if (out_rate_def) out_rate= vi->rate;
376    out_rate_def= 0;
377 
378    // Find the SBAGEN_LOOPER tag
379    looper= "";
380    vc= ov_comment(&str[0].ogg, -1);
381    for (a= 0; a<vc->comments; a++)
382       if (0 == memcmp(vc->user_comments[a], "SBAGEN_LOOPER=", 14))
383 	 looper= vc->user_comments[a] + 14;
384 
385    // Setup info from SBAGEN_LOOPER tag
386    seg0= seg1= datcnt;
387    fade_cnt= datrate;
388    ch2= 0;
389    ch2_swap= 1;
390    on= 1;
391    if (mix_cnt < 0) mix_cnt= 0;
392    while (*looper) {
393       char flag, *p;
394       double val;
395 
396       flag= *looper++;
397       if (isspace(flag)) continue;
398       if (!strchr("s-fcwd#", flag)) {
399 	 warn("Bad SBAGEN_LOOPER flag: %c", flag);
400 	 continue;
401       }
402       if (flag == '-') switch (prev_flag) {
403        case 's': flag= 'S'; break;
404        case 'd': flag= 'D'; break;
405        default:
406 	 warn("SBAGEN_LOOPER '-' found not in form s<val>-<val>");
407 	 continue;
408       }
409       prev_flag= flag;
410 
411       val= strtod(looper, &p);
412       if (p == looper) {
413 	 warn("Bad SBAGEN_LOOPER value for flag '%c': %s", flag, p);
414 	 continue;
415       }
416       looper= p;
417 
418       if (flag == '#')
419 	 on= (val == mix_cnt);
420       else if (on) switch (flag) {
421        case 's': seg0= seg1= val * datrate; break;
422        case 'S': seg1= val * datrate; break;
423        case 'd': datbase= val * datrate; datcnt= datcnt0 - datbase; break;
424        case 'D': datcnt= val * datrate - datbase; break;
425        case 'f': fade_cnt= val * datrate; break;
426        case 'c': ch2= val > 1.5; break;
427        case 'w': ch2_swap= val > 0.5; break;
428       }
429    }
430 
431    // Tidy up LOOPER settings
432    if (fade_cnt < datrate/50) fade_cnt= datrate/50;	// 20ms min fade
433    if (datcnt + datbase > datcnt0) datcnt= datcnt0-datbase;
434    if (datcnt < 0)
435       error("Source data range invalid in SBAGEN_LOOPER settings");
436    if (datcnt <= 3 * fade_cnt)
437       error("Length of source data 'd' too short for fade-length of %gs\n"
438 	    " in SBAGEN_LOOPER settings", fade_cnt * 1.0 / datrate);
439    if (seg0 > datcnt) seg0= datcnt;
440    if (seg1 > datcnt) seg1= datcnt;
441    if (seg0 > seg1) seg0= seg1;
442    if (seg0 < 3 * fade_cnt) {
443       seg0= 3 * fade_cnt;
444       warn("SBAGEN_LOOPER segment size too short for fade-length of %gs; adjusted.",
445 	   fade_cnt * 1.0 / datrate);
446    }
447    if (seg1 < seg0) seg1= seg0;
448 
449    // Calculate delta to use for fades
450    del_amp= 0xFFFFFFFFU/fade_cnt;		// Rely on rounding down here
451    if (del_amp * (uint)fade_cnt < 0xF0000000)	// Paranoid check
452       error("Internal rounding error in calculating amplitude delta");
453    if (ch2) del_amp >>= 1;
onigenc_unicode_get_case_fold_codes_by_str(OnigEncoding enc,OnigCaseFoldType flag,const OnigUChar * p,const OnigUChar * end,OnigCaseFoldCodeItem items[])454 
455    //   debug("Segment range %d-%d, fade %d, amp delta per sample %d",
456    //	      seg0, seg1, fade_cnt, del_amp);
457 
458    // Init three streams and start off
459    looper_sched();
460 
461    // Start a thread to handle generation of the mix stream
462    inbuf_start(looper_read, 256*1024);	// 1024K buffer: 3s@44.1kHz
463 }
464 
465 void
466 looper_term() {
467    int a;
468    for (a= 0; a<3; a++) {
469       ov_clear(&str[a].ogg);
470       free(str[a].buf0);
471    }
472 }
473 
474 int
475 looper_read(int *dst, int dlen) {
476    int *dst0= dst;
477    int *dst1= dst + dlen;
478 
479    // Clear the whole thing
480    memset(dst0, 0, (char*)dst1 - (char*)dst0);
481 
482    // Go through in chunks
483    while (dst0 < dst1) {
484       int a;
485       int len= (dst1-dst0)/2;
486       int resched= 0;
487 
488       for (a= 0; a<3; a++) {
489 	 AStream *aa= &str[a];
490 	 if (aa->mode && aa->cnt < len)
491 	    len= aa->cnt;
492       }
493 
494       // Process 'len' samples in each channel
495       for (a= 0; a<3; a++) {
496 	 AStream *aa= &str[a];
497 	 int cnt= len;
498 
499 	 if (!aa->mode) continue;
500 
501 	 dst= dst0;
502 	 while (cnt > 0) {
503 	    // Refill buffer if necessary
504 	    if (aa->mode > 1 &&
505 		aa->b_rd == aa->b_end) {
506 	       int sect;
507 	       char *buf= (char*)aa->buf0;
508 	       int len= (aa->buf1-aa->buf0)*sizeof(aa->buf0[0]);
509 	       int rv= ov_read(&aa->ogg, buf, len, &sect);
510 	       if (rv < 0) {
511 		  warn("Recoverable error in Ogg stream  ");
512 		  continue;
513 	       }
514 	       if (rv == 0) {    // EOF; internal error?
515 		  warn("Hit EOF in looping OGG stream, filling with zeros");
516 		  memset(buf, 0, len);
517 		  rv= len;
518 	       }
519 	       if (rv & 3)
520 		  error("UNEXPECTED: ov_read() returned a partial sample count: %d", rv);
521 	       aa->b_rd= aa->buf0;
522 	       aa->b_end= aa->buf0 + (rv/2);
523 	    }
524 
525 	    // Waiting to start playing
526 	    if (aa->mode == 1) {
527 	       aa->cnt -= cnt;
528 	       cnt= 0;
529 	       continue;
530 	    }
531 
532 	    // Playing fade-in / main part / fade-out
533 	    if (aa->chan && ch2_swap) {
534 	       // Output with swapped L+R
535 	       while (cnt > 0 && aa->b_rd != aa->b_end) {
536 		  uint amp= (~aa->amp) >> 16; amp= (~(amp*amp))>>21; amp *= ogg_mult;
537 		  cnt--;
538 		  *dst++ += ((int)(aa->b_rd[1] * amp)) >> 11;
539 		  *dst++ += ((int)(aa->b_rd[0] * amp)) >> 11;
540 		  aa->b_rd += 2;
541 		  aa->amp += aa->del;
542 		  aa->cnt--;
543 	       }
544 	    } else {
545 	       // Output with normal L+R
546 	       while (cnt > 0 && aa->b_rd != aa->b_end) {
547 		  uint amp= (~aa->amp) >> 16; amp= (~(amp*amp))>>21; amp *= ogg_mult;
548 		  cnt--;
549 		  *dst++ += ((int)(*aa->b_rd++ * amp)) >> 11;
550 		  *dst++ += ((int)(*aa->b_rd++ * amp)) >> 11;
551 		  aa->amp += aa->del;
552 		  aa->cnt--;
553 	       }
554 	    }
555 	 }
556 
557 	 if (!aa->cnt) switch (aa->mode) {
558 	  case 1:
559 	     aa->mode= 2;
560 	     aa->cnt= fade_cnt;
561 	     aa->del= del_amp;
562 	     break;
563 	  case 2:
564 	     aa->mode= 3;
565 	     aa->cnt= aa->cnt_all - 2 * fade_cnt;
566 	     aa->del= 0;
567 	     break;
568 	  case 3:
569 	     aa->mode= 4;
570 	     aa->cnt= fade_cnt;
571 	     aa->del= -del_amp;
572 	     break;
573 	  case 4:
574 	     aa->mode= 0;
575 	     resched= 1;
576 	     break;
577 	 }
578       }
579 
580       dst0 += len*2;
581 
582       // Schedule in another section if necessary
583       if (resched) looper_sched();
584    }
585 
586    return dlen;		// Always returns a full buffer
587 }
588 
589 // Calculate sample-count before end of playback on this channel
590 #define CNT_TO_END(aa) \
591 (aa->mode == 1 ? aa->cnt_all + aa->cnt : \
592  aa->mode == 2 ? aa->cnt_all - fade_cnt + aa->cnt : \
593  aa->mode == 3 ? fade_cnt + aa->cnt : \
594  aa->mode == 4 ? aa->cnt : 0)
595 
596 //
597 //	Schedule in the next segment or segments
598 //
599 
600 static void
601 looper_sched() {
602    int update= 0;
603 
604    // Handle 2-channel separately
605    if (ch2) {
606       looper_sched2();
607       return;
608    }
609 
610    while (1) {
611       AStream *aa= &str[0];
612       AStream *bb= &str[1];
613       int cnt_all, rv;
614 
615       // Complete when both are set up ready
616       if (aa->mode && bb->mode) break;
617       update= 1;
618 
619       // Make 'bb' the one we are filling in
620       if (bb->mode && !aa->mode) {
621 	 AStream *tmp= aa; aa= bb; bb= tmp;
622       }
623 
624       // Make 'aa' zero if it is not active
625       if (!aa->mode) aa= 0;
626 
627       // Setup a new segment for 'bb'
628       bb->off= -1;
629       bb->mode= 1;
630       bb->cnt= 0;
631       bb->amp= 0;
632       bb->b_rd= bb->b_end= bb->buf0;
633 
634       // Position segment to follow on from segment currently playing
635       // on 'aa'
636       if (aa) {
637 	 bb->cnt= CNT_TO_END(aa) - fade_cnt;
638 	 if (bb->cnt < 0) bb->cnt= 0;
639       }
640 
641       // Select the segment length
642       bb->cnt_all= cnt_all= zxrand(seg0, seg1+1);
643 
644       // Look for a segment starting-point which doesn't overlap the
645       // segment playing on the other channel.  First range below is
646       // before 'aa' segment, second is after 'aa' segment.
647       if (aa) {
648 	 bb->off= zxrandM(-1, "rr", 	// Default -1 if no range is available
649 			  0, aa->off - cnt_all,
650 			  aa->off + aa->cnt_all, datcnt - cnt_all);
651       }
652 
653       // If we haven't been able to work around 'aa', or 'aa' is not
654       // active, then just randomly choose a position
655       if (bb->off < 0)
656 	 bb->off= zxrand(0, datcnt - cnt_all);
657 
onigenc_unicode_case_map(OnigCaseFoldType * flagP,const OnigUChar ** pp,const OnigUChar * end,OnigUChar * to,OnigUChar * to_end,const struct OnigEncodingTypeST * enc)658       // Reseek the OGG stream
659       rv= ov_pcm_seek(&bb->ogg, datbase + bb->off);
660       if (rv) error("UNEXPECTED: Can't reseek the looping OGG stream: %d", rv);
661    }
662 
663    //   //DEBUG
664    //   if (update) {
665    //      int a;
666    //      for (a= 0; a<2; a++) {
667    //	 AStream *aa= &str[a];
668    //	 printf("STR%d ", a);
669    //	 if (!aa->mode) { printf("off\n"); continue; }
670    //	 printf("mode %d, cnt %d, cnt_all %d\n",
671    //		aa->mode, aa->cnt, aa->cnt_all);
672    //      }
673    //   }
674 }
675 
676 // This is for two tracks playing constantly
677 static void
678 looper_sched2() {
679    while (1) {
680       AStream *aa= &str[0];
681       AStream *bb= &str[1];
682       AStream *cc= &str[2];
683       AStream *tmp;
684       int cnt_all, rv;
685 
686       // Complete when all are ready
687       if (aa->mode && bb->mode && cc->mode) break;
688 
689       // Put the used slots in order: aa first, then bb, then cc
690       if (!aa->mode && bb->mode) {
691  	 tmp= aa; aa= bb; bb= tmp;
692       }
693       if (!aa->mode && cc->mode) {
694  	 tmp= aa; aa= cc; cc= tmp;
695       }
696       if (!bb->mode && cc->mode) {
697  	 tmp= bb; bb= cc; cc= tmp;
698       }
699 
700       // If there are only 0 or 1 in use, we can add a new one on the
701       // other channel, so long as its fade-out time doesn't clash
702       // with 'aa', if active.
703       if (!bb->mode) {
704 	 // Setup a new segment for 'bb'
705  	 bb->chan= aa ? !aa->chan : 0;
706 	 bb->off= -1;
707 	 bb->mode= 1;
708 	 bb->amp= 0;
709 	 bb->cnt= 0;
710 	 bb->b_rd= bb->b_end= bb->buf0;
711 
712 	 // Select the segment length and start-point, avoiding a
713 	 // length that would cause a clash with 'aa's fade-out
714 	 if (!aa) {
715 	    cnt_all= zxrand(seg0, seg1+1);
716 	 } else {
717 	    int end= CNT_TO_END(aa);		// Count before aa fade-out end
718 	    cnt_all= zxrandM(-1, "orr",
719 			     seg0, seg1+1,	    // Overall limit to valid range seg0->seg1
720 			     seg0, end-fade_cnt,    // To fit before the 'aa' fade-out
721 			     end+fade_cnt, seg1+1); // To fit after
722 
723 	    // If -1 then we can't fit it in with the provided
724 	    // segment-length range, so start late instead
725 	    if (cnt_all < 0) {
726 	       bb->cnt= end+fade_cnt - seg1;
727 	       cnt_all= seg1;
728 	    }
729 	 }
730 	 bb->cnt_all= cnt_all;
731 	 if (bb->cnt < 0) bb->cnt= 0;
732 
733 	 // Look for a segment starting-point which doesn't overlap
734 	 // the segment playing on the other channel, or if that
735 	 // didn't work, just choose a random position
736 	 if (aa) {
737 	    bb->off= zxrandM(-1, "rr", 	// Default -1 if no range is available
738 			     0, aa->off - cnt_all,
739 			     aa->off + aa->cnt_all, datcnt - cnt_all);
740 	 }
741 	 if (bb->off < 0)
742 	    bb->off= zxrand(0, datcnt - cnt_all);
743 
744 	 // Reseek the OGG stream
745 	 rv= ov_pcm_seek(&bb->ogg, datbase + bb->off);
746 	 if (rv) error("UNEXPECTED: Can't reseek the looping OGG stream: %d", rv);
747 	 continue;
748       }
749 
750       // Okay, so we have 'aa' and 'bb' and we need to fill in 'cc'.
751       // 'aa' and 'bb' should be on different channels.  We need to
752       // create a 'cc' that continues where the shorter of 'aa' and
753       // 'bb' leaves off.
754       if (aa->chan == bb->chan)
755 	 error("UNEXPECTED: internal error, looper_sched2(), aa/bb on same chan");
756 
757       // Make 'aa' the shorter one
758       if (CNT_TO_END(aa) > CNT_TO_END(bb)) {
759  	 tmp= aa; aa= bb; bb= tmp;
760       }
761 
762       // Setup a new segment for 'cc'
763       cc->chan= aa->chan;
764       cc->cnt= CNT_TO_END(aa) - fade_cnt;
765       cc->off= -1;
766       cc->mode= 1;
767       cc->amp= 0;
768       cc->b_rd= cc->b_end= cc->buf0;
769 
770       // Select the segment length and start-point, avoiding a
771       // length that would cause a clash with 'bb's fade-out
772       if (!bb) {
773 	 cnt_all= zxrand(seg0, seg1+1);
774       } else {
775 	 int end= CNT_TO_END(bb);		// Count before bb fade-out end
776 	 end -= cc->cnt;			// Take account of the offset we are starting at
777 	 cnt_all= zxrandM(-1, "orr",
778 			  seg0, seg1+1,	    // Overall limit to valid range seg0->seg1
779 			  seg0, end-fade_cnt,    // To fit before the 'bb' fade-out
780 			  end+fade_cnt, seg1+1); // To fit after
781 
782 	 // If -1 then we can't fit it in with the provided
783 	 // segment-length range, so go shorter or longer
784 	 if (cnt_all < 0) {
785 	    if (end-fade_cnt > fade_cnt * 2)
786 	       cnt_all= end-fade_cnt;
787 	    else
788 	       cnt_all= end+fade_cnt;	// Might overflow datcnt, so this is last resort
789 	 }
790       }
791       cc->cnt_all= cnt_all;
792 
793       // Look for a segment starting-point which doesn't overlap
794       // either of the segments playing on the other two channels
795       {
796 	 int r0= aa->off;
797 	 int r1= aa->off + aa->cnt_all;
798 	 int r2= bb->off;
799 	 int r3= bb->off + bb->cnt_all;
800 
801 	 if (r0 > r2) {
802 	    int tmp;
803 	    tmp= r0; r0= r2; r2= tmp;
804 	    tmp= r1; r1= r3; r3= tmp;
805 	 }
806 
807 	 cc->off= zxrandM(-1, "rrr", 	// Default -1 if no range is available
808 			  0, r0 - cnt_all,
809 			  r1, r2 - cnt_all,
810 			  r3, datcnt - cnt_all);
811       }
812 
813       // Failing that, choose a segment at random
814       if (cc->off < 0)
815 	 cc->off= zxrand(0, datcnt - cnt_all);
816 
817       // Reseek the OGG stream
818       rv= ov_pcm_seek(&cc->ogg, datbase + cc->off);
819       if (rv) error("UNEXPECTED: Can't reseek the looping OGG stream: %d", rv);
820       continue;
821    }
822 }
823 
824 // END //
825