#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

const char * UsageLines [] = {
       "Usage: swwritecw (cycles per word) (samples per word) (# of words)",
       "Writes a headerless sound file, .sw, to standard output consisting",
       "of a constant pitch note, morse-code keyed with random content.",
       "",
       "The text used will be output on standard error.",
       "",
       "The pitch will depend on the playback speed, and is given by:",
       "(playback speed in samples/sec) x (cycles per word) / (samples per word)",
       "",
       "The sending speed will also depend on the playback speed, and is",
       "(playback speed in samples/sec) x (60 sec/min) / (samples per word)",
       "",
       "example of use:",
       "swwritecw 2333 25000 25 > sound.sw 2> key.txt",
       "sox sound.sw sound.wav (will use default 8000 samples per sec)",
       "",
       "Will use a pitch of 700 Hz and send 18 wpm",
       "",
       "(Number of words is also used as a random key)",
       "May 22, 2019.  Latest is at gopher://sdf.org/0/users/julianbr",
       "",
       };
const int NumUsageLines = sizeof UsageLines / sizeof (UsageLines [0] );

const static struct {
       char letter;
       char * code;
       } Elements [] = {
       { 'a', ".-" },
       { 'b', "-..." },
       { 'c', "-.-." },
       { 'd', "-.." },
       { 'e', "." },
       { 'f', "..-." },
       { 'g', "-.." },
       { 'h', "...." },
       { 'i', ".." },
       { 'j', ".---" },
       { 'k', "-.-" },
       { 'l', ".-.." },
       { 'm', "--" },
       { 'n', "-." },
       { 'o', "---" },
       { 'p', ".--." },
       { 'q', "--.-" },
       { 'r', ".-." },
       { 's', "..." },
       { 't', "-" },
       { 'u', "..-" },
       { 'v', "...-" },
       { 'w', ".--" },
       { 'x', "-..-" },
       { 'y', "-.--" },
       { 'z', "--.." },
       { '.', ".-.-.-" },
       { ',', "--..--" },
       { '?', "..--.." },
       { '/', "-..-." },
       { '1', ".----" },
       { '2', "..---" },
       { '3', "...--" },
       { '4', "....-" },
       { '5', "....." },
       { '6', "-...." },
       { '7', "--..." },
       { '8', "---.." },
       { '9', "----." },
       { '0', "-----" },
       { 'e', "." },
       { 'e', "." },
       { 'e', "." },
       { 'e', "." },
       { 'e', "." },
       { 'e', "." },
       { 't', "-" },
       { 't', "-" },
       { 't', "-" },
       { 'i', ".." },
       { 'i', ".." },
       { 'i', ".." },
       { 'a', ".-" },
       { 'n', "-." },
       { 's', "..." },
       };
#define NumElements sizeof Elements / sizeof (Elements [0] )

int main (int argc, char * * argv)
       {
       unsigned long int CyclesPerWord, SamplesPerWord, NumWords;
       unsigned long int a, r, m, mmax, n;
       char letter, * code;
       int element, LenWord, i, j, k;
       char c;

       if (argc < 2) {
               for (i = 0; i < NumUsageLines; i++)
                       printf ("%s\n", UsageLines [i] );
               }
       if (argc != 4
                       || sscanf (argv [1], "%lu%c", & CyclesPerWord, & c) != 1
                       || sscanf (argv [2], "%lu%c", & SamplesPerWord, & c) != 1
                       || sscanf (argv [3], "%lu%c", & NumWords, & c) != 1
                       ) {
               fprintf (stderr, "Usage: %s (Cycles Per Word)", argv [0] );
               fprintf (stderr, " (Samples Per Word)");
               fprintf (stderr, " (number of words).\n");
               return 0;
               }
       srand (NumWords);
       n = 0;
       for (i = 0; i < NumWords; i++) {
               r = rand ()/113;
               LenWord = 1 + r%8;
               m = 0;
               /* silence at beginning of word */
               mmax = 16*SamplesPerWord;
               while (m < mmax) {
                       n = (n + CyclesPerWord)%SamplesPerWord;
                       if (n + n < SamplesPerWord)
                               a = 32768;
                       else
                               a = 32767;
                       putchar (a%256);
                       putchar ((a/256)^128);
                       m += 400;
                       }
               m -= mmax;

               for (j = 0; j < LenWord; j++) {
                       r = rand ()/1113;
                       element = r%NumElements;
                       letter = Elements [element].letter;
                       code = Elements [element].code;
                       /* silence at beginning of letter */
                       mmax = 8*SamplesPerWord;
                       while (m < mmax) {
                               n = (n + CyclesPerWord)%SamplesPerWord;
                               if (n + n < SamplesPerWord)
                                       a = 32768;
                               else
                                       a = 32767;
                               putchar (a%256);
                               putchar ((a/256)^128);
                               m += 400;
                               }
                       m -= mmax;

                       k = 0;
                       c = code [k];
                       while (c != '\0') {
                               /* silence at beginning of component */
                               mmax = 3*SamplesPerWord;
                               while (m < mmax) {
                                       n = (n + CyclesPerWord)%SamplesPerWord;
                                       if (n + n < SamplesPerWord)
                                               a = 32768;
                                       else
                                               a = 32767;
                                       putchar (a%256);
                                       putchar ((a/256)^128);
                                       m += 400;
                                       }
                               m -= mmax;

                               /* component rise time */
                               mmax = 2*SamplesPerWord;
                               while (m < mmax) {
                                       n = (n + CyclesPerWord)%SamplesPerWord;
                                       if (n + n < SamplesPerWord)
                                               a = 32768 + 20000*sin(M_PI*(n + n)/SamplesPerWord)*m/mmax;
                                       else
                                               a = 32767 - 20000*sin(M_PI*(n + n - SamplesPerWord)/SamplesPerWord)*m/mmax;
                                       putchar (a%256);
                                       putchar ((a/256)^128);
                                       m += 400;
                                       }
                               m -= mmax;

                               /* component dwell time */
                                       mmax = 6*SamplesPerWord;
                               if (c == '-')
                                       mmax = 22*SamplesPerWord;
                               while (m < mmax) {
                                       n = (n + CyclesPerWord)%SamplesPerWord;
                                       if (n + n < SamplesPerWord)
                                               a = 32768 + 20000*sin (M_PI*(n + n)/SamplesPerWord);
                                       else
                                               a = 32767 - 20000*sin (M_PI*(n + n - SamplesPerWord)/SamplesPerWord);
                                       putchar (a%256);
                                       putchar ((a/256)^128);
                                       m += 400;
                                       }
                               m -= mmax;

                               /* component fall time */
                               mmax = 2*SamplesPerWord;
                               while (m < mmax) {
                                       n = (n + CyclesPerWord)%SamplesPerWord;
                                       if (n + n < SamplesPerWord)
                                               a = 32768 + 20000*sin(M_PI*(n + n)/SamplesPerWord)*(mmax - m)/mmax;
                                       else
                                               a = 32767 - 20000*sin(M_PI*(n + n - SamplesPerWord)/SamplesPerWord)*(mmax - m)/mmax;
                                       putchar (a%256);
                                       putchar ((a/256)^128);
                                       m += 400;
                                       }
                               m -= mmax;

                               /* silence at end of component */
                               mmax = 3*SamplesPerWord;
                               while (m < mmax) {
                                       n = (n + CyclesPerWord)%SamplesPerWord;
                                       if (n + n < SamplesPerWord)
                                               a = 32768;
                                       else
                                               a = 32767;
                                       putchar (a%256);
                                       putchar ((a/256)^128);
                                       m += 400;
                                       }
                               m -= mmax;

                               k++;
                               c = code [k];
                               }
                       fprintf (stderr, "%c", letter);
                       /* silence at end of letter */
                       mmax = 8*SamplesPerWord;
                       while (m < mmax) {
                               n = (n + CyclesPerWord)%SamplesPerWord;
                               if (n + n < SamplesPerWord)
                                       a = 32768;
                               else
                                       a = 32767;
                               putchar (a%256);
                               putchar ((a/256)^128);
                               m += 400;
                               }
                       m -= mmax;

                       }
               fprintf (stderr, " ");
               /* silence at end of word */
               mmax = 16*SamplesPerWord;
               while (m < mmax) {
                       n = (n + CyclesPerWord)%SamplesPerWord;
                       if (n + n < SamplesPerWord)
                               a = 32768;
                       else
                               a = 32767;
                       putchar (a%256);
                       putchar ((a/256)^128);
                       m += 400;
                       }
               m -= mmax;

               }
       fprintf (stderr, "\n");
       fprintf (stderr, "\n");
       return 0;
       }