/* Telphone Tones generator A.J. Fisher August 1995 C++ vsn AJF Dec. 1999 */ #include #include #include #include #include #define global #define unless(x) if(!(x)) #define until(x) while(!(x)) #define MAXSTR 512 #define SAMPLERATE 8000 #define SINEBITS 11 #define SINELEN (1 << SINEBITS) #define TWOPI (2.0 * M_PI) #define TWO32 4294967296.0 /* 2^32 */ typedef unsigned char uchar; typedef unsigned int uint; union word { word(char *sx) { s = sx; } word(int nx) { n = nx; } char *s; int n; }; static short expandtab[128]; /* entries 0 .. 32767 */ static char compresstab[32768]; /* entries 0 .. 127 */ static double sinetab[SINELEN]; static int header[8] = { 0x2e736e64, /* ".snd" magic number */ 32, /* length of hdr */ 0, /* *nominal* length of body, in samples */ 1, SAMPLERATE, 1, 0, 0, /* don't ask me what this means! */ }; extern "C" int atoi(char*); static void newhandler(), initaudio(), makeexpandtab(), makecompresstab(), makesinetab(); static void sendheader(), writeword(uint); static void senddtmf(char*), sendtone(int), sendwarble(double, double), sendfreqs(double, double, int, int); static void usage(), fail(char*, word = 0); inline int ifix(double x) { return (x >= 0.0) ? (int) (x+0.5) : (int) (x-0.5); } global void main() { set_new_handler(newhandler); logweb("teletones", ""); getentries(); initaudio(); if (isset("dial")) { char *s = getval("dial"); senddtmf(s); } else if (isset("tone")) { char *s = getval("tone"); sendtone(atoi(s)); } else usage(); exit(0); } static void newhandler() { fail("No room!"); } static void initaudio() { makeexpandtab(); makecompresstab(); makesinetab(); sendheader(); } static void makeexpandtab() { /* make mu-law expanding table */ for (int n = 0; n < 128; n++) { double x = (pow(256.0, (double) n / 127.0) - 1.0) / 255.0; /* result in range 0 .. 1 */ expandtab[n] = ifix(x * 32767.0); /* in range 0 .. 32767 */ } } static void makecompresstab() { /* make mu-law compressing table */ int i = 0, j = 0; while (i < 32768) { compresstab[i] = j; if (j < 127 && (expandtab[j+1] - i) < (i - expandtab[j])) j++; i++; } } static void makesinetab() { for (int k = 0; k < SINELEN; k++) { double th = TWOPI * (double) k / (double) SINELEN; sinetab[k] = sin(th); } } static void sendheader() { printf("Content-Type: audio/basic\n\n"); for (int i = 0; i < 8; i++) writeword(header[i]); } static void writeword(uint n) { #ifdef linux for (int i = 0; i < 4; i++) { putchar(n >> 24); n <<= 8; } #else for (int i = 0; i < 4; i++) { putchar(n & 0xff); n >>= 8; } #endif } static double rowtab[4] = { 697.0, 770.0, 852.0, 941.0 }; static double coltab[4] = { 1209.0, 1336.0, 1477.0, 1633.0 }; static void senddtmf(char *s) { int k = 0; until (s[k] == '\0') { char c = s[k++]; char *dstr = "123A456B789C*0#D"; char *p = strchr(dstr, c); unless (p == NULL) { uchar n = p - dstr; sendfreqs(rowtab[n >> 2], coltab[n & 3], 100, 1); /* tones for 100 ms */ sendfreqs(0.0, 0.0, 100, 1); /* silence for 100 ms */ } } } static void sendtone(int n) { switch (n) { default: usage(); case 0: /* BT */ { for (int i = 0; i < 14; i++) { sendfreqs(400.0, 400.0, 375, 1); sendfreqs(0.0, 0.0, 375, 1); } break; } case 1: /* EET */ { for (int i = 0; i < 7; i++) { sendfreqs(400.0, 400.0, 400, 0); /* quieter */ sendfreqs(0.0, 0.0, 350, 0); sendfreqs(400.0, 400.0, 225, 1); sendfreqs(0.0, 0.0, 525, 1); } break; } case 2: /* RT */ { for (int i = 0; i < 4; i++) { sendfreqs(400.0, 450.0, 400, 1); sendfreqs(0.0, 0.0, 200, 1); sendfreqs(400.0, 450.0, 400, 1); sendfreqs(0.0, 0.0, 2000, 1); } break; } case 3: /* NU */ { sendfreqs(400.0, 400.0, 10000, 1); break; } case 4: /* PT */ { for (int i = 0; i < 40; i++) { sendfreqs(400.0, 400.0, 125, 1); sendfreqs(0.0, 0.0, 125, 1); } break; } case 5: /* DT */ { sendfreqs(350.0, 450.0, 10000, 1); break; } case 6: /* Warble 1 */ { for (int i = 0; i < 4; i++) { sendwarble(1500.0, 1700.0); sendfreqs(0.0, 0.0, 200, 1); sendwarble(1500.0, 1700.0); sendfreqs(0.0, 0.0, 2000, 1); } break; } case 7: /* Warble 2 */ { for (int i = 0; i < 4; i++) { sendwarble(900.0, 1100.0); sendfreqs(0.0, 0.0, 200, 1); sendwarble(900.0, 1100.0); sendfreqs(0.0, 0.0, 2000, 1); } break; } } } static void sendwarble(double f1, double f2) { /* 400ms of warble */ for (int i = 0; i < 3; i++) { sendfreqs(f1, f1, 62, 1); sendfreqs(f2, f2, 63, 1); } sendfreqs(f1, f1, 25, 1); } static double amptab[2] = { 8191.75, 16383.5 }; inline int phinc(double f) { /* given frequency f, return corresponding phase increment */ return ifix(TWO32 * f / (double) SAMPLERATE); } inline double sine(uint ptr) { /* given 32-bit pointer ptr, return corresponding element from sine table */ return sinetab[ptr >> (32-SINEBITS)]; } static void sendfreqs(double f1, double f2, int ms, int ak) { double amp = amptab[ak]; int phinc1 = phinc(f1), phinc2 = phinc(f2); int ns = ms * (SAMPLERATE/1000); uint ptr1 = 0, ptr2 = 0; for (int n = 0; n < ns; n++) { double val = amp * (sine(ptr1) + sine(ptr2)); int ival = ifix(val); if (ival < -32768 || ival > 32767) fail("Bug! out of range: %08x", ival); putchar((ival >= 0) ? 255 - compresstab[ival] : 127 - compresstab[~ival]); ptr1 += phinc1; ptr2 += phinc2; } } static void usage() { fail("Usage error!"); } static void fail(char *msg, word p1) { discard_output(); /* in case we've sent audio/basic */ printf("Content-type: text/html\n\n"); printf("\n\n"); printf("

Error!

\n"); printf(msg, p1); putchar('\n'); exit(0); }