home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / hamradio / fftmorse.zip / FFTMORSE.C next >
C/C++ Source or Header  |  1992-05-01  |  25KB  |  632 lines

  1. /*
  2.     FFT Morse Code Decoder Version 1.0
  3.     Copyright (c) 1992 François Jalbert (jalbert@IRO.UMontreal.CA)
  4.  
  5.     Sound-Blaster (c) 1989-1991 Creative Labs Inc
  6.     Turbo-C 2.0 (c) 1988 Borland International
  7.     Sound-Blaster C Library BLAST13 (c) 1991 Joel Lucsy
  8.     LZEXE 0.91 (c) 1989 Fabrice Bellard
  9.  
  10.     Turbo-C flags used: -mt -1 -d -f- -A -K -G -O -w
  11.  
  12.     Warning! This source file contains IBM extended ASCII characters.
  13.              Some source lines are slightly longer than 80 characters.
  14. */
  15. /*
  16. #define DEBUG
  17. #define FFTDEBUG
  18. */
  19. #include <direct.h> /* BLAST13 */
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <conio.h>
  23. #include <dos.h>
  24.  
  25. #define TRUE  1
  26. #define FALSE 0
  27. #define N 16 /* number of FFT terms, do not change this!!! See also LOG2N */
  28.  
  29. static unsigned int videoseg=0xB800; /* assume color */
  30.  
  31. /*----------------------------------- FFT ------------------------------------*/
  32.  
  33. #define S0  0 /* corresponds to 0.0 */
  34. #define S1  3
  35. #define S2  6
  36. #define S3  9 /* sin() table with 4 bit precision */
  37. #define S4 11 /* increasing precision will cause short integer overflows... */
  38. #define S5 13 /* too bad, I really would have liked more precision */
  39. #define S6 15
  40. #define S7 16
  41. #define S8 16 /* corresponds to 1.0 */
  42. #define SCALE 11 /* scale FFT with 2**SCALE from big values to low */
  43.  
  44. #ifdef DEBUG
  45. static int s[N+N],c[N+N];
  46. #endif
  47. static int FFTenable=FALSE; /* Maximum sampling rate for initial SW tuning */
  48. static int waitfactor=3; /* Best initial sampling rate for my 12MHz 286 */
  49. static int fft[N],oldfft[N];
  50.  
  51. void FFT(void)
  52. { /* compute fast short integer FT */
  53. #ifdef DEBUG
  54.   static int data,kl,a[N],b[N],fff[N];
  55. #endif
  56.   static int k,l,f[N+N];
  57.   static int level,oldlevel,line,column;
  58.   static int f16p0,f17m1,f17p1,f18m2,f18p2,f19m3,f19p3;
  59.   static int f20m4,f20p4,f21m5,f21p5,f22m6,f22p6,f23m7,f23p7;
  60.   static int f24p8,f25m9,f25p9,f26m10,f26p10,f27m11,f27p11;
  61.   static int f28m12,f28p12,f29m13,f29p13,f30m14,f30p14,f31m15,f31p15;
  62.   static int f25m9Mf23m7,f25m9Pf23m7,f26m10Mf22m6,f26m10Pf22m6;
  63.   static int f27m11Pf21m5,f29m13Mf19m3,f29m13Pf19m3,f27m11Mf21m5;
  64.   static int f30m14Mf18m2,f30m14Pf18m2,f31m15Mf17m1,f31m15Pf17m1;
  65.   static int f24p8Pf16p0,f25p9Mf23p7,f25p9Pf23p7,f26p10Mf22p6,f26p10Pf22p6;
  66.   static int f27p11Mf21p5,f27p11Pf21p5,f28p12Pf20p4,f29p13Mf19p3;
  67.   static int f29p13Pf19p3,f30p14Mf18p2,f30p14Pf18p2,f31p15Mf17p1,f31p15Pf17p1;
  68.   static int f29Mf19Pf27Mf21,f29Pf19Mf27Pf21,f29Mf19Mf27Mf21;
  69.   static int f31Mf17Pf25Mf23,f31Pf17Mf25Pf23,f31Mf17Mf25Mf23;
  70.   static int s4Mf28f20,s4Pf28f20;
  71.   static int s4Mf30f18f26f22,s4Pf30f26f22f18,s4Mf31f29f27f25,s4Pf31f29f27f25;
  72.   static int s8Mf30f18f26f22,s8Pf28f24f20f16,s8Mf24f16,s8Mf28f20,s8f16,s8f24;
  73.   static int s4Mf30f26Ms8Mf28,s4Mf30f26Ps8Mf28;
  74.   static int s4Pf30f22Ms8Mf24,s4Pf30f22Ps8Mf24;
  75.   static int s6Mf31f25Ms2Mf29f27,s6Mf29f27Ps2Mf31f25;
  76.   static int s6Pf29f27Ms2Pf31f25,s6Pf31f25Ps2Pf29f27;
  77.   static int s1Mf25s3f27s5f29s7f31,s1Pf25s3f27s5f29s7f31;
  78.   static int s1Mf27s3f31s5f25s7f29,s1Pf27s3f31s5f25s7f29;
  79.   static int s1Mf29s3f25s5f31s7f27,s1Pf29s3f25s5f31s7f27;
  80.   static int s1Mf31s3f29s5f27s7f25,s1Pf31s3f29s5f27s7f25;
  81.   static int s2Mf26Ps6Mf30,s2Pf26Ms6Pf30,s2Mf30Ms6Mf26,s2Pf30Ps6Pf26;
  82.   static int s4Mf28Ps8f16,s4Mf28Ms8f16,s4Pf28Ps8f24,s4Pf28Ms8f24;
  83.   static int s2Mf26Ps4f28s6f30Ms8f16,s2Mf26Ms4f28s6f30Ps8f16;
  84.   static int s2Pf26Ms4f28s6f30Ps8f24,s2Pf26Ps4f28s6f30Ms8f24;
  85.   static int s2Mf30Ps4f28s6f26Ps8f16,s2Mf30Ms4f28s6f26Ms8f16;
  86.   static int s2Pf30Ps4f28s6f26Ps8f24,s2Pf30Ms4f28s6f26Ms8f24;
  87.  
  88.   for (k=0 ; k<(N+N) ; k++) {
  89.     for (l=1 ; l<waitfactor ; l++) read_data(); 
  90.     f[k]=read_data()-128;
  91.   }
  92.   f17m1 =f[17]-f[1];  f17p1 =f[17]+f[1];
  93.   f18m2 =f[18]-f[2];  f18p2 =f[18]+f[2];
  94.   f19m3 =f[19]-f[3];  f19p3 =f[19]+f[3];
  95.   f20m4 =f[20]-f[4];  f20p4 =f[20]+f[4];
  96.   f21m5 =f[21]-f[5];  f21p5 =f[21]+f[5];
  97.   f22m6 =f[22]-f[6];  f22p6 =f[22]+f[6];
  98.   f23m7 =f[23]-f[7];  f23p7 =f[23]+f[7];
  99.   f16p0 =f[16]+f[0];  f24p8 =f[24]+f[8];
  100.   f25m9 =f[25]-f[9];  f25p9 =f[25]+f[9];
  101.   f26m10=f[26]-f[10]; f26p10=f[26]+f[10];
  102.   f27m11=f[27]-f[11]; f27p11=f[27]+f[11];
  103.   f28m12=f[28]-f[12]; f28p12=f[28]+f[12];
  104.   f29m13=f[29]-f[13]; f29p13=f[29]+f[13];
  105.   f30m14=f[30]-f[14]; f30p14=f[30]+f[14];
  106.   f31m15=f[31]-f[15]; f31p15=f[31]+f[15];
  107.   f25m9Mf23m7 =f25m9 -f23m7; f25m9Pf23m7 =f25m9 +f23m7;
  108.   f26m10Mf22m6=f26m10-f22m6; f26m10Pf22m6=f26m10+f22m6; 
  109.   f27m11Mf21m5=f27m11-f21m5; f27m11Pf21m5=f27m11+f21m5; 
  110.   f29m13Mf19m3=f29m13-f19m3; f29m13Pf19m3=f29m13+f19m3;
  111.   f30m14Mf18m2=f30m14-f18m2; f30m14Pf18m2=f30m14+f18m2; 
  112.   f31m15Mf17m1=f31m15-f17m1; f31m15Pf17m1=f31m15+f17m1;
  113.   f25p9Mf23p7 =f25p9 -f23p7; f25p9Pf23p7 =f25p9 +f23p7;
  114.   f26p10Mf22p6=f26p10-f22p6; f26p10Pf22p6=f26p10+f22p6;
  115.   f27p11Mf21p5=f27p11-f21p5; f27p11Pf21p5=f27p11+f21p5;
  116.   f24p8Pf16p0 =f24p8 +f16p0; f28p12Pf20p4=f28p12+f20p4;
  117.   f29p13Mf19p3=f29p13-f19p3; f29p13Pf19p3=f29p13+f19p3; 
  118.   f30p14Mf18p2=f30p14-f18p2; f30p14Pf18p2=f30p14+f18p2;
  119.   f31p15Mf17p1=f31p15-f17p1; f31p15Pf17p1=f31p15+f17p1; 
  120.   f29Mf19Pf27Mf21=f29p13Mf19p3+f27p11Mf21p5;
  121.   f29Pf19Mf27Pf21=f29p13Pf19p3-f27p11Pf21p5;
  122.   f29Mf19Mf27Mf21=f29p13Mf19p3-f27p11Mf21p5;
  123.   f31Mf17Pf25Mf23=f31p15Mf17p1+f25p9Mf23p7;
  124.   f31Pf17Mf25Pf23=f31p15Pf17p1-f25p9Pf23p7;
  125.   f31Mf17Mf25Mf23=f31p15Mf17p1-f25p9Mf23p7;
  126.   s4Mf30f18f26f22=S4*(f30p14Mf18p2+f26p10Mf22p6);
  127.   s4Pf30f26f22f18=S4*(f30p14Pf18p2-f26p10Pf22p6);
  128.   s4Mf31f29f27f25=S4*(f31Mf17Mf25Mf23+f29Mf19Mf27Mf21);
  129.   s4Pf31f29f27f25=S4*(f31p15Pf17p1+f25p9Pf23p7-f29p13Pf19p3-f27p11Pf21p5);
  130.   s8Mf30f18f26f22=S8*(f30p14Mf18p2-f26p10Mf22p6);
  131.   s8Pf28f24f20f16=S8*(f28p12Pf20p4-f24p8Pf16p0);
  132.   s8Mf24f16=S8*(f24p8-f16p0); 
  133.   s8Mf28f20=S8*(f28p12-f20p4);
  134.   s4Mf30f26Ms8Mf28=s4Mf30f18f26f22-s8Mf28f20;
  135.   s4Mf30f26Ps8Mf28=s4Mf30f18f26f22+s8Mf28f20;
  136.   s4Pf30f22Ms8Mf24=s4Pf30f26f22f18-s8Mf24f16;
  137.   s4Pf30f22Ps8Mf24=s4Pf30f26f22f18+s8Mf24f16;
  138.   s6Mf31f25Ms2Mf29f27=S6*f31Mf17Pf25Mf23-S2*f29Mf19Pf27Mf21;
  139.   s6Mf29f27Ps2Mf31f25=S6*f29Mf19Pf27Mf21+S2*f31Mf17Pf25Mf23;
  140.   s6Pf29f27Ms2Pf31f25=S6*f29Pf19Mf27Pf21-S2*f31Pf17Mf25Pf23;
  141.   s6Pf31f25Ps2Pf29f27=S6*f31Pf17Mf25Pf23+S2*f29Pf19Mf27Pf21;
  142.   s1Mf25s3f27s5f29s7f31=S1*f25m9Mf23m7+S3*f27m11Mf21m5+S5*f29m13Mf19m3+S7*f31m15Mf17m1;
  143.   s1Pf25s3f27s5f29s7f31=S1*f25m9Pf23m7-S3*f27m11Pf21m5+S5*f29m13Pf19m3-S7*f31m15Pf17m1;
  144.   s1Mf27s3f31s5f25s7f29=S1*f27m11Mf21m5+S3*f31m15Mf17m1+S5*f25m9Mf23m7-S7*f29m13Mf19m3;
  145.   s1Pf27s3f31s5f25s7f29=S1*f27m11Pf21m5+S3*f31m15Pf17m1-S5*f25m9Pf23m7+S7*f29m13Pf19m3;
  146.   s1Mf29s3f25s5f31s7f27=S1*f29m13Mf19m3+S3*f25m9Mf23m7-S5*f31m15Mf17m1+S7*f27m11Mf21m5;
  147.   s1Pf29s3f25s5f31s7f27=S1*f29m13Pf19m3+S3*f25m9Pf23m7+S5*f31m15Pf17m1-S7*f27m11Pf21m5;
  148.   s1Mf31s3f29s5f27s7f25=S1*f31m15Mf17m1-S3*f29m13Mf19m3+S5*f27m11Mf21m5-S7*f25m9Mf23m7;
  149.   s1Pf31s3f29s5f27s7f25=S1*f31m15Pf17m1+S3*f29m13Pf19m3+S5*f27m11Pf21m5+S7*f25m9Pf23m7;
  150.   s2Mf26Ps6Mf30=S2*f26m10Mf22m6+S6*f30m14Mf18m2;;
  151.   s2Pf26Ms6Pf30=S2*f26m10Pf22m6-S6*f30m14Pf18m2;
  152.   s2Mf30Ms6Mf26=S2*f30m14Mf18m2-S6*f26m10Mf22m6;
  153.   s2Pf30Ps6Pf26=S2*f30m14Pf18m2+S6*f26m10Pf22m6;
  154.   s4Mf28f20=S4*(f28m12-f20m4); s4Pf28f20=S4*(f28m12+f20m4);
  155.   s8f16=S8*(f[16]-f[0]); s8f24=S8*(f[24]-f[8]);
  156.   s4Mf28Ps8f16=s4Mf28f20+s8f16;
  157.   s4Mf28Ms8f16=s4Mf28f20-s8f16;
  158.   s4Pf28Ps8f24=s4Pf28f20+s8f24;
  159.   s4Pf28Ms8f24=s4Pf28f20-s8f24;
  160.   s2Mf26Ps4f28s6f30Ms8f16=s2Mf26Ps6Mf30+s4Mf28Ms8f16;
  161.   s2Mf26Ms4f28s6f30Ps8f16=s2Mf26Ps6Mf30-s4Mf28Ms8f16;
  162.   s2Pf26Ms4f28s6f30Ps8f24=s2Pf26Ms6Pf30-s4Pf28Ms8f24;
  163.   s2Pf26Ps4f28s6f30Ms8f24=s2Pf26Ms6Pf30+s4Pf28Ms8f24;
  164.   s2Mf30Ps4f28s6f26Ps8f16=s2Mf30Ms6Mf26+s4Mf28Ps8f16;
  165.   s2Mf30Ms4f28s6f26Ms8f16=s2Mf30Ms6Mf26-s4Mf28Ps8f16;
  166.   s2Pf30Ps4f28s6f26Ps8f24=s2Pf30Ps6Pf26+s4Pf28Ps8f24;
  167.   s2Pf30Ms4f28s6f26Ms8f24=s2Pf30Ps6Pf26-s4Pf28Ps8f24;
  168.   fft[1]=(abs(s1Mf25s3f27s5f29s7f31+s2Mf26Ps4f28s6f30Ms8f16)>>SCALE)+
  169.          (abs(s1Pf31s3f29s5f27s7f25+s2Pf30Ps4f28s6f26Ps8f24)>>SCALE);
  170.   fft[2]=(abs(s6Pf31f25Ps2Pf29f27+s4Pf30f22Ms8Mf24)>>SCALE)+
  171.          (abs(s6Mf29f27Ps2Mf31f25+s4Mf30f26Ps8Mf28)>>SCALE);
  172.   fft[3]=(abs(s2Mf30Ms4f28s6f26Ms8f16-s1Mf29s3f25s5f31s7f27)>>SCALE)+
  173.          (abs(s2Pf26Ms4f28s6f30Ps8f24-s1Pf27s3f31s5f25s7f29)>>SCALE);
  174.   fft[4]=(abs(s4Pf31f29f27f25-s8Pf28f24f20f16)>>SCALE)+
  175.          (abs(s4Mf31f29f27f25+s8Mf30f18f26f22)>>SCALE);
  176.   fft[5]=(abs(s1Mf27s3f31s5f25s7f29-s2Mf30Ps4f28s6f26Ps8f16)>>SCALE)+
  177.          (abs(s2Pf26Ps4f28s6f30Ms8f24-s1Pf29s3f25s5f31s7f27)>>SCALE);
  178.   fft[6]=(abs(s6Pf29f27Ms2Pf31f25+s4Pf30f22Ps8Mf24)>>SCALE)+
  179.          (abs(s6Mf31f25Ms2Mf29f27+s4Mf30f26Ms8Mf28)>>SCALE);
  180.   fft[7]=(abs(s1Mf31s3f29s5f27s7f25-s2Mf26Ms4f28s6f30Ps8f16)>>SCALE)+
  181.          (abs(s1Pf25s3f27s5f29s7f31-s2Pf30Ms4f28s6f26Ms8f24)>>SCALE);
  182.   fft[8]=(abs(S8*(f30p14Pf18p2+f26p10Pf22p6-f28p12Pf20p4-f24p8Pf16p0))>>SCALE)+
  183.          (abs(S8*(f31Mf17Mf25Mf23-f29Mf19Mf27Mf21))>>SCALE);
  184.   fft[9]=(abs(s1Mf31s3f29s5f27s7f25+s2Mf26Ms4f28s6f30Ps8f16)>>SCALE)+
  185.          (abs(s1Pf25s3f27s5f29s7f31+s2Pf30Ms4f28s6f26Ms8f24)>>SCALE);
  186.   fft[10]=(abs(s6Pf29f27Ms2Pf31f25-s4Pf30f22Ps8Mf24)>>SCALE)+
  187.           (abs(s4Mf30f26Ms8Mf28-s6Mf31f25Ms2Mf29f27)>>SCALE);
  188.   fft[11]=(abs(s1Mf27s3f31s5f25s7f29+s2Mf30Ps4f28s6f26Ps8f16)>>SCALE)+
  189.           (abs(s1Pf29s3f25s5f31s7f27+s2Pf26Ps4f28s6f30Ms8f24)>>SCALE);
  190.   fft[12]=(abs(s8Pf28f24f20f16+s4Pf31f29f27f25)>>SCALE)+
  191.           (abs(s8Mf30f18f26f22-s4Mf31f29f27f25)>>SCALE);
  192.   fft[13]=(abs(s1Mf29s3f25s5f31s7f27+s2Mf30Ms4f28s6f26Ms8f16)>>SCALE)+
  193.           (abs(s1Pf27s3f31s5f25s7f29+s2Pf26Ms4f28s6f30Ps8f24)>>SCALE);
  194.   fft[14]=(abs(s4Pf30f22Ms8Mf24-s6Pf31f25Ps2Pf29f27)>>SCALE)+
  195.           (abs(s4Mf30f26Ps8Mf28-s6Mf29f27Ps2Mf31f25)>>SCALE);
  196.   fft[15]=(abs(s2Mf26Ps4f28s6f30Ms8f16-s1Mf25s3f27s5f29s7f31)>>SCALE)+
  197.           (abs(s2Pf30Ps4f28s6f26Ps8f24-s1Pf31s3f29s5f27s7f25)>>SCALE);
  198. #ifdef DEBUG
  199.   for (l=1 ; l<N ; l++) a[l]=b[l]=0;
  200.   for (k=0 ; k<(N+N) ; k++) 
  201.     for (l=1 ; l<N ; l++) {
  202.       kl=(l*k)%(N+N);
  203.       a[l]+=f[k]*c[kl];
  204.       b[l]+=f[k]*s[kl];
  205.     }
  206.   for (l=1 ; l<N ; l++) {
  207.     fff[l]=(abs(a[l])>>SCALE)+(abs(b[l])>>SCALE);
  208.     if (fff[l]!=fft[l]) printf("l:%2d fft:%3d fff:%3d\n",l,fft[l],fff[l]);
  209.   }
  210. #endif
  211. #ifdef FFTDEBUG
  212.   gotoxy(1,1);
  213.   for (l=1 ; l<N ; l++) printf("%2d %7d\n",l,fft[l]);
  214. #endif
  215.   for (l=1,line=0 ; l<N ; l++,line+=160) {
  216.     oldlevel=oldfft[l];
  217.     level=oldfft[l]=fft[l];
  218.     for (k=1,column=2 ; k<=level ; k++,column+=2) 
  219.       pokeb(videoseg,80+line+column,'■');
  220.     for (k=level+1 ; k<=oldlevel ; k++,column+=2)  
  221.       pokeb(videoseg,80+line+column,' ');
  222.   }
  223. }
  224.  
  225. /*------------------------------ FFT to Tone ---------------------------------*/
  226.  
  227. #define FLIP 5 /* levels above average sufficient to trigger tone detected */
  228. #define LOG2N 4 /* Adjust according to N way above */ 
  229.  
  230. static int tonedetected=FALSE; /* indicates a tone is currently present */
  231. static int freqm2,freqm1,freqp1,freqp2,freq=(N>>1); /* interesting frequency */
  232.  
  233. void FFT2tone(void)
  234. { /* determines whether a morse tone is present or not */
  235.   static int old3active,old2active=FALSE,old1active=FALSE,active=FALSE; 
  236.   static int average,l,limit,oldtonedetected;
  237.  
  238.   average=0;
  239.   for (l=1 ; l<N ; l++) average+=fft[l];
  240.   average>>=LOG2N;
  241.   limit=FLIP+(5*average);
  242.   old3active=old2active;
  243.   old2active=old1active;
  244.   old1active=active;
  245.   active=( (fft[freqm2]+fft[freqp2]+fft[freqm1]+fft[freqp1]+fft[freq])>=limit );
  246.   oldtonedetected=tonedetected;
  247.   tonedetected=(active || old1active || old2active || old3active);
  248.   if (tonedetected && !oldtonedetected) pokeb(videoseg,158,'█');
  249.   else if (oldtonedetected && !tonedetected) pokeb(videoseg,158,'■');
  250. }
  251.  
  252. /*----------------------------- Tone to Morse --------------------------------*/
  253.  
  254. #define M 8 /* number of elements used to compute average element */
  255. #define LOG2M 3 /* adjust according to M above */
  256.  
  257. static int reset=TRUE;
  258. static int counterdots=0,counterdashes=0;
  259. static int sumdots=0,sumdashes=0;
  260. static int avrgdot=0,avrgdash=0;
  261. static int dots[M],dashes[M];
  262. static int dot=FALSE,dash=FALSE,space=FALSE;
  263. static int oncounter=0,offcounter=0;
  264. static int firsttone=0;
  265.  
  266. void learn(void)
  267. { /* learn dot and dash duration out of tone detection */
  268.  
  269.   if (tonedetected) oncounter+=waitfactor;
  270.   else 
  271.     if (oncounter>0) {
  272.       /* tone oncounter long just completed */
  273.       if (counterdots==0) { /* not one of each yet, must be starting to learn */
  274.         if (firsttone==0) firsttone=oncounter;
  275.         else /* make sure tones are different enough, ie dot and dash */
  276.           if (firsttone>oncounter) { /* which is dash and which is dot? */
  277.             if (firsttone>(oncounter<<1)) { /* firsttone=dash oncounter=dot */
  278.               dashes[0]=sumdashes=avrgdash=firsttone;
  279.               dots[0]=sumdots=avrgdot=oncounter;
  280.               counterdashes=counterdots=1;
  281.             } else firsttone=oncounter; /* not different enough */
  282.           } else {
  283.             if (oncounter>(firsttone<<1)) { /* oncounter=dash firsttone=dot */
  284.               dashes[0]=sumdashes=avrgdash=oncounter;
  285.               dots[0]=sumdots=avrgdot=firsttone;
  286.               counterdashes=counterdots=1;
  287.             } else firsttone=oncounter; /* not different enough */
  288.           }
  289.       } else { /* at least one instance of dot and dash encountered so far */
  290.         if (oncounter>((avrgdot+avrgdash)>>1)) {
  291.           if (counterdashes<M) { /* still some to learn about dashes */
  292.             dashes[counterdashes]=oncounter;
  293.             sumdashes+=oncounter;
  294.             counterdashes++;
  295.             avrgdash=sumdashes/counterdashes;
  296.           }
  297.         } else {
  298.           if (counterdots<M) { /* still some to learn about dots */
  299.             dots[counterdots]=oncounter;
  300.             sumdots+=oncounter;
  301.             counterdots++;
  302.             avrgdot=sumdots/counterdots;
  303.           }
  304.         }
  305.         if ((counterdots==M) && (counterdashes==M)) { /* enough learning */
  306.           counterdots=counterdashes=0;
  307.           reset=FALSE;
  308.         }
  309.       }
  310.       oncounter=0;
  311.     }
  312. }
  313.  
  314. void tone2morse(void)
  315. { /* deduces dot or dash or space out of tone detection */
  316.  
  317.   if (tonedetected) {
  318.     oncounter+=waitfactor;
  319.     if (offcounter>0) {
  320.       /* silence offcounter long just completed */
  321.       if (offcounter>((avrgdot+avrgdot+avrgdot+avrgdash)>>2)) space=TRUE;
  322.       offcounter=0;
  323.     }
  324.   } else {
  325.     offcounter+=waitfactor;
  326.     if (oncounter>0) {
  327.       /* tone oncounter long just completed */
  328.       if (oncounter>((avrgdot+avrgdash)>>1)) {
  329.         dash=TRUE;
  330.         sumdashes-=dashes[counterdashes];
  331.         dashes[counterdashes]=oncounter;
  332.         sumdashes+=oncounter;
  333.         avrgdash=(sumdashes>>LOG2M);
  334.         if (counterdashes==(M-1)) counterdashes=0;
  335.         else counterdashes++;
  336.       } else {
  337.         dot=TRUE;
  338.         sumdots-=dots[counterdots];
  339.         dots[counterdots]=oncounter;
  340.         sumdots+=oncounter;
  341.         avrgdot=(sumdots>>LOG2M);
  342.         if (counterdots==(M-1)) counterdots=0;
  343.         else counterdots++;
  344.       }
  345.       oncounter=0;
  346.     }
  347.   }
  348. }
  349.  
  350. /*----------------------------- Morse to Text --------------------------------*/
  351.  
  352. void morse2text(void)
  353. { /* outputs text on the screen */
  354.   static int code=0,mask=1,x=1,y=1,y160=160,punctuation;
  355.   static char c;
  356.  
  357.   if (dot) {
  358.     code+=mask;
  359.     mask<<=1;
  360.     dot=FALSE;
  361.   } else
  362.     if (dash) {
  363.       mask<<=1;
  364.       dash=FALSE;
  365.     } else
  366.       if (space) {
  367.         code+=mask;
  368.         switch (code) {
  369.           case 2:c='T'; punctuation=FALSE; break;
  370.           case 3:c='E'; punctuation=FALSE; break;
  371.           case 4:c='M'; punctuation=FALSE; break;
  372.           case 5:c='A'; punctuation=FALSE; break;
  373.           case 6:c='N'; punctuation=FALSE; break;
  374.           case 7:c='I'; punctuation=FALSE; break;
  375.           case 8:c='O'; punctuation=FALSE; break;
  376.           case 9:c='W'; punctuation=FALSE; break;
  377.           case 10:c='K'; punctuation=FALSE; break;
  378.           case 11:c='U'; punctuation=FALSE; break;
  379.           case 12:c='G'; punctuation=FALSE; break;
  380.           case 13:c='R'; punctuation=FALSE; break;
  381.           case 14:c='D'; punctuation=FALSE; break;
  382.           case 15:c='S'; punctuation=FALSE; break;
  383.           case 17:c='J'; punctuation=FALSE; break;
  384.           case 18:c='Y'; punctuation=FALSE; break;
  385.           case 19:c='Ü'; punctuation=FALSE; break;
  386.           case 20:c='Q'; punctuation=FALSE; break;
  387.           case 21:c='Ä'; punctuation=FALSE; break;
  388.           case 22:c='X'; punctuation=FALSE; break;
  389.           case 23:c='V'; punctuation=FALSE; break;
  390.           case 24:c='Ö'; punctuation=FALSE; break;
  391.           case 25:c='P'; punctuation=FALSE; break;
  392.           case 26:c='C'; punctuation=FALSE; break;
  393.           case 27:c='F'; punctuation=FALSE; break;
  394.           case 28:c='Z'; punctuation=FALSE; break;
  395.           case 29:c='L'; punctuation=FALSE; break;
  396.           case 30:c='B'; punctuation=FALSE; break;
  397.           case 31:c='H'; punctuation=FALSE; break;
  398.           case 32:c='0'; punctuation=FALSE; break;
  399.           case 33:c='1'; punctuation=FALSE; break;
  400.           case 35:c='2'; punctuation=FALSE; break;
  401.           case 36:c='Ñ'; punctuation=FALSE; break;
  402.           case 39:c='3'; punctuation=FALSE; break;
  403.           case 41:c='Å'; punctuation=FALSE; break;
  404.           case 47:c='4'; punctuation=FALSE; break;
  405.           case 48:c='9'; punctuation=FALSE; break;
  406.           case 54:c='/'; punctuation=FALSE; break;
  407.           case 56:c='8'; punctuation=FALSE; break;
  408.           case 59:c='É'; punctuation=FALSE; break;
  409.           case 60:c='7'; punctuation=FALSE; break;
  410.           case 62:c='6'; punctuation=FALSE; break;
  411.           case 63:c='5'; punctuation=FALSE; break;
  412.           case 76:c=','; punctuation=TRUE; break;
  413.           case 82:c='|'; punctuation=FALSE; break;
  414.           case 85:c='.'; punctuation=TRUE; break;
  415.           case 94:c='-'; punctuation=FALSE; break;
  416.           case 106:c=';'; punctuation=TRUE; break;
  417.           case 115:c='?'; punctuation=TRUE; break;
  418.           case 120:c=':'; punctuation=TRUE; break;
  419.           default:c='■'; punctuation=FALSE; break;
  420.         }
  421.         pokeb(videoseg,(x<<1)+y160,c);
  422.         x++;
  423.         if (x==35) {
  424.           y++; y160+=160;
  425.           if (y==24) {y=1; y160=160;}
  426.           for (x=1 ; x<35 ; x++) pokeb(videoseg,(x<<1)+y160,' ');
  427.           x=1;
  428.         }
  429.         if (punctuation) {
  430.           pokeb(videoseg,(x<<1)+y160,' ');
  431.           x++;
  432.           if (x==35) {
  433.             y++; y160+=160;
  434.             if (y==24) {y=1; y160=160;}
  435.             for (x=1 ; x<35 ; x++) pokeb(videoseg,(x<<1)+y160,' ');
  436.             x=1;
  437.           }
  438.         }
  439.         pokeb(videoseg,(x<<1)+y160,'_');
  440.         code=0; mask=1;
  441.         space=FALSE;
  442.       }
  443. }
  444.  
  445. /*-------------------------------- Keyboard ----------------------------------*/
  446.  
  447. void updatecursor(char c1, char c2)
  448. { /* displays selected frequency cursor */
  449.   freqp1=freq+1; freqm1=freq-1; freqp2=freq+2; freqm2=freq-2;
  450.   pokeb(videoseg,(74-160)+(160*freqm2),c1);
  451.   pokeb(videoseg,(74-160)+(160*freqm1),c1);
  452.   pokeb(videoseg,(74-160)+(160*freq),c1);
  453.   pokeb(videoseg,(74-160)+(160*freqp1),c1);
  454.   pokeb(videoseg,(74-160)+(160*freqp2),c1);
  455.   pokeb(videoseg,(76-160)+(160*freqm2),c2);
  456.   pokeb(videoseg,(76-160)+(160*freqm1),c2);
  457.   pokeb(videoseg,(76-160)+(160*freq),c2);
  458.   pokeb(videoseg,(76-160)+(160*freqp1),c2);
  459.   pokeb(videoseg,(76-160)+(160*freqp2),c2);
  460. }
  461.  
  462. #include <bios.h>
  463.  
  464. #define UPKEY     0x4800
  465. #define SUPKEY    0x4838
  466. #define SFIVEKEY  0x4C35
  467. #define DOWNKEY   0x5000   
  468. #define SDOWNKEY  0x5032
  469. #define ESCKEY    0x011B
  470. #define PLUSKEY   0x4E2B
  471. #define PLUSKEY2  0x0D2B
  472. #define MINUSKEY  0x4A2D
  473. #define MINUSKEY2 0x0C2D
  474. #define SPACEKEY  0x3920
  475. #define STARKEY   0x372A
  476. #define STARKEY2  0x092A
  477. #define OFFSTRING "Toggle FFT On/Off with Space  (now off)"
  478. #define ONSTRING  "Toggle FFT On/Off with Space  (now on) "
  479. #define WAITSTRING "S-Blaster DSP Mixture Ratio 1:%d  (+/-) "
  480.  
  481. void handlekey(int *done)
  482. { /* read key pressed and act accordingly */
  483.   updatecursor(' ',' ');
  484.   switch (bioskey(0)) {
  485.     case UPKEY:if (freq>3) freq--; break;
  486.     case DOWNKEY:if (freq<(N-3)) freq++; break;
  487.     case SUPKEY:freq=3; break;
  488.     case SDOWNKEY:freq=N-3; break;
  489.     case SFIVEKEY:freq=(N>>1); break;
  490.     case PLUSKEY:
  491.     case PLUSKEY2:waitfactor++; gotoxy(40,25);
  492.                   cprintf(WAITSTRING,waitfactor);
  493.                   break;
  494.     case MINUSKEY:
  495.     case MINUSKEY2:if (waitfactor>1) {
  496.                      waitfactor--; gotoxy(40,25);
  497.                      cprintf(WAITSTRING,waitfactor);
  498.                    }
  499.                    break;
  500.     case SPACEKEY:FFTenable=!FFTenable; 
  501.                   gotoxy(40,20);
  502.                   if (FFTenable) cprintf(ONSTRING); 
  503.                   else cprintf(OFFSTRING);
  504.                   break;
  505.     case STARKEY:
  506.     case STARKEY2:reset=TRUE; 
  507.                   counterdots=counterdashes=0;
  508.                   sumdots=sumdashes=0;
  509.                   avrgdot=avrgdash=0;
  510.                   firsttone=0;
  511.                   break;
  512.     case ESCKEY:*done=TRUE; break;
  513.   }
  514.   updatecursor('=','>');
  515. }
  516.  
  517. /*------------------------------- Initialize ---------------------------------*/
  518.  
  519. #ifdef DEBUG
  520. #include <math.h>
  521. #endif
  522.  
  523. #ifdef DEBUG
  524. #define CTEPI (3.14159265358979323846/(float)N)
  525. #define TRIG  16 /* trig table lookup precision compatible with S? way above */
  526. #endif
  527. #define COPYSTRING "FFT Morse (c) 1992 François Jalbert"
  528. #define FREQSTRING "Lock Frequency with Up and Down Arrows"
  529. #define EXITSTRING "Exit with Esc"
  530.  
  531. void begin(void)
  532. { /* initializes screen, data & SB */
  533. #ifdef DEBUG
  534.   static float xx,ss,cc;
  535.   static int k;
  536. #endif
  537.   static int l,line,xx,yy;
  538.   static struct text_info info;
  539.  
  540.   clrscr();
  541.   if (reset_dsp()!=SBOK) {
  542.     printf("Ne peut pas initialiser DSP!\7\n\n");
  543.     exit(1);
  544.   }
  545.   gettextinfo(&info);
  546.   if (info.currmode==7) videoseg=0xB000;
  547.   for (xx=1 ; xx<=34 ; xx++) pokeb(videoseg,(xx<<1),'─');
  548.   for (xx=1 ; xx<=34 ; xx++) pokeb(videoseg,(xx<<1)+(160*24),'─');
  549.   for (yy=1 ; yy<=23 ; yy++) pokeb(videoseg,(160*yy),'│');
  550.   for (yy=1 ; yy<=23 ; yy++) pokeb(videoseg,(35<<1)+(160*yy),'│');
  551.   pokeb(videoseg,0,'┌');
  552.   pokeb(videoseg,(35<<1),'┐');
  553.   pokeb(videoseg,(160*24),'└');
  554.   pokeb(videoseg,(35<<1)+(160*24),'┘');
  555.   gotoxy(40,17); cprintf(COPYSTRING);
  556.   gotoxy(40,19); cprintf(FREQSTRING);
  557.   gotoxy(40,20); if (FFTenable) cprintf(ONSTRING); else cprintf(OFFSTRING);
  558.   gotoxy(40,21); cprintf(EXITSTRING);
  559.   gotoxy(40,25); cprintf(WAITSTRING,waitfactor);
  560.   updatecursor('=','>');
  561.   for (l=1,line=0 ; l<N ; l++,line+=160) {
  562.     fft[l]=0;
  563.     pokeb(videoseg,80+line,'≡');
  564.   }
  565. #ifdef DEBUG
  566.   for (k=0 ; k<(N+N) ; k++) {
  567.     xx=CTEPI*k;
  568.     ss=TRIG*sin(xx);
  569.     cc=TRIG*cos(xx);
  570.     if (ss>0.0) ss+=0.5; else ss-=0.5;
  571.     if (cc>0.0) cc+=0.5; else cc-=0.5;
  572.     s[k]=(int)ss; /* truncate */
  573.     c[k]=(int)cc; /* truncate */
  574.   }
  575. #endif
  576. }
  577.  
  578. /*---------------------------------- main ------------------------------------*/
  579.  
  580. #include <time.h>
  581.  
  582. #define KCHECK 64 /* ratio of key pressed checks versus FFT cycles  */
  583. #define SCHECK 16 /* ratio of sampling rate checks versus key checks */
  584. #define SAMPSTRING "%d S-Blaster Samples per Second  "
  585. #define STATSTRING "Avrg Dot:%d  Avrg Dash:%d (* resets) "
  586.  
  587. void main(void)
  588. {
  589.   static int done=FALSE,counter=0;
  590.   static int kloop,sloop,delta,k;
  591.   static long int start,current;
  592.  
  593.   begin();
  594.   time(&start);
  595.   speaker_on();
  596.   while (!done) {
  597.     for (sloop=1 ; sloop<=SCHECK ; sloop++) {
  598.       if (FFTenable) 
  599.         for (kloop=1 ; kloop<=KCHECK ; kloop++) {
  600.           FFT();
  601.           FFT2tone();
  602.           if (reset) learn();
  603.           else {
  604.             tone2morse();
  605.             morse2text(); 
  606.           }
  607.         }
  608.       else
  609.         for (kloop=1 ; kloop<=KCHECK ; kloop++)
  610.           for (k=0 ; k<(N+N) ; k++) read_data();
  611.       if (bioskey(1)!=0) {
  612.         handlekey(&done);
  613.         if (done) goto abortit; /* get out quickly, facultative statement */
  614.       }
  615.     }
  616.     counter+=(N+N);
  617.     time(¤t);
  618.     delta=(int)(current-start);
  619.     if (delta>2) {
  620.       gotoxy(40,24);
  621.       cprintf(SAMPSTRING, counter*((KCHECK*SCHECK)/delta) );
  622.       start=current;
  623.       counter=0;
  624.     } 
  625.     gotoxy(40,23);
  626.     cprintf(STATSTRING,avrgdot,avrgdash);
  627.   }
  628.   abortit:
  629.   speaker_off();
  630.   gotoxy(1,24);
  631. }
  632.