#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;
	}