const char * UsageLines [] = {
"Usage: swnotes (beats per second) (sample rate) (key)",
"Reads text describing notes from standard input.",
"Writes headerless sound file to standard output.",
"Reads whitespace-separated groups of the form:",
"[(repetition)x](duration)[:(note)][,(note)]...",
"All must be non-negative integers. Duration is measured in beats.",
"A duration without notes will produce silence.",
"Each note value must be between 0 and 72.",
"For a key of 0, note 41 has a pitch of 440 Hz. Each higher/",
"lower note number has a pitch one semitone higher/lower using",
"equal temperament.",
"Example of scale CDEFGABC: 1:44 1:46 1:48 1:49 1:51 1:53 1:55 1:56",
"Example C-chord ECEGCE (lasting 10 beats, played 3 times):",
"\t3x10:12,20,24,27,32,36",
"Specifying a key other than 0 will shift the key upward (+)",
"or downward (-) by the specified number of semitones.",
"Sample rate is in Hz, for example 8000 for 8kHz.",
"Writes mono, signed, two-byte-per-sample,",
"\tLS byte first sound file (.sw).",
"Anything from # to end of line is considered a comment.",
"May 16, 2011. Newest is at gopher -p users/julianbr sdf.org",
};
const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] );
/* Compile with -lm */
#include <stdio.h>
#include <math.h>
void PlayChord (
int NumBeats,
int * notes,
unsigned long int BeatsPerSecond,
unsigned long int SamplesPerSecond,
int key)
{
unsigned long int sample, SamplesPerBeat, NumSamples, NoteHz;
unsigned long int amplitude, AmplitudeEachNote;
unsigned int AmplitudeThisNote, AmplitudeAllNotes;
int NumUsedNotes, note;
float shape;
float log2over12;
int PlayChords (
unsigned long int BeatsPerSecond,
unsigned long int SamplesPerSecond,
int key)
{
int notes [NumNotes];
int c, NumRepetitions, NumBeats, note, i;
c = getchar ();
while (c == ' ' || c == '\t' || c == '\n')
c = getchar ();
while (c != EOF) {
NumRepetitions = 0;
while (c >= '0' && c <= '9') {
NumRepetitions = 10*NumRepetitions + (c - '0');
c = getchar ();
}
if (c == 'x') {
c = getchar ();
NumBeats = 0;
while (c >= '0' && c <= '9') {
NumBeats = 10*NumBeats + (c - '0');
c = getchar ();
}
}
else {
NumBeats = NumRepetitions;
NumRepetitions = 1;
}
if (c == ':')
c = getchar ();
note = 0;
while (note < sizeof (notes)/sizeof (notes [0] ) ) {
notes [note] = 0;
note++;
}
while (c >= '0' && c <= '9') {
note = 0;
while (c >= '0' && c <= '9') {
note = 10*note + (c - '0');
c = getchar ();
}
if (note >= sizeof (notes)/sizeof (note) ) {
fprintf (stderr, "***swnotes: Improper note");
fprintf (stderr, " number: %d.\n", note);
return 0;
}
notes [note]++;
if (c == ',')
c = getchar ();
}
if (c == '#') {
/* Treat anything from # to end of line as a comment */
while (c != EOF && c != '\n')
c = getchar ();
}
else if (!(c == EOF || c == ' ' || c == '\t' || c == '\n') ) {
fprintf (stderr, "***swnotes: Improper input");
fprintf (stderr, " character: '%c'.\n", c);
return 0;
}
for (i = 0; i < NumRepetitions; i++)
PlayChord (
NumBeats,
notes,
BeatsPerSecond,
SamplesPerSecond,
key);
while (c == ' ' || c == '\t' || c == '\n')
c = getchar ();
}
return 1;
}
int main (int argc, char * argv [] )
{
unsigned long int BeatsPerSecond, SamplesPerSecond;
int i, key, ok;
char c;
if (argc < 2) {
for (i = 0; i < NumUsageLines; i++)
printf ("%s\n", UsageLines [i] );
}
else if (argc == 4) {
ok = 1;
if (sscanf (argv [1], "%lu%c", & BeatsPerSecond, & c) != 1
|| BeatsPerSecond < 1) {
fprintf (stderr, "***swnotes: Expecting number > 0");
fprintf (stderr, " for beats per second, found");
fprintf (stderr, " \"%s\".\n", argv [1] );
ok = 0;
}
if (sscanf (argv [2], "%lu%c", & SamplesPerSecond, & c) != 1
|| SamplesPerSecond < 1) {
fprintf (stderr, "***swnotes: Expecting number > 0");
fprintf (stderr, " for samples per second, found");
fprintf (stderr, " \"%s\".\n", argv [2] );
ok = 0;
}
if (sscanf (argv [3], "%d%c", & key, & c) != 1) {
fprintf (stderr, "***swnotes: Expecting number");
fprintf (stderr, " for key, found");
fprintf (stderr, " \"%s\".\n", argv [3] );
ok = 0;
}
if (ok)
PlayChords (BeatsPerSecond, SamplesPerSecond, key);
}
else {
fprintf (stderr, "Usage: swmix (beats per second)");
fprintf (stderr, " (samples per second) (key)\n");
}
return 0;
}