/* Scales.c
   Copyright (c) 1990,1991,1992 by Thomas E. Janzen
   All Rights Reserved

   THIS SOFTWARE IS FURNISHED FREE OF CHARGE FOR STUDY AND USE AND MAY
   BE COPIED ONLY FOR PERSONAL USE OR COMPLETELY AS OFFERED WITH NO
   CHANGES FOR FREE DISTRIBUTION.  NO TITLE TO AND OWNERSHIP OF THE
   SOFTWARE IS HEREBY TRANSFERRED.  THOMAS E. JANZEN ASSUMES NO 
   RESPONSBILITY FOR THE USE OR RELIABILITY OF THIS SOFTWARE.
   
   Thomas E. Janzen
   58A School St. Apt. 2-L
   Hudson, MA 01749
   (508)562-1295
*/
/*
**  FACILITY:
**
**	AlgoRhythms music improviser on Commodore (TM) Amiga (TM)
**	compiled with SAS/C V5.10b
**
**  ABSTRACT:
**
**	Scales.c creates and manages musical scales.
**
**  AUTHORS: Thomas E. Janzen
**
**  CREATION DATE:	26-MAR-1990
**
**  MODIFICATION HISTORY:
**    DATE	NAME	DESCRIPTION
**    7 Dec 90 T. Janzen Procedurized filling octave-repeating scales
**  4 Jan 92 TEJ  last changes for 2.0
**--
*/
#include <stdlib.h>  /* needed for ANSI abs () */
#include <math.h>

#define CHROMATIC       1
#define SHORTPENTATONIC 2
#define HIRA            3
#define KUMOI           4
#define KOKIN           5
#define WHOLETONE       6
#define DIATONIC        7
#define HARMONIC        8
#define HUNGARIAN       9
#define DIMINISHED      10
#define LONGPENTATONIC  11
#define MODE3           12 /* Messiaen Art of My Musical Language*/
#define MODE4           13
#define MODE5           14
#define MODE6           15
#define MODE7           16
#define MTSsel          17 /*minr thrd, majr secnd, non-octave repeating*/
#define M3M2            18 /*major third, minor second */
#define QUARTAL         19
#define QUINTAL         20

#define NUMOCTAVES      7
#define BOTTOMOCT       2
#define CHROMNUM        12
#define SHRTPENTANUM    13
#define HIRANUM         12
#define KUMOINUM        12
#define KOKINNUM        11
#define WHOLENUM        6
#define DIANUM          7
#define HARMONNUM       7
#define HUNGARNUM       7
#define DIMINISHNUM     8
#define LONGPENTANUM    5
#define MODE3NUM        9 /*Messiaen  Art of My Musical Language*/
#define MODE4NUM        8
#define MODE5NUM        6
#define MODE6NUM        8
#define MODE7NUM        10
#define MTSNUM          30 /*minr thrd, majr secnd, non-octave repeating*/
#define M3M2NUM         29 /*major third,  minor second */
#define QUARTALNUM      20 /* fourths if starts from low c 12 */
#define QUINTALNUM      14 /* fifths if starts from low c 12 */

static int OctaveRepeatingScale  (  const char OneOctaveScale[], 
                                    int scale[], 
                                    const int ScaleOctaveLen);

extern int InstallScale  (const int Select, int scale[]) 
{
	const char  chromatic[CHROMNUM]  =  /* chromatic */
		         {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 
	            lucy[SHRTPENTANUM]   =  /* Short Pentatonic */
		         {48, 50, 53, 55, 58, 60, 62, 65, 67, 70, 72, 74, 77},
	            hira[HIRANUM]        =  /* hira joshi koto */
		         {57, 59, 60, 64, 65, 69, 71, 72, 76, 77, 81, 83},
               kumoi[KUMOINUM]      =  /* kumoi joshi koto */
		         {57, 58, 62, 64, 65, 69, 70, 74, 76, 77, 81, 83},
               kokin[KOKINNUM]      =  /* kokin joshi koto */
		         {59, 62, 64, 65, 69, 71, 74, 76, 77, 81, 83},   
	            wholetone[WHOLENUM]  =  /* whole tone scale */
               {0, 2, 4, 6, 8, 10},
	            Diatonic[DIANUM]     =  /* diatonic scale */ 
               {0, 2, 4, 5, 7, 9, 11},
	            HarmMinor[HARMONNUM] =  /* harmonic minor scale */
               {0, 2, 3, 5, 7, 8, 11},
	            HungMinor[HUNGARNUM] =  /* Hungarian minor */
               {0, 2, 3, 6, 7, 8, 11},
	            diminished[DIMINISHNUM] = /* diminished scale */
               {0, 2, 3, 5, 6, 8, 9, 11},
	            pentatonic[LONGPENTANUM] = /* long pentatonic scale */
               {0, 2, 4, 7, 9},
	            Mode3[MODE3NUM] =       /* Messiaen mode 3 */
               {0, 2, 3, 4, 6, 7, 8, 10, 11},
	            Mode4[MODE4NUM] =       /* Messiaen mode 4 */
               {0, 1, 2, 5, 6, 7, 8, 11},
	            Mode5[MODE5NUM] =       /* Messiaen mode 5 */
               {0, 1, 5, 6, 7, 11},
	            Mode6[MODE6NUM] =       /* Messiaen mode 6 */
               {0, 2, 4, 5, 6, 8, 10, 11},
	            Mode7[MODE7NUM] =       /* Messiaen mode 7 */
               {0, 1, 2, 3, 5, 6, 7, 8, 9, 11},
	            /* scale alternating minor third, major second; 
               does not repeat octaves */
	            MTS[MTSNUM] = {24, 26, 29, 31, 34, 36, 39, 41, 
					               44, 46, 49, 51, 54, 56, 59, 61, 
					               64, 66, 69, 71, 74, 76, 79, 81, 
					               84, 86, 89, 91, 94, 96},
	            /* scale alternating major third minor second; 
                  does not repeat octaves */
	            M3m2[32] = {24, 28, 29, 33, 34, 38, 39, 43, 
				               44, 48, 49, 53, 54, 58, 59, 63, 
				               64, 68, 69, 73, 74, 78, 79, 83, 
				               84, 88, 89, 93, 94}, /* 29 notes */
               Quartal[QUARTALNUM] = { 12, 17, 23, 28, 33, 38, 43, 48, 53,
                                       58, 63, 68, 73, 78, 83, 88, 93, 98, 
                                       103, 108},
               Quintal[QUINTALNUM] = { 12, 19, 26, 33, 40, 47, 54, 61, 68,
                                       75, 82, 89, 96, 103};
	register int      i;
	
	switch (Select) 
   {
		case CHROMATIC: /*chromatic*/
			return OctaveRepeatingScale (chromatic, scale, CHROMNUM);
			break;
		case SHORTPENTATONIC: /*Pentatonic (Lucy) */
			for (i = 0; i < SHRTPENTANUM; i++)
			{
				scale[i] = (int)lucy[i];
			}
			return SHRTPENTANUM;
			break;
		case HIRA:
			for (i = 0; i < HIRANUM; i++)
			{
				scale[i] = (int)hira[i];
			}
			return HIRANUM;
			break;
		case KUMOI:
			for (i = 0; i < KUMOINUM; i++)
			{
				scale[i] = (int)kumoi[i];
			}
			return KUMOINUM;
			break;
		case KOKIN:
			for (i = 0; i < KOKINNUM; i++)
			{
				scale[i] = (int)kokin[i];
			}
			return KOKINNUM;
			break;
		case WHOLETONE: /*whole tone*/
			return OctaveRepeatingScale (wholetone, scale, WHOLENUM);
			break;
		case DIATONIC: /*diatonic*/
			return OctaveRepeatingScale (Diatonic, scale, DIANUM);
			break;
		case HARMONIC: /* harmonic minor */
			return OctaveRepeatingScale (HarmMinor, scale, HARMONNUM);
			break;
		case HUNGARIAN: /* hungarian minor */
			return OctaveRepeatingScale (HungMinor, scale, HUNGARNUM);
			break;
		case DIMINISHED: /*diminished scale */
			return OctaveRepeatingScale (diminished, scale, DIMINISHNUM);
			break;
		case LONGPENTATONIC: /*long pentatonic scale */
			return OctaveRepeatingScale (pentatonic, scale, LONGPENTANUM);
			break;
		case MODE3: /*Olivier Messiaen mode from Technique
				of my Musical Language*/
			return OctaveRepeatingScale (Mode3, scale, MODE3NUM);
			break;
		case MODE4: /*Olivier Messiaen mode from Technique
				of my Musical Language*/
			return OctaveRepeatingScale (Mode4, scale, MODE4NUM);
			break;
		case MODE5: /*Olivier Messiaen mode from Technique
				of my Musical Language*/
			return OctaveRepeatingScale (Mode5, scale, MODE5NUM);
			break;
		case MODE6: /*Olivier Messiaen mode from Technique
				of my Musical Language*/
			return OctaveRepeatingScale (Mode6, scale, MODE6NUM);
			break;
		case MODE7: /*Olivier Messiaen mode from Technique
				of my Musical Language*/
			return OctaveRepeatingScale (Mode7, scale, MODE7NUM);
			break;
		case MTSsel:
				for (i = 0; i < 30; i++)
				{
					scale[i] = MTS[i];
				}
			return MTSNUM;
			break;
		case M3M2:
				for (i = 0; i < M3M2NUM; i++)
				{
					scale[i] = M3m2[i];
				}
			return M3M2NUM;
			break;
		case QUARTAL:
				for (i = 0; i < QUARTALNUM; i++)
				{
					scale[i] = Quartal[i];
				}
			return QUARTALNUM;
			break;
		case QUINTAL:
				for (i = 0; i < QUINTALNUM; i++)
				{
					scale[i] = Quintal[i];
				}
			return QUINTALNUM;
			break;
		default:
			for (i = 0; i < SHRTPENTANUM; i++)
			{
				scale[i] = lucy[i];
			}
			return SHRTPENTANUM;
			break;
		}
}

extern void TransposeScale (  const int transpose, int *scale, 
                              const int range) 
{
	register int i;
   
	if (abs(transpose)<CHROMNUM) 
   {
		for (i = 0; i < range; i++)
	{
			scale[i] = scale[i] + transpose;
		}
	}
}

static int OctaveRepeatingScale (const char OneOctaveScale[], 
                                int scale[], 
                                const int ScaleOctaveLen)
{
         int oct,
             i;

			for (oct = 0; oct < NUMOCTAVES; oct++)
			{
				for (i = 0; i < ScaleOctaveLen; i++)
				{
					scale[i + (oct * ScaleOctaveLen)]   
               = (int)OneOctaveScale[i] + ((oct + BOTTOMOCT) * CHROMNUM);
				}
			}
			return (NUMOCTAVES * ScaleOctaveLen);
}
