1 
2 /*
3  *  Diverse Bristol midi routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 3 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 /*
23  * This will take a character filename and a float mapping, attempt to find the
24  * specified file with a few different names/locations and then parse the
25  * contents into the float array. The end result is a set of frequency tables
26  * that can be converted separately into the midi frequency map.
27  *
28  * Bounds checking is done to limit the float map to 128 entries.
29  *
30  * We need to look for the full path name, then look for the filename in
31  * our profiles directory, then look for the <filename>.scl in the same
32  * profiles directory.
33  *
34  * The midihandlers.c code will parse emulation mappings and uses midiFileMgt.c
35  * code here in the library.
36 
37 ! meanquar.scl
38 !
39 1/4-comma meantone scale. Pietro Aaron's temperament (1523)
40  12
41 !
42  76.04900
43  193.15686
44  310.26471
45  5/4
46  503.42157
47  579.47057
48  696.57843
49  25/16
50  889.73529
51  1006.84314
52  1082.89214
53  2/1
54 
55  */
56 
57 #include <string.h>
58 #include <stdio.h>
59 #include <ctype.h>
60 
61 #include "bristolmidi.h"
62 
63 #define BUFSIZE 256
64 
65 static float
getScalaFreq(char * line)66 getScalaFreq(char *line)
67 {
68 	float freq;
69 	char *denominator;
70 
71 	/* See if we have a fraction */
72 	if ((denominator = index(line, '/')) != NULL)
73 	{
74 		freq = (atoi(line));
75 		return(freq / atoi(++denominator));
76 	}
77 
78 	/* See if we have a decimal and treat it then as cents */
79 	if (index(line, '.') != NULL)
80 		return(1.0 + atof(line) / 1200);
81 
82 	/* Assume we have a raw number */
83 	return(atoi(line));
84 }
85 
86 static char *
spanWhiteSpace(char * line)87 spanWhiteSpace(char *line)
88 {
89 	int i = 0;
90 
91 	while (isspace(line[i]))
92 		i++;
93 
94 	return(&line[i]);
95 }
96 
97 static int
scalaParse(FILE * fd,float * freq)98 scalaParse(FILE *fd, float *freq)
99 {
100 	char line[BUFSIZE];
101 	char *scan;
102 	int lineid = 0; /* To decide what to parse */
103 	int freqindex = 0, count = 0;
104 
105     while ((fgets(line, BUFSIZE, fd)) != 0)
106 	{
107 		if (line[0] == '!')
108 			continue;
109 
110 		switch (lineid++)
111 		{
112 			case 0:
113 				printf("Scale info: %s", line);
114 				lineid = 1;
115 				break;
116 			case 1:
117 				scan = spanWhiteSpace(line);
118 				if ((count = atoi(scan)) < 0)
119 					return(-1);
120 				if (count > 128)
121 				{
122 					printf("Scala: cannot converge %i notes\n", count);
123 					return(-2);
124 				}
125 				lineid = 2;
126 				break;
127 			default:
128 				/* The rest should be frequencies */
129 				scan = spanWhiteSpace(line);
130 				if ((freq[freqindex] = getScalaFreq(scan)) <= 0)
131 					continue;
132 				freqindex++;
133 				break;
134 		}
135 	}
136 
137 	return(freqindex);
138 }
139 
140 int
bristolParseScala(char * file,float * freq)141 bristolParseScala(char *file, float *freq)
142 {
143 	FILE *fd;
144 	char *cache;
145 	int ncount;
146 
147 	if ((cache = getBristolCache(file)) == NULL)
148 	{
149 		printf("Could not resolve cache\n");
150 		return(-10);
151 	}
152 
153 	if (file[0] == '/')
154 	{
155 		if ((fd = fopen(file, "r")) == (FILE *) NULL)
156 		{
157 			printf("Could not find scala file\n");
158 			return(-1);
159 		}
160 	} else {
161 		char filename[1024];
162 
163 		if (strlen(file) > 200)
164 		{
165 			printf("Will not open stupidly named file: %s\n", file);
166 			return(-2);
167 		}
168 
169 		/*
170 		 * First look for the complete filename:
171 		 */
172 		sprintf(filename, "%s/memory/profiles/%s", cache, file);
173 
174 		if ((fd = fopen(filename, "r")) == (FILE *) NULL)
175 		{
176 			sprintf(filename, "%s/memory/profiles/%s.scl", cache, file);
177 
178 			if ((fd = fopen(filename, "r")) == (FILE *) NULL)
179 			{
180 				printf("Could not open named scala file %s\n", filename);
181 				return(-3);
182 			}
183 		}
184 	}
185 
186 	if ((ncount = scalaParse(fd, freq)) < 0)
187 	{
188 		printf("Could not parse named scala file %s\n", file);
189 		fclose(fd);
190 		return(-4);
191 	}
192 
193 	fclose(fd);
194 
195 	printf("Converged %i notes from scala file %s\n", ncount, file);
196 
197 	return(ncount);
198 }
199 
200