/* tuning.c -- a scale definition program */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 16-Jun-86 | Created changelog * 12-Aug-86 | Fixed an off-by-12 indexing bug, use userio.h to open file *****************************************************************************/ #include "cext.h" #include "stdio.h" #include "pitch.h" #include "userio.h" #include "cmdline.h" #define MINPITCH -12 #define MAXPITCH 115 /**************************************************************************** * Routines local to this module ****************************************************************************/ private char getcommand(); private void getoctave(); private void getonepitch(); private void getrange(); private void readpitch(); private void writepitch(); private void ratio_to_cents(); /**************************************************************************** * Data for command line parsing ****************************************************************************/ #define nswitches 0 #define switches NULL #define noptions 0 #define options NULL /**************************************************************************** * getcommand * Outputs: * returns char: character typed by user * Effect: * prompts for command and gets it ****************************************************************************/ private char getcommand() { char result; printf("\nr - enter a range of values\n"); printf("o - enter one octave (that will be generalized)\n"); printf("p - enter one pitch (you choose)\n"); printf("q - quit\n\n"); printf("Command >>"); while ((result = getchar()) == '\n') ; readln(stdin); /* flush the newline and any other chars */ return result; } /**************************************************************************** * getoctave * Outputs: * pitch_table pit_tab[]: array of pitch data * Effect: * prompts user for one octave of data, then transposes to get others ****************************************************************************/ private void getoctave(pit_tab) pitch_table pit_tab[]; { float ratio[12], num, denom; int pitch[12], bend[12], base, key, i, j, count, choice; printf("\n\nYou will input the information for one octave and that\n"); printf(" will be generalized for all octaves.\n"); printf("\nWould you like to enter the information as\n"); printf(" (1) frequency ratios of notes to a tonic\n"); printf("or (2) semitones (integer) + pitchbend (in cents)\n\n"); printf(" >>"); scanf("%d\n", &choice); if (choice == 1) { printf("Please enter ratio x/y as x y where x and y are floating point numbers.\n\n"); printf("Note 0 (tonic) ratio is 1/1 (1 1)\n"); ratio[0] = 1.0; for (i = 1; i < 12; i++) { printf("note %d ratio >>", i); scanf("%f %f\n", &num,&denom); ratio[i] = num/denom; printf("ratio[%d] = %f\n",i,ratio[i]); } ratio_to_cents(ratio, bend, pitch); } else { printf("\n\nFor the given note number, enter the desired pitch\n"); printf("and the amount of pitchbend in cents based on given tonic\n"); printf("\n1 unit of pitch = 1 semitone -- the tonic (note 0) has pitch 0 and bend 0.\n"); printf(" Bend range = -100 .. 100 cents, 0 for no pitch bend\n"); printf(" (100 cents = 1 semitone)\n"); printf("\n\n"); bend[0] = pitch[0] = 0; for (i = 1; i <12; i++) { printf("Octave note %d\n", i); printf(" pitch >>"); scanf("%d\n", &pitch[i]); printf(" bend >>"); scanf("%d\n", &bend[i]); } } printf("\nWhat note would you like your octave to start on?\n\n"); printf("C C# D D# E F F# G G# A A# B\n"); printf("0 1 2 3 4 5 6 7 8 9 10 11\n"); printf(" >>"); scanf("%d\n", &key); for (i = 0; i < 12; i++) { base = i + key; if (base > 11) { base -= 12; key -=12; } /* 0 <= base <= 11 */ /* remember that pitches range from -12 to 115: */ for (count = -1, j = base+MINPITCH; j <= MAXPITCH; j+=12) { pit_tab[j-MINPITCH].ppitch = key + pitch[i] + count*12; pit_tab[j-MINPITCH].pbend = bend[i]; count++; } } } /**************************************************************************** * getonepitch * Inputs: * pitch_table pit_tab[]: table to be modified * Outputs: * pitch_table pit_tab[]: table with modifications is returned * Effect: * prompts user for a note to change, gets data, modifies table ****************************************************************************/ private void getonepitch(pit_tab) pitch_table pit_tab[128]; { int pitch, bend, index, finished = 0; while (!finished) { printf("Note range is -12..115. Which note would you like to enter ?"); printf("\n (Q to quit)\n"); printf("Note >>"); if (scanf("%d\n", &index) == 0) { finished = true; readln(stdin); } else { printf("\n\nFor the given pitch number, enter pitch paramaters\n"); printf(" Bend range = -100 .. 100 cents, 0 for no pitch bend\n"); printf(" (100 cents = 1 semitone)\n"); printf(" Pitch range = -12 .. 115, 48 is middle C\n\n\n"); printf("Adagio note %d\n", index); printf(" pitch >>"); scanf("%d\n", &pitch); printf(" bend >>"); scanf("%d\n", &bend); pit_tab[index - MINPITCH].pbend = bend; pit_tab[index - MINPITCH].ppitch = pitch; } } } /**************************************************************************** * getrange * Inputs: * pitch_table pit_tab[128]: a table of pitch info * Outputs: * pitch_table pit_tab[128]: modified table of pitch info * Effect: * asks user for a range, then prompts for pitch data within that * range ****************************************************************************/ private void getrange(pit_tab) pitch_table pit_tab[128]; { int i,low,high,bend,pitch; printf("Adagio note range is 1..128\nWhat range of notes would you like to enter ?\n"); printf("From >>"); scanf("%d\n", &low); printf(" To >>"); scanf("%d\n", &high); printf("\n\nFor the given Adagio note number, enter the desired pitch\n"); printf("and the amount of pitchbend in cents\n"); printf(" Bend range = -100 .. 100, '0' for no pitch bend\n"); printf(" (100 cents = 1 semitone)\n"); printf(" Pitch range = 1 .. 128, 48 is middle C\n"); printf("\n\n"); for (i = low; i <= high; i++) { printf("Adagio Note %d\n", i); printf(" pitch >>"); scanf("%d\n", &pitch); printf(" bend >>"); scanf("%d\n", &bend); pit_tab[i - MINPITCH].pbend = bend; pit_tab[i - MINPITCH].ppitch = pitch; } } /**************************************************************************** * main * Inputs: * int argc: number of command line arguments * char *argv[]: vector of command line arguments * Effect: main program ****************************************************************************/ void main(argc, argv) int argc; char *argv[]; { int i, done = 0; FILE *fp; char *s; /* the filename argument, if any */ char filename[100]; pitch_table pit_tab[128]; cl_init(switches, nswitches, options, noptions, argv, argc); /* get output file: */ if ((s = cl_arg(1)) != NULL) strcpy(filename, s); else strcpy(filename, ""); fp = fileopen(filename, "tun", "w", "Name of tuning file"); for (i = MINPITCH; i <= MAXPITCH; i++) { /* initialize pit_tab */ pit_tab[i - MINPITCH].pbend = 0; pit_tab[i - MINPITCH].ppitch = i; } printf("You will now create a pitch file.\n\n"); while (!done) { switch (getcommand()) { case 'r': getrange(pit_tab); break; case 'p': getonepitch(pit_tab); break; case 'o': getoctave(pit_tab); break; case 'q': done = 1; break; default: continue; } } writepitch(fp, pit_tab); } /**************************************************************************** * readpitch * Inputs: * FILE *fp: file from which to read * Outputs: * pitch_table pit_tab[128]: this table is initialized by reading fp ****************************************************************************/ private void readpitch(fp, pit_tab) FILE *fp; pitch_table pit_tab[128]; { int i, j, pitch, bend; for ( j = MINPITCH; j <= MAXPITCH; j++) { fscanf(fp,"%d %d %d\n", &i, &pitch, &bend); pit_tab[i].ppitch = pitch; pit_tab[i].pbend = bend; } } /**************************************************************************** * writepitch * Inputs: * FILE *fp: the file to write * pitch_table pit_tab[128]: the table to write * Effect: * writes pit_tab to file *fp ****************************************************************************/ private void writepitch(fp, pit_tab) FILE *fp; pitch_table pit_tab[128]; { int i; for ( i = MINPITCH; i <= MAXPITCH; i++) { fprintf(fp,"%d %d %d\n", i, pit_tab[i-MINPITCH].ppitch, pit_tab[i-MINPITCH].pbend); } } /**************************************************************************** * ratio_to_cents * Inputs: * float ratio[]: an octave of rations to convert * Outputs: * int bend[]: an octave of pitch bends * int pitch[]: an octave of pitches * Effect: * converts 12 ratios to pitch + bend pairs ****************************************************************************/ private void ratio_to_cents(ratio, bend, pitch) float ratio[]; int bend[], pitch[]; { int i; float cents; for (i = 0; i < 12; i++) { cents = 1200 * log(ratio[i])/log(2); pitch[i] = (int)(cents/100); bend[i] = (int)(cents - (pitch[i] * 100) + 0.5); } }