//||
//||	`rhybag' - Rhythmic BinAural Generator
//||
//||	(c) 1999 Jim Peters <jim@aguazul.demon.co.uk>.  All Rights Reserved.
//||	For latest version see <http://www.aguazul.demon.co.uk/bagen/>.
//||	Released under the GNU GPL.  Use at your own risk.
//||
//||	" This program is free software; you can redistribute it and/or modify
//||	  it under the terms of the GNU General Public License as published by
//||	  the Free Software Foundation, version 2.
//||
//||	  This program is distributed in the hope that it will be useful,
//||	  but WITHOUT ANY WARRANTY; without even the implied warranty of
//||	  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//||	  GNU General Public License for more details. "
//||
//||	If you really don't have a copy of the GNU GPL, I'll send you one.
//||	

//
//	General template for sample-playing routine.  The following
//	macros should have been defined, which will fill in parts of
//	the routine:
//
//	  AMP_MULT   	Amplitude multiplier
//	  FUNC_NAM  	Name of function
//	  DAT_TO_BP 	Code-fragment to write two samples to *bp++ based on values of
//			 dat, off, and frb
//

int
FUNC_NAM(PlayS *pl) {
  int *bp;
  int tim, bcnt;
  uint frb= pl->frb;
  uint max= pl->max;
  char *dat= pl->dat;
  uint off;

  while (1) {
    if (pl->len) {		// We're in the middle of something
      bp= pbuf; bcnt= plen; 
    } 
    else {			// Get next part set up
      EnvList *env= pl->env; 
      if (!env) return 1;	// Done - delete me

      pl->env= env->nxt; 
      pl->adj[0]= env->adj[0]; 
      pl->adj[1]= env->adj[1]; 
      pl->adj[2]= env->adj[2]; 
      pl->amp[0]= env->vol[0] * pl->vol * (AMP_MULT); 
      pl->amp[1]= env->vol[1]; 
      pl->amp[2]= env->vol[2]; 
      pl->ampi= env->voli; 
      pl->len= env->len; 
      pl->d_cnt= env->cnt; 
      pl->cnt= 0;

      tim= pl->tim + env->tim - ptim; 
      off= pl->off;
      while (tim < 0 && pl->len > 0) {
	int cnt, cnt2;
	uint inc;
	
	inc= (uint)(pl->adj[0] * exp_table[(int)pl->adj[1]]);
	
	cnt= -tim < pl->len ? -tim : pl->len;
	cnt2= pl->d_cnt - pl->cnt;
	if (cnt >= cnt2) {
	  cnt= cnt2;
	  pl->adj[1] += pl->adj[2];
	  pl->amp[1] += pl->amp[2];
	  pl->cnt= 0;
	}
	else pl->cnt += cnt;
	
	pl->len -= cnt;
	tim += cnt;
	
	// @@ Could do better here, but it's not a critical part of the code
	if (inc && (max-off) / inc < cnt) 	// Can't do `< cnt*inc' due to overflow cases
	  while (cnt-- > 0) {	// Check `max'
	    if ((off += inc) >= max) { off -= pl->dec; if (!pl->loop) return 1; }
	  }
	else 
	  off += inc * cnt;
      }
      pl->off= off;

      bp= pbuf + 2*tim; 
      bcnt= plen - tim; 
      if (bcnt <= 0) return 0;	// Leave until next chunk
    } 

    // Write as much as we can to the buffer
    while (pl->len && bcnt) {		// Efficiency required in this loop
      int cnt, cnt2;
      uint inc, amp, ampi, off;
      double tmp;

      inc= (uint)(pl->adj[0] * exp_table[(int)pl->adj[1]]);
      amp= (uint)(tmp= pl->amp[0] * exp_table[(int)pl->amp[1]]);
      ampi= (uint)(int)(tmp * pl->ampi + (tmp < 0 ? 0.49 : -0.49));
      if (pl->cnt) amp += ampi * pl->cnt;

      cnt= bcnt < pl->len ? bcnt : pl->len;
      cnt2= pl->d_cnt - pl->cnt;
      if (cnt >= cnt2) {
        cnt= cnt2;
        pl->adj[1] += pl->adj[2];
        pl->amp[1] += pl->amp[2];
        pl->cnt= 0;
      }
      else pl->cnt += cnt;

      pl->len -= cnt;
      bcnt -= cnt;

      off= pl->off;

      if (inc && (max-off) / inc < cnt) 	// Can't do `< cnt*inc' due to overflow cases
	while (cnt-- > 0) {	// Check `max'
	  DAT_TO_BP;
	  if ((off += inc) >= max) { off -= pl->dec; if (!pl->loop) return 1; }
	  amp += ampi;
	}
      else 
	while (cnt-- > 0) {	// No need to check `max'
	  DAT_TO_BP;
	  off += inc;
	  amp += ampi;
	}

      pl->off= off;
    }
    if (!bcnt) break;
  }
  return 0;
}

#undef AMP_MULT
#undef FUNC_NAM
#undef DAT_TO_BP

// END //
