使用自定义类型实现类似枚举的功能
Implementing enum like functionality with custom types
我正在使用 Teensy 开发 USB MIDI 控制器。控制器是一排7个按钮,每个按钮是一个进行度数,7个按钮组成一个和弦进行。按下时,设备会发送一个 MIDI 音符 on/off 消息来演奏和弦。
在我的代码中,我将 intervals 存储在 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
音程的方式访问和弦,这样我就可以做这样的事情(伪代码):
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);
我知道不可能有自定义类型的枚举,但有什么办法可以接近这个吗?我考虑过使用哈希表,但我必须从头开始实现它,如果我能帮上忙,我不希望这样做。
枚举的要点是您创建了一个新类型,它只能采用一组固定值。你的区间使用枚举是合适的,因为实际使用的区间只有这么多,而且在这里创建一个新类型比使用整数常量更方便。
故事因你的和弦而不同。您已经有了一个和弦类型,因此将它们包装在另一个枚举类型中没有帮助。此外,和弦的数量远没有那么有限。我手头的和弦图显示了 22 种形状,但不包括转位。你的和弦结构比用枚举人为限制和弦更合适。
除了枚举之外,C 还有另外两种创建“常量”的机制:preprocessor-defines 和静态变量。
使用预处理器指令,我们可以定义和弦文字。 IIRC 结构文字是 C99 的东西,以前只能有初始化程序文字。
#define CHORD_MAJOR ((Chord){"maj", {ROOT, MAJOR_THIRD, PERFECT_FIFTH}})
使用静态变量,您可以在 header 中声明一个 object:
static const Chord chord_major = {"maj", {ROOT, MAJOR_THIRD, PERFECT_FIFTH}};
请注意,C 没有像 ::
这样的名称空间运算符。相反,您必须自己为任何可能冲突的标识符添加前缀。 C++ 确实有命名空间,但这并不影响本答案中提出的要点。
我正在使用 Teensy 开发 USB MIDI 控制器。控制器是一排7个按钮,每个按钮是一个进行度数,7个按钮组成一个和弦进行。按下时,设备会发送一个 MIDI 音符 on/off 消息来演奏和弦。
在我的代码中,我将 intervals 存储在 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
音程的方式访问和弦,这样我就可以做这样的事情(伪代码):
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);
我知道不可能有自定义类型的枚举,但有什么办法可以接近这个吗?我考虑过使用哈希表,但我必须从头开始实现它,如果我能帮上忙,我不希望这样做。
枚举的要点是您创建了一个新类型,它只能采用一组固定值。你的区间使用枚举是合适的,因为实际使用的区间只有这么多,而且在这里创建一个新类型比使用整数常量更方便。
故事因你的和弦而不同。您已经有了一个和弦类型,因此将它们包装在另一个枚举类型中没有帮助。此外,和弦的数量远没有那么有限。我手头的和弦图显示了 22 种形状,但不包括转位。你的和弦结构比用枚举人为限制和弦更合适。
除了枚举之外,C 还有另外两种创建“常量”的机制:preprocessor-defines 和静态变量。
使用预处理器指令,我们可以定义和弦文字。 IIRC 结构文字是 C99 的东西,以前只能有初始化程序文字。
#define CHORD_MAJOR ((Chord){"maj", {ROOT, MAJOR_THIRD, PERFECT_FIFTH}})
使用静态变量,您可以在 header 中声明一个 object:
static const Chord chord_major = {"maj", {ROOT, MAJOR_THIRD, PERFECT_FIFTH}};
请注意,C 没有像 ::
这样的名称空间运算符。相反,您必须自己为任何可能冲突的标识符添加前缀。 C++ 确实有命名空间,但这并不影响本答案中提出的要点。