[UVA][樂理] 449 - Majoring in Scales
Majoring in Scales
Majoring in Scales |
Background
In western music, the twelve notes used in musical notation are arranged in the following order:
C/B# C#/Db D D#/Eb E/Fb F/E# F#/Gb G G#/Ab A A#/Bb B/Cb
Note that a slash in the above list indicates alternate notations for the same note.
Any two notes that are adjacent to each other in the above list are known as a semitone. Any two notes that have one note separating them in the list above are known as a tone. A major scale is made up of 8 notes. It starts on one of the above notes and moves in the progression tone-tone-semitone-tone-tone-tone-semitone. For example, the major scale starting on Db is made up of the following notes:
Db Eb F Gb Ab Bb C Db
The following rules also apply to major scales:
- The scale will contain each letter from A to G once and only once, with the exception of the first letter of the scale (which will be repeated as the last note of the scale).
- The scale may not contain a combination of both flat (b) notes and sharp (#) notes.
For the purposes of this problem, we are only concerned with the following major scales: C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, and B.
An interval is a distance between two notes on a scale. It can be either ascending or descending. The names of the intervals are derived by the distance between the two notes. Two notes adjacent to each other in a major scale are known as a major second. Two notes in a major scale with three notes separating them are known as a major fifth. An octave is a special interval which spans from one occurrence of a note to the next occurrence of it in the major scale.
Input and Output
Your program is to read an input file that contains major scale intervals to calculate, and is to output the results to an output file. The data in the input file will consist of pairs of lines. The first line of each pair will contain the major scale to be used, and the second line of each pair will contain one or more intervals to be calculated. Each interval to be calculated will be separated by a semicolon. The interval to calculate will be specified with a starting note, a direction (UP or DOWN), and the interval itself (SECOND, THIRD, FOURTH, FIFTH, SIXTH, SEVENTH, or OCTAVE). When specifying notes, the lowercase letter "b" will be used to represent a flat, and the symbol "#" will be used to represent a sharp. No spaces will immediately precede or follow a semicolon, but one space will separate the note from the direction as well as the direction from the interval.
The output file should be formatted as shown below, with a blank line after every test case. Each pair of lines in the input file will produce a line stating the key, followed by the results of the calculated intervals, one interval per line. If the starting note of the interval is not a part of the major scale being used, the program should output "invalid note for this key".
The following example shows more clearly the format of the input and output files:
Sample Input
C F UP SECOND;G DOWN THIRD E F# DOWN FOURTH;Bb DOWN SEVENTH;B UP OCTAVE
Sample Output
Key of C F: UP SECOND > G G: DOWN THIRD > E Key of E F#: DOWN FOURTH > C# Bb: invalid note for this key B: UP OCTAVE > B
題目有點麻煩,定義一個調中不會同時存在升記號與降記號,並且每個 A-G 只會出現一次。
而定義某某調時,不會有升記號的調。
而詢問在某個調中的七個音中,從某個音往下數或者往上數的音為何。
可能打表比較好一點,再建某個調有哪七個音十分困難!
其餘就一般處理。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <map>
using namespace std;
map<string, int> NOTE;
string nn[12][2] = {
{"C", "B#"}, {"C#", "Db"}, {"D", ""}, {"D#", "Eb"}, {"E", "Fb"},
{"F", "E#"}, {"F#", "Gb"}, {"G", ""}, {"G#", "Ab"}, {"A", ""},
{"A#", "Bb"}, {"B", "Cb"}};
string majorScale[12][2][8];
void build() {
int i, j, k;
int d[] = {2,2,1,2,2,2,1};
for(i = 0; i < 12; i++) {
for(k = 0; k < 2; k++) {
if(nn[i][k] == "" || nn[i][k][1] == '#') continue;
int pos = i;
for(j = 0; j < 7; j++) {
majorScale[i][k][j] = nn[pos][k];
if(j) {
if(majorScale[i][k][j-1][0] == 'G' && nn[pos][k][0] != 'A')
majorScale[i][k][j] = nn[pos][!k];
if(majorScale[i][k][j-1][0] != 'G' && nn[pos][k][0] != majorScale[i][k][j-1][0]+1)
majorScale[i][k][j] = nn[pos][!k];
}
//cout << majorScale[i][k][j] << "-";
pos += d[j];
pos %= 12;
}
//cout << endl;
}
}
}
int trans(string n) {
if(n == "SECOND")
return 2;
if(n == "THIRD")
return 3;
if(n == "FOURTH")
return 4;
if(n == "FIFTH")
return 5;
if(n == "SIXTH")
return 6;
if(n == "SEVENTH")
return 7;
if(n == "OCTAVE")
return 8;
return 0;
}
int main() {
build();
int i, j, k;
char s[10005];
string major;
while(cin >> major) {
while(getchar() != '\n');
gets(s);
int len = strlen(s);
for(i = 0; i < len; i++)
if(s[i] == ';') s[i] = ' ';
stringstream sin(s);
string note, dir, gap;
printf("Key of %s\n", major.c_str());
int mposx, mposy;
for(i = 0; i < 12; i++)
for(j = 0; j < 2; j++)
if(nn[i][j] == major)
mposx = i, mposy = j;
while(sin >> note >> dir >> gap) {
printf("%s: ", note.c_str());
int g = trans(gap)-1, pos = -1;
if(dir == "DOWN") g = -g;
for(i = 0; i < 7; i++) {
if(majorScale[mposx][mposy][i] == note)
pos = i;
}
if(pos == -1) {
puts("invalid note for this key");
continue;
}
printf("%s %s > ", dir.c_str(), gap.c_str());
pos = (pos+g+7)%7;
printf("%s\n", majorScale[mposx][mposy][pos].c_str());
}
puts("");
}
return 0;
}