/*
 *  SoundAlgorithm.cpp
 *  AudioUIdemo
 *
 *	Code and Sound Design by Peter "pdx" Drescher.
 *  Copyright 2010 twittering machine. All rights reserved.
 *
 *  Uses the "flip coin / throw dice" methods described in 
 *  Martin Gardener's article "White, Brown, and Fractal Music" c. 1978.
 *	This seminal piece relates fractal math, procedural music, CGI landscapes,
 *	and the human nervous system's perception of reality ... and
 *	inspired my interest in computer music in the first place.
 *  http://www.twittering.com/twittering/code/docs/WhiteBrownFractalMusic.pdf
 *
 */

#include "SoundAlgorithm.h"

int prevByteCounter, currByteCounter;
int pinkDice[6];

void initSoundAlgorithm ()
{
	srand ( time(NULL) );
	prevByteCounter = 0;
	currByteCounter = 0;
}

//  throw six dice, and add the results to produce a random position in the array
int calcWhiteNoise ()
{
	int arrayPos = 0;
	int dice[6];
	for (int c = 0; c < 6; c++) {
		dice[c] = (rand() % 6) + 1;
		arrayPos += dice[c];
	}
	return (arrayPos);
}

//  throw dice depending on an increasing binary pattern of bits changed, i.e.
//  0 = 0x0000 = throw all dice
//  1 = 0x0001 = throw #1
//  2 = 0x0010 = throw #1, #2
//  3 = 0x0011 = throw #1
//  4 = 0x0100 = throw #1, #2, #3
//  5 = 0x0101 = throw #1
//  ...
int calcPinkNoise ()
{
	int arrayPos = 0;
	int bitsChanged = 0;
	
	if (currByteCounter == 0)
	{
		currByteCounter++;
		for (int c = 0; c < 6; c++)
		{
			pinkDice[c] = (rand() % 6) + 1;
			arrayPos += pinkDice[c];
		}
	}
	else
	{
		prevByteCounter = currByteCounter++;
		bitsChanged = prevByteCounter ^ currByteCounter;

		for (int c = 0; c < 6; c++)
		{
			if (bitsChanged & (1 << c))
			{
				arrayPos += pinkDice[c];
			}
			else
			{				
				pinkDice[c] = (rand() % 6) + 1;
				arrayPos += pinkDice[c];
			}
		}
	}
	return (arrayPos);
}

//  flip a coin to determine the direction to move a small random amount
int calcBrownian(int arrayPos)
{
	int flipCoin;
	if ((flipCoin = (random() % 2)) == 0) {
		arrayPos += (random() % 4);
	} else {
		arrayPos -= (random() % 4);
	}
	
	// edge cases: "bounce" off top or bottom of array
	if (arrayPos > 40) {
		arrayPos -= 4;
	} else if (arrayPos < 0) {
		arrayPos += 4;
	}
	
	return (arrayPos);
}

//  assign a sound to keys alphabetically
int calcWeightedAlpha(char ch1)
{
	int arrayPos;
	
	if		((ch1 == '0') || (ch1 ==')')) arrayPos = 0;
	else if ((ch1 == '1') || (ch1 =='!')) arrayPos = 1;
	else if ((ch1 == '2') || (ch1 =='@')) arrayPos = 2;
	else if ((ch1 == '3') || (ch1 =='#')) arrayPos = 3;
	else if ((ch1 == '4') || (ch1 =='$')) arrayPos = 4;
	else if ((ch1 == '5') || (ch1 =='%')) arrayPos = 5;
	else if ((ch1 == '6') || (ch1 =='^')) arrayPos = 6;
	else if ((ch1 == '7') || (ch1 =='&')) arrayPos = 7;
	else if ((ch1 == '8') || (ch1 =='*')) arrayPos = 8;
	else if ((ch1 == '9') || (ch1 =='(')) arrayPos = 9;
	else if	((ch1 == 'a') || (ch1 =='A')) arrayPos = 10;
	else if ((ch1 == 'b') || (ch1 =='B')) arrayPos = 11;
	else if ((ch1 == 'c') || (ch1 =='C')) arrayPos = 12;
	else if ((ch1 == 'd') || (ch1 =='D')) arrayPos = 13;
	else if ((ch1 == 'e') || (ch1 =='E')) arrayPos = 14;
	else if ((ch1 == 'f') || (ch1 =='F')) arrayPos = 15;
	else if ((ch1 == 'g') || (ch1 =='G')) arrayPos = 16;
	else if ((ch1 == 'h') || (ch1 =='H')) arrayPos = 18;
	else if ((ch1 == 'i') || (ch1 =='I')) arrayPos = 19;
	else if ((ch1 == 'j') || (ch1 =='J')) arrayPos = 20;
	else if ((ch1 == 'k') || (ch1 =='K')) arrayPos = 21;
	else if ((ch1 == 'l') || (ch1 =='L')) arrayPos = 22;
	else if ((ch1 == 'm') || (ch1 =='M')) arrayPos = 23;
	else if ((ch1 == 'n') || (ch1 =='N')) arrayPos = 24;
	else if ((ch1 == 'o') || (ch1 =='O')) arrayPos = 25;
	else if ((ch1 == 'p') || (ch1 =='P')) arrayPos = 26;
	else if ((ch1 == 'q') || (ch1 =='Q')) arrayPos = 27;
	else if ((ch1 == 'r') || (ch1 =='R')) arrayPos = 28;
	else if ((ch1 == 's') || (ch1 =='S')) arrayPos = 29;
	else if ((ch1 == 't') || (ch1 =='T')) arrayPos = 30;
	else if ((ch1 == 'u') || (ch1 =='U')) arrayPos = 31;
	else if ((ch1 == 'v') || (ch1 =='V')) arrayPos = 32;
	else if ((ch1 == 'w') || (ch1 =='W')) arrayPos = 33;
	else if ((ch1 == 'x') || (ch1 =='X')) arrayPos = 34;
	else if ((ch1 == 'y') || (ch1 =='Y')) arrayPos = 35;
	else if ((ch1 == 'z') || (ch1 =='Z')) arrayPos = 36;
	else if ((ch1 == ':') || (ch1 ==';')) arrayPos = 37;
	else if ((ch1 == ',') || (ch1 =='<')) arrayPos = 38;
	else if ((ch1 == '.') || (ch1 =='>')) arrayPos = 39;
	else if ((ch1 == '/') || (ch1 =='?')) arrayPos = 40;
	else if ((ch1 == '[') || (ch1 =='{')) arrayPos = 1;
	else if ((ch1 == ']') || (ch1 =='}')) arrayPos = 2;
	else if ((ch1 == '-') || (ch1 =='_')) arrayPos = 3;
	else if ((ch1 == '=') || (ch1 =='+')) arrayPos = 4;
	else if  (ch1 == ' ') arrayPos = 20;
	else arrayPos = 0;
	
	return arrayPos;
}

//  assign a sound to keys based on the Qwerty keyboard layout
int calcWeightedQwerty(char ch1)
{
	int arrayPos;
	
	if		((ch1 == '1') || (ch1 =='!')) arrayPos = 0;
	else if ((ch1 == '2') || (ch1 =='@')) arrayPos = 1;
	else if ((ch1 == '3') || (ch1 =='#')) arrayPos = 2;
	else if ((ch1 == '4') || (ch1 =='$')) arrayPos = 3;
	else if ((ch1 == '5') || (ch1 =='%')) arrayPos = 4;
	else if ((ch1 == '6') || (ch1 =='^')) arrayPos = 5;
	else if ((ch1 == '7') || (ch1 =='&')) arrayPos = 6;
	else if ((ch1 == '8') || (ch1 =='*')) arrayPos = 7;
	else if ((ch1 == '9') || (ch1 =='(')) arrayPos = 8;
	else if ((ch1 == '0') || (ch1 ==')')) arrayPos = 9;
	else if	((ch1 == '-') || (ch1 =='_')) arrayPos = 10;
	else if ((ch1 == '=') || (ch1 =='+')) arrayPos = 11;
	else if ((ch1 == 'q') || (ch1 =='Q')) arrayPos = 12;
	else if ((ch1 == 'w') || (ch1 =='W')) arrayPos = 13;
	else if ((ch1 == 'e') || (ch1 =='E')) arrayPos = 14;
	else if ((ch1 == 'r') || (ch1 =='R')) arrayPos = 15;
	else if ((ch1 == 't') || (ch1 =='T')) arrayPos = 16;
	else if ((ch1 == 'y') || (ch1 =='Y')) arrayPos = 18;
	else if ((ch1 == 'u') || (ch1 =='U')) arrayPos = 19;
	else if ((ch1 == 'i') || (ch1 =='I')) arrayPos = 20;
	else if ((ch1 == 'o') || (ch1 =='O')) arrayPos = 21;
	else if ((ch1 == 'p') || (ch1 =='P')) arrayPos = 22;
	else if ((ch1 == '[') || (ch1 =='[')) arrayPos = 23;
	else if ((ch1 == ']') || (ch1 ==']')) arrayPos = 24;
	else if ((ch1 == 'a') || (ch1 =='A')) arrayPos = 25;
	else if ((ch1 == 's') || (ch1 =='S')) arrayPos = 26;
	else if ((ch1 == 'd') || (ch1 =='D')) arrayPos = 27;
	else if ((ch1 == 'f') || (ch1 =='F')) arrayPos = 28;
	else if ((ch1 == 'g') || (ch1 =='G')) arrayPos = 29;
	else if ((ch1 == 'h') || (ch1 =='H')) arrayPos = 30;
	else if ((ch1 == 'j') || (ch1 =='J')) arrayPos = 31;
	else if ((ch1 == 'k') || (ch1 =='K')) arrayPos = 32;
	else if ((ch1 == 'l') || (ch1 =='L')) arrayPos = 33;
	else if ((ch1 == ';') || (ch1 ==';')) arrayPos = 34;
	else if ((ch1 == 'z') || (ch1 =='Z')) arrayPos = 35;
	else if ((ch1 == 'x') || (ch1 =='X')) arrayPos = 36;
	else if ((ch1 == 'c') || (ch1 =='C')) arrayPos = 37;
	else if ((ch1 == 'v') || (ch1 =='V')) arrayPos = 38;
	else if ((ch1 == 'b') || (ch1 =='B')) arrayPos = 39;
	else if ((ch1 == 'n') || (ch1 =='N')) arrayPos = 40;
	else if ((ch1 == 'm') || (ch1 =='M')) arrayPos = 1;
	else if ((ch1 == ',') || (ch1 =='<')) arrayPos = 2;
	else if ((ch1 == '.') || (ch1 =='>')) arrayPos = 3;
	else if ((ch1 == '/') || (ch1 =='?')) arrayPos = 4;
	else if  (ch1 == ' ') arrayPos = 20;
	else arrayPos = 0;
	
	return arrayPos;
}

//  assign a sound to keys based on their frequency in the English language (ETAOIN SHRDLU)
int calcWeightedETA(char ch1)
{
	int arrayPos;

	if		 ((ch1 == '0') || (ch1 ==')')) arrayPos = 0;
	else if ((ch1 == '1') || (ch1 =='!')) arrayPos = 1;
	else if ((ch1 == '2') || (ch1 =='@')) arrayPos = 2;
	else if ((ch1 == '3') || (ch1 =='#')) arrayPos = 3;
	else if ((ch1 == '4') || (ch1 =='$')) arrayPos = 4;
	else if ((ch1 == '5') || (ch1 =='%')) arrayPos = 5;
	else if ((ch1 == '6') || (ch1 =='^')) arrayPos = 6;
	else if ((ch1 == '7') || (ch1 =='&')) arrayPos = 7;
	else if ((ch1 == '8') || (ch1 =='*')) arrayPos = 8;
	else if ((ch1 == '9') || (ch1 =='(')) arrayPos = 9;
	else if ((ch1 == 'e') || (ch1 =='E')) arrayPos = 10;
	else if ((ch1 == 't') || (ch1 =='T')) arrayPos = 11;
	else if ((ch1 == 'a') || (ch1 =='A')) arrayPos = 12;
	else if ((ch1 == 'o') || (ch1 =='O')) arrayPos = 13;
	else if ((ch1 == 'i') || (ch1 =='I')) arrayPos = 14;
	else if ((ch1 == 'n') || (ch1 =='N')) arrayPos = 15;
	else if ((ch1 == 's') || (ch1 =='S')) arrayPos = 16;
	else if ((ch1 == 'h') || (ch1 =='H')) arrayPos = 18;
	else if ((ch1 == 'r') || (ch1 =='R')) arrayPos = 19;
	else if ((ch1 == 'd') || (ch1 =='D')) arrayPos = 20;
	else if ((ch1 == 'l') || (ch1 =='L')) arrayPos = 21;
	else if ((ch1 == 'u') || (ch1 =='U')) arrayPos = 22;
	else if ((ch1 == 'c') || (ch1 =='C')) arrayPos = 23;
	else if ((ch1 == 'm') || (ch1 =='M')) arrayPos = 24;
	else if ((ch1 == 'f') || (ch1 =='F')) arrayPos = 25;
	else if ((ch1 == 'w') || (ch1 =='W')) arrayPos = 26;
	else if ((ch1 == 'y') || (ch1 =='Y')) arrayPos = 27;
	else if ((ch1 == 'p') || (ch1 =='P')) arrayPos = 28;
	else if ((ch1 == 'v') || (ch1 =='V')) arrayPos = 29;
	else if ((ch1 == 'b') || (ch1 =='B')) arrayPos = 30;
	else if ((ch1 == 'g') || (ch1 =='G')) arrayPos = 31;
	else if ((ch1 == 'k') || (ch1 =='K')) arrayPos = 32;
	else if ((ch1 == 'q') || (ch1 =='Q')) arrayPos = 33;
	else if ((ch1 == 'j') || (ch1 =='J')) arrayPos = 34;
	else if ((ch1 == 'x') || (ch1 =='X')) arrayPos = 35;
	else if ((ch1 == 'z') || (ch1 =='Z')) arrayPos = 36;
	else if ((ch1 == ':') || (ch1 ==';')) arrayPos = 37;
	else if ((ch1 == ',') || (ch1 =='<')) arrayPos = 38;
	else if ((ch1 == '.') || (ch1 =='>')) arrayPos = 39;
	else if ((ch1 == '/') || (ch1 =='?')) arrayPos = 40;
	else if ((ch1 == '[') || (ch1 =='{')) arrayPos = 1;
	else if ((ch1 == ']') || (ch1 =='}')) arrayPos = 2;
	else if ((ch1 == '-') || (ch1 =='_')) arrayPos = 3;
	else if ((ch1 == '=') || (ch1 =='+')) arrayPos = 4;
	else if  (ch1 == ' ') arrayPos = 20;
	else arrayPos = 0;

	return arrayPos;
}
