/* LarkTones.c
   L. Stewart October 26, 1982  6:52 PM
   L. Stewart, December 7, 1982  1:56 PM, tone event
   L. Stewart, December 8, 1982  3:56 PM, silent DTMF code, LarkSlave addrs
   L. Stewart, January 17, 1983  3:47 PM, Lark.mesa revisions
   L. Stewart, April 23, 1983  6:07 PM, some cleanup
   L. Stewart, June 2, 1983  11:50 AM, some cleanup
   L. Stewart, June 6, 1983  12:46 PM, new sinetables
 */

#include "Lark.h"
#include "Env.h"
#include "LarkNet.h"
#include "LarkSlave.h"
#include "Queue.h"

extern int UDiv();
extern int DoubleUDiv();
extern MoveBlock();
extern int Sine();
extern InitQueue();
extern Enqueue();
extern ToNet();

extern STab06();
extern STab09();
extern STab12();
extern STab15();
extern STab18();
int lastHalf;
extern int toneDone;

/* sinewave tables */
int sTables[5];

struct SineCB {   /* used by SineML.dsm to generate tones */
  char *dest;
  int count, freq, sinetab;
  };

struct ToneCB {
  struct ToneCB *next;
  int f1, f2, totOn, totOff, this, active, sineTable, times, notify;
  };

extern struct ToneCB *Dequeue();

static int phase1, phase2;		/* phase continuity */
static struct SineCB f1a, f1b, f2a, f2b;
static struct Queue toneQ, toneFreeQ;
static struct ToneCB tcb[20];
struct ToneCB *wToneCB;
extern int bufferPointer;

InitToneStuff()
  {
  int i;
  InitQueue(&toneQ);
  InitQueue(&toneFreeQ);
  wToneCB = 0;
  lastHalf = false;
  for (i = 0; i < 20; i += 1) Enqueue(&toneFreeQ, &tcb[i]);
  f1a.dest = OutBuf1;
  f1b.dest = OutBuf1+160;
  f2a.dest = OutBuf2;
  f2b.dest = OutBuf2+160;
  f1a.count = f1b.count = f2a.count = f2b.count = 160;
  sTables[0] = (int) &STab06;
  sTables[1] = (int) &STab09;
  sTables[2] = (int) &STab12;
  sTables[3] = (int) &STab15;
  sTables[4] = (int) &STab18;
  };

/* on and off are in milliseconds, pass queue argument to playtone
  on first digit, then pass true
 */

LocPlayDTMF(d, on, off, queue, tab, notify)
  char d;
  int on, off, queue, tab, notify;
  {
  int mf1, mf2;
  switch (d) {
    case '1': { mf1 = 697; mf2 = 1209; break; };
    case '2': { mf1 = 697; mf2 = 1336; break; };
    case '3': { mf1 = 697; mf2 = 1477; break; };
    case 'A': { mf1 = 697; mf2 = 1633; break; };
    case '4': { mf1 = 770; mf2 = 1209; break; };
    case '5': { mf1 = 770; mf2 = 1336; break; };
    case '6': { mf1 = 770; mf2 = 1477; break; };
    case 'B': { mf1 = 770; mf2 = 1633; break; };
    case '7': { mf1 = 852; mf2 = 1209; break; };
    case '8': { mf1 = 852; mf2 = 1336; break; };
    case '9': { mf1 = 852; mf2 = 1477; break; };
    case 'C': { mf1 = 852; mf2 = 1633; break; };
    case '0': { mf1 = 941; mf2 = 1336; break; };
    case '*': { mf1 = 941; mf2 = 1209; break; };
    case '#': { mf1 = 941; mf2 = 1477; break; };
    case 'D': { mf1 = 941; mf2 = 1633; break; };
    default: { mf1 = 0; mf2 = 0; break; };
    };
  PlayTone(mf1, mf2, on, off, 1, queue, tab, notify);
  };

static int FreqToFrac(freq)
  int freq;
  {
  int v[2];
  v[1] = UDiv(freq,2);
  v[0] = (freq & 1) ? 0x8000: 0;
  /* 0 is 0 and 4000 is 08000H */
  /* multiplier is freq * 32768/4000 */
  return(DoubleUDiv(v, 4000));
  };

/*  f1 and f2 are in Hz
    on and off are times in milliseconds,  either can be 0
    times is the number of repititions
    if (queue) enqueue; else flushqueue and enqueue
    stIndex is the index into the table of available sine tables
 */

int PlayTone(f1, f2, on, off, times, queue, stIndex, notify)
  int f1, f2, on, off, times, queue, stIndex, notify;
  {
  struct ToneCB *t, *tt;
  int dontBother;
  dontBother = false;
  t = Dequeue(&toneFreeQ);
  if (t == 0) return(false);
  t->f1 = FreqToFrac(f1);
  t->f2 = FreqToFrac(f2);
  t->this = t->totOn = on/20; /* start with on cycle */
  t->totOff = off/20;
  t->notify = ((notify >> 8) == 26) ? notify: 0;
  t->times = ((on == 0) || (off == 0)) ? times: times << 1;
  t->active = true;
  t->sineTable = sTables[stIndex];
  if (!queue) {
    for (;;) {
      tt = Dequeue(&toneQ);
      if (tt) Enqueue(&toneFreeQ, tt);
      else break;
      };
    if (tt = wToneCB) {
      wToneCB = 0;
      Enqueue(&toneFreeQ, tt);
      };
    };
  if ((t->totOn == 0) && (t->totOff == 0)) dontBother = true;
  if (t->times == 0) dontBother = true;
  if (dontBother) Enqueue(&toneFreeQ, t);
  else Enqueue(&toneQ, t);
  return(true);
  };
  
TryEcho()
  {
  if (!lastHalf && (bufferPointer >= 160)) {
    ToneMode();
    if (wToneCB) {
      if (wToneCB->active) {
        phase1 = Sine(phase1, &f1a);
        phase2 = Sine(phase2, &f2a);
        };
      };
    ToNet();
    lastHalf = true;
    };
  if (lastHalf && (bufferPointer < 160)) {
    ToneMode();
    if (wToneCB) {
      if (wToneCB->active) {
        phase1 = Sine(phase1, &f1b);
        phase2 = Sine(phase2, &f2b);
        };
      };
    ToNet();
    lastHalf = false;
    };
  };

static ToneMode()
  {
  if (wToneCB == 0) {
    if (wToneCB = Dequeue(&toneQ)) {
      f1a.freq = f1b.freq = wToneCB->f1;
      f2a.freq = f2b.freq = wToneCB->f2;
      f1a.sinetab = f1b.sinetab = f2a.sinetab = f2b.sinetab = wToneCB->sineTable;
      };
    };
  else {
    if (wToneCB->times == 0) {
      toneDone = wToneCB->notify;
      Enqueue(&toneFreeQ, wToneCB);
      wToneCB = Dequeue(&toneQ);
      if (wToneCB)  {
        f1a.freq = f1b.freq = wToneCB->f1;
        f2a.freq = f2b.freq = wToneCB->f2;
        f1a.sinetab = f1b.sinetab = f2a.sinetab = f2b.sinetab = wToneCB->sineTable;
        };
      };
    };
  if (wToneCB) {
    if (wToneCB->this == 1) wToneCB->times -= 1;  /* should not be 0! */
    if (wToneCB->this == 0) { /* done with whatever */
      if (wToneCB->active && wToneCB->totOff > 0) {
        wToneCB->active = false;
        };
      else {
        if (!wToneCB->active && wToneCB->totOn > 0) wToneCB->active = true;
        };
      wToneCB->this = (wToneCB->active) ? wToneCB->totOn: wToneCB->totOff;
      };
    else wToneCB->this -= 1;
    };
  };