1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/audio/ags_diatonic_scale.h>
21 
22 #include <string.h>
23 
24 /**
25  * SECTION:ags_diatonic_scale
26  * @short_description: diatonic scale util
27  * @title: AgsDiatonicScale
28  * @section_id:
29  * @include: ags/audio/ags_diatonic_scale.h
30  *
31  * Utility functions to handle diatonic scale.
32  */
33 
34 /**
35  * ags_diatonic_scale_note_to_midi_key:
36  * @note: the note name
37  * @key: return location of MIDI key
38  *
39  * Convert @note to MIDI key and store in @key.
40  *
41  * Returns: the number of chars read
42  *
43  * Since: 3.0.0
44  */
45 guint
ags_diatonic_scale_note_to_midi_key(gchar * note,glong * key)46 ags_diatonic_scale_note_to_midi_key(gchar *note,
47 				    glong *key)
48 {
49   guint char_count;
50   gint position;
51   glong x_key;
52   int retval;
53   gboolean success;
54 
55   if(note == NULL ||
56      note[0] == '\0' ||
57      key == NULL){
58     return(0);
59   }
60 
61   x_key = 49;
62 
63   char_count = 0;
64 
65   success = FALSE;
66 
67   switch(note[0]){
68   case 'a':
69   {
70     success = TRUE;
71 
72     x_key = 49;
73   }
74   break;
75   case 'h':
76   case 'b':
77   {
78     success = TRUE;
79 
80     x_key = 51;
81   }
82   break;
83   case 'c':
84   {
85     success = TRUE;
86 
87     x_key = 52;
88   }
89   break;
90   case 'd':
91   {
92     success = TRUE;
93 
94     x_key = 54;
95   }
96   break;
97   case 'e':
98   {
99     success = TRUE;
100 
101     x_key = 56;
102   }
103   break;
104   case 'f':
105   {
106     success = TRUE;
107 
108     x_key = 57;
109   }
110   break;
111   case 'g':
112   {
113     success = TRUE;
114 
115     x_key = 59;
116   }
117   break;
118   }
119 
120   if(success){
121     char_count = 1;
122   }
123 
124   if(!success ||
125      note[1] == '\0'){
126     goto ags_diatonic_scale_note_to_midi_key_COMPLETED;
127   }
128 
129   success = FALSE;
130 
131   switch(note[1]){
132   case '#':
133   {
134     success = TRUE;
135 
136     x_key += 1;
137   }
138   break;
139   case 'b':
140   {
141     success = TRUE;
142 
143     x_key -= 1;
144   }
145   break;
146   }
147 
148   if(success){
149     char_count = 2;
150   }
151 
152   if(!success ||
153      note[2] == '\0'){
154     goto ags_diatonic_scale_note_to_midi_key_COMPLETED;
155   }
156 
157   success = FALSE;
158 
159   position = -1;
160 
161   retval = sscanf(note + 2, "%d", &position);
162 
163   if(retval > 0){
164     if(position > 49){
165       x_key += ((position - 1) * 12) - 48;
166     }else if(position < 49){
167       x_key += ((position - 1) * 12) - 48;
168     }
169 
170     char_count += retval;
171   }
172 
173 ags_diatonic_scale_note_to_midi_key_COMPLETED:
174   key[0] = x_key;
175 
176   return(char_count);
177 }
178 
179 /**
180  * ags_diatonic_scale_midi_key_to_note:
181  * @key: MIDI key
182  * @note: return location of note name
183  *
184  * Convert MIDI @key to note name and store in @note.
185  *
186  * Returns: the number of chars written
187  *
188  * Since: 3.0.0
189  */
190 guint
ags_diatonic_scale_midi_key_to_note(glong key,gchar ** note)191 ags_diatonic_scale_midi_key_to_note(glong key,
192 				    gchar **note)
193 {
194   gchar *x_note;
195   gchar *str;
196 
197   guint char_count;
198   gint sharp_flats;
199   gint position;
200 
201   static const gchar *sharp = "#";
202 
203   if(key > 128 ||
204      note == NULL){
205     return(0);
206   }
207 
208   x_note = NULL;
209 
210   sharp_flats = -1;
211   position = -1;
212 
213   switch(key % 12){
214   case 0:
215   {
216     x_note = "a";
217   }
218   break;
219   case 1:
220   {
221     x_note = "a";
222     sharp_flats = 1;
223   }
224   break;
225   case 2:
226   {
227     x_note = "h";
228   }
229   break;
230   case 3:
231   {
232     x_note = "c";
233   }
234   break;
235   case 4:
236   {
237     x_note = "c";
238     sharp_flats = 1;
239   }
240   break;
241   case 5:
242   {
243     x_note = "d";
244   }
245   break;
246   case 6:
247   {
248     x_note = "d";
249     sharp_flats = 1;
250   }
251   break;
252   case 7:
253   {
254     x_note = "e";
255   }
256   break;
257   case 8:
258   {
259     x_note = "f";
260   }
261   break;
262   case 9:
263   {
264     x_note = "f";
265     sharp_flats = 1;
266   }
267   break;
268   case 10:
269   {
270     x_note = "g";
271   }
272   case 11:
273   {
274     x_note = "g";
275     sharp_flats = 1;
276   }
277   break;
278   break;
279   }
280 
281   position = floor((gdouble) key / 12.0) + 1;
282 
283   if(sharp_flats != -1 &&
284      position != -1){
285     str = g_strdup_printf("%s%s%d",
286 			  x_note,
287 			  sharp,
288 			  position);
289   }else if(position != -1){
290     str = g_strdup_printf("%s%d",
291 			  x_note,
292 			  position);
293   }else{
294     str = g_strdup_printf("%s",
295 			  x_note);
296   }
297 
298   char_count = strlen(str);
299   note[0] = str;
300 
301   return(char_count);
302 }
303