Реализация функциональности типа enum с пользовательскими типами
Я работаю над USB MIDI-контроллером, используя Teensy. Контроллер представляет собой ряд из 7 кнопок, каждая кнопка представляет собой степень прогрессии, а 7 кнопок составляют последовательность аккордов. При нажатии устройство отправляет сообщение о включении / выключении MIDI-ноты для воспроизведения аккорда.
В моем коде у меня есть интервалы, хранящиеся в enum
:
/*
* Intervals
*/
typedef enum {
ROOT = 0,
UNISON = 0,
DIMINISHED_SECOND = 0,
MINOR_SECOND = 1,
AUGMENTED_UNISON = 1,
HALFSTEP = 1,
MAJOR_SECOND = 2,
DIMINISHED_THIRD = 2,
WHOLESTEP = 2,
MINOR_THIRD = 3,
AUGMENTED_SECOND = 3,
MAJOR_THIRD = 4,
DIMINISHED_FOURTH = 4,
PERFECT_FOURTH = 5,
AUGMENTED_THIRD = 5,
DIMINISHED_FIFTH = 6,
AUGMENTED_FOURTH = 6,
PERFECT_FIFTH = 7,
DIMINISHED_SIXTH = 7,
MINOR_SIXTH = 8,
AUGMENTED_FIFTH = 8,
MAJOR_SIXTH = 9,
DIMINISHED_SEVENTH = 9,
MINOR_SEVENTH = 10,
AUGMENTED_SIXTH = 10,
MAJOR_SEVENTH = 11,
DIMINISHED_OCTAVE = 11,
PERFECT_OCTAVE = 12,
AUGMENTED_SEVENTH = 12,
DIMISHED_NINTH = 12,
MINOR_NINTH = 13,
AUGMENTED_OCTAVE = 13,
MAJOR_NINTH = 14,
DIMINISHED_TENTH = 14,
MINOR_TENTH = 15,
AUGMENTED_NINTH = 15,
MAJOR_TENTH = 16,
DIMINISHED_ELEVENTH = 16,
PERFECT_ELEVENTH = 17,
AUGMENTED_TENTH = 17,
DIMINISHED_TWELFTH = 18,
AUGMENTED_ELEVENTH = 18,
PERFECT_TWELFTH = 19,
DIMINISHED_THIRTEENTH = 19,
MINOR_THIRTEENTH = 20,
AUGMENTED_TWELFTH = 20,
MAJOR_THIRTEENTH = 21,
DIMINISHED_FOURTEENTH = 21,
MINOR_FOURTEENTH = 22,
AUGMENTED_THIRTEENTH = 22,
MAJOR_FOURTEENTH = 23,
DIMINISHED_FIFTEENTH = 23,
PERFECT_FIFTEENTH = 24,
AUGMENTED_FOURTEENTH = 24,
AUGMENTED_FIFTEENTH = 25
} INTERVAL;
У меня также есть массив chords
, вот так:
struct Chord {
String name;
int tones[7];
};
Chord chords[6] = {
{ "maj", {
INTERVAL::UNISON,
INTERVAL::MAJOR_THIRD,
INTERVAL::PERFECT_FIFTH }
},
{ "min", {
INTERVAL::UNISON,
INTERVAL::MINOR_THIRD,
INTERVAL::PERFECT_FIFTH }
},
{ "maj7", {
INTERVAL::UNISON,
INTERVAL::MAJOR_THIRD,
INTERVAL::PERFECT_FIFTH,
INTERVAL::MAJOR_SEVENTH }
},
{ "min7", {
INTERVAL::UNISON,
INTERVAL::MINOR_THIRD,
INTERVAL::PERFECT_FIFTH,
INTERVAL::MINOR_SEVENTH }
},
{ "maj9", {
INTERVAL::UNISON,
INTERVAL::MAJOR_THIRD,
INTERVAL::PERFECT_FIFTH,
INTERVAL::MAJOR_SEVENTH,
INTERVAL::MAJOR_NINTH }
},
{ "min9", {
INTERVAL::UNISON,
INTERVAL::MINOR_THIRD,
INTERVAL::PERFECT_FIFTH,
INTERVAL::MINOR_SEVENTH,
INTERVAL::MINOR_NINTH }
}
};
Я хотел бы получить доступ к аккордам аналогично enum
интервалов, чтобы я мог сделать что-то вроде этого (psudeocode):
void playChord(Chord chord, int velocity, int channel) {
int i;
for(i=0; i<chord.length; i++) {
usbMIDI.sendNoteOn(chord[i], velocity, channel);
}
}
playChord(Chord::MAJOR, 127, 1);
Я знаю, что невозможно иметь перечисление пользовательских типов, но есть ли способ, которым я мог бы приблизиться к этому? Я подумал об использовании HashTable, но мне пришлось бы реализовать его с нуля, и я не думаю, что если смогу помочь.
1 ответ
Смысл перечисления в том, что вы создаете новый тип, который может принимать только фиксированный набор значений. Для ваших интервалов целесообразно использовать enum, потому что в действительности используется только очень много интервалов, и потому что создание нового типа удобнее, чем использование здесь целочисленных констант.
История отличается для ваших аккордов. У вас уже есть тип для ваших аккордов, поэтому перенос их в другой тип enum не поможет. Кроме того, количество аккордов гораздо менее ограничено. Имеющаяся у меня диаграмма аккордов показывает 22 фигуры, но они не включают инверсии. Ваша структура аккордов гораздо более подходящая, чем искусственное ограничение аккордов с помощью enum.
В C есть два других механизма для создания "констант", отличных от перечислений: препроцессорные определения и статические переменные.
С помощью директивы препроцессора мы можем определить литерал Chord. Структурные литералы IIRC - это вещь C99, ранее существовали только литералы инициализатора.
#define CHORD_MAJOR ((Chord){"maj", {ROOT, MAJOR_THIRD, PERFECT_FIFTH}})
Со статической переменной вы бы объявили объект в заголовке:
static const Chord chord_major = {"maj", {ROOT, MAJOR_THIRD, PERFECT_FIFTH}};
Обратите внимание, что C не имеет оператора пространства имен, такого как ::
, Вместо этого вы должны сами префиксировать любые конфликтующие идентификаторы. C++ имеет пространства имен, но это не влияет на замечания, сделанные в этом ответе.