1 /* scherzo - Music notation training
3 * pitch.c - Common structures and functions for pitches, etc.
5 * Copyright © 2013 Carl Worth
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.
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.
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/ .
27 pitch_string (pitch_t pitch)
29 static char double_flat[] = "X𝄫";
30 static char flat[] = "X♭";
31 static char natural[] = "X";
32 static char sharp[] = "X♯";
33 static char double_sharp[] = "X𝄪";
36 switch (PITCH_ACCIDENTAL (pitch)) {
37 case PITCH_ACCIDENTAL_DOUBLE_FLAT:
40 case PITCH_ACCIDENTAL_FLAT:
43 case PITCH_ACCIDENTAL_NATURAL:
46 case PITCH_ACCIDENTAL_SHARP:
49 case PITCH_ACCIDENTAL_DOUBLE_SHARP:
54 switch (PITCH_NAME (pitch)) {
82 pitch_raise_by_octaves (pitch_t pitch, int octaves)
84 int new_octave = PITCH_OCTAVE (pitch) + octaves;
89 return PITCH (PITCH_NAME (pitch), PITCH_ACCIDENTAL (pitch), new_octave);
93 pitch_lower_by_octaves (pitch_t pitch, int octaves)
95 int new_octave = PITCH_OCTAVE (pitch) - octaves;
100 return PITCH (PITCH_NAME (pitch), PITCH_ACCIDENTAL (pitch), new_octave);
103 /* Number of half steps from 'root' up to 'pitch' (that is, counting
104 * the steps up a chromatic scale), within the same octave. */
106 pitch_from_root_in_half_steps (pitch_t pitch, pitch_t root)
108 int root_midi = pitch_to_midi (root);
109 int pitch_midi = pitch_to_midi (pitch);
111 while (pitch_midi < root_midi)
114 return (pitch_midi - root_midi) % 12;
118 pitch_spell_as_degree (pitch_t pitch, pitch_t root, int degree)
120 pitch_name_t name = PITCH_NAME (pitch);
121 pitch_accidental_t accidental = PITCH_ACCIDENTAL (pitch);
122 int octave = PITCH_OCTAVE (pitch);
123 int degree_zero_based = (degree - 1) % 7;
126 int note_degree_zero_based = name - PITCH_NAME (root);
127 if (note_degree_zero_based < 0)
128 note_degree_zero_based += 7;
130 if (note_degree_zero_based == degree_zero_based)
133 degree_delta = note_degree_zero_based - degree_zero_based;
134 if (degree_delta > 3)
135 degree_delta = - (7 - degree_delta);
136 if (degree_delta < -3)
137 degree_delta = - (-7 - degree_delta);
139 /* Cannot re-spell pitch more than one degree away. Return
141 if (abs (degree_delta) != 1)
144 if (degree_delta == -1) {
145 if (name == PITCH_NAME_B) {
166 if (degree_delta == +1) {
167 if (name == PITCH_NAME_C) {
187 /* Also cannot use accidentals to respell more than two half steps
188 * either direction. Return original pitch. */
189 if (accidental < 0 || accidental > PITCH_ACCIDENTAL_DOUBLE_SHARP)
192 return PITCH (name, accidental, octave);
195 /* Return a MIDI note value corresponding to 'pitch' */
197 pitch_to_midi (pitch_t pitch)
199 int octave = PITCH_OCTAVE (pitch);
200 unsigned char midi_note = 12 * (octave + 1);
202 switch (PITCH_NAME (pitch)) {
225 switch (PITCH_ACCIDENTAL (pitch)) {
226 case PITCH_ACCIDENTAL_DOUBLE_FLAT:
229 case PITCH_ACCIDENTAL_FLAT:
232 case PITCH_ACCIDENTAL_NATURAL:
234 case PITCH_ACCIDENTAL_SHARP:
237 case PITCH_ACCIDENTAL_DOUBLE_SHARP:
245 /* Return the pitch_t value corresponding to the given MIDI note value. */
247 pitch_from_midi (unsigned char midi_note)
249 int octave = octave = midi_note / 12 - 1;
251 switch (midi_note % 12)
255 return PITCH_LITERAL (C, NATURAL, octave);
258 return PITCH_LITERAL (D, FLAT, octave);
261 return PITCH_LITERAL (D, NATURAL, octave);
264 return PITCH_LITERAL (E, FLAT, octave);
267 return PITCH_LITERAL (E, NATURAL, octave);
270 return PITCH_LITERAL (F, NATURAL, octave);
273 return PITCH_LITERAL (G, FLAT, octave);
276 return PITCH_LITERAL (G, NATURAL, octave);
279 return PITCH_LITERAL (A, FLAT, octave);
282 return PITCH_LITERAL (A, NATURAL, octave);
285 return PITCH_LITERAL (B, FLAT, octave);
288 return PITCH_LITERAL (B, NATURAL, octave);
294 pitch_enharmonic_to (pitch_t a, pitch_t b)
296 return pitch_to_midi (a) == pitch_to_midi (b);