/* tones.c
L. Stewart October 13, 1982 9:15 PM
L. Stewart November 30, 1982 10:24 AM, removed net stuff
*/
#include "Lark.h"
#include "Env.h"
#include "LarkNet.h"
#include "Queue.h"
extern int UDiv();
extern int DoubleUDiv();
extern MoveBlock();
extern int Sine();
extern InitQueue();
extern Enqueue();
extern STab00();
extern STab03();
extern STab06();
extern STab09();
extern STab12();
extern char *obuf1;
extern char *obuf2;
extern char *inbuf1;
extern char *inbuf2;
extern int *bufptr;
extern int first;
/* sinewave tables */
int sTables[5];
extern int audioMode;
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;
};
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];
static struct ToneCB *wToneCB;
InitToneStuff()
{
int i;
InitQueue(&toneQ);
InitQueue(&toneFreeQ);
for (i = 0; i < 20; i += 1) Enqueue(&toneFreeQ, &tcb[i]);
f1a.dest = obuf1;
f1b.dest = &obuf1[160];
f2a.dest = obuf2;
f2b.dest = &obuf2[160];
f1a.count = f1b.count = f2a.count = f2b.count = 160;
sTables[0] = (int) &STab00;
sTables[1] = (int) &STab03;
sTables[2] = (int) &STab06;
sTables[3] = (int) &STab09;
sTables[4] = (int) &STab12;
};
/* on and off are in milliseconds, pass queue argument to playtone
on first digit, then pass true
*/
LocPlayDTMF(d, on, off, queue, tab)
char d;
int on, off, queue, tab;
{
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: return;
};
PlayTone(mf1, mf2, on, off, 1, queue, tab);
};
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));
};
AudioIdle()
{
audioMode = AMOff;
};
/* 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)
int f1, f2, on, off, times, queue, stIndex;
{
struct ToneCB *t, *tt;
t = Dequeue(&toneFreeQ);
if (t == 0) return(false);
t->f1 = FreqToFrac(f1);
t->f2 = FreqToFrac(f2);
t->this = t->totOn = on/20;
t->totOff = off/20;
if ((on == 0) || (off == 0)) t->times = times;
else t->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);
};
};
Enqueue(&toneQ, t);
AudioIdle();
audioMode = AMTone;
return(true);
};
TryEcho()
{
if (first == 0 && *bufptr >= 160) {
switch (audioMode) {
case AMEcho: CopyLow(); break;
case AMTone: ToneLow(); break;
default:
};
first = 1;
};
if (first != 0 && *bufptr < 160) {
switch (audioMode) {
case AMEcho: CopyHigh(); break;
case AMTone: ToneHigh(); break;
default:
};
first = 0;
};
};
static CopyLow()
{
MoveBlock(obuf1, inbuf1, 80);
MoveBlock(obuf2, inbuf2, 80);
};
static CopyHigh()
{
MoveBlock(&obuf1[160], &inbuf1[160], 80);
MoveBlock(&obuf2[160], &inbuf2[160], 80);
};
static ToneMode()
{
struct ToneCB *temp;
if ((wToneCB == 0) || (wToneCB->times == 0)) {
if (wToneCB != 0) 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;
};
if (wToneCB->active) wToneCB->this = wToneCB->totOn;
else wToneCB->this = wToneCB->totOff;
};
else wToneCB->this -= 1;
};
};
static ToneLow()
{
ToneMode();
if (wToneCB) {
if (wToneCB->active) {
phase1 = Sine(phase1, &f1a);
phase2 = Sine(phase2, &f2a);
};
};
};
static ToneHigh()
{
ToneMode();
if (wToneCB) {
if (wToneCB->active) {
phase1 = Sine(phase1, &f1b);
phase2 = Sine(phase2, &f2b);
};
};
};