Java中的枚举替代方案是什么?

3

我正在通过编写MIDI处理程序来自学Java。该程序需要能够在MIDI音符号码和它们对应的紧凑字符串表示之间进行转换。我考虑使用枚举设置,但由于命名约束,你不能这样做。

c-1, c#-1, ...  g9;

由于升降号的存在(是的,我遵循这种约定,让您最终得到一个负八度:P)。

必须在所允许和所需之间进行转换,这似乎有些笨拙。

CNEG1("c-1"),
CSNEG1("c#-1"),
DNEG1("d-1"),
...
G9("g9");

所以我想出了下面的静态导入方案,它工作得很好。然而,我想学习更多关于如何使用枚举的知识,并且我有一种预感,如果我更好地理解内部机制,它们可能更适合这个任务。那么我的问题是:有人能想出一种优雅的方法来使用枚举方案提供相同的功能吗?此外,是否有充分的理由这样做呢?

public abstract class MethodsAndConstants {

    public static final String TONICS[] = {"c","c#","d","d#","e","f","f#","g","g#","a","a#","b"};
    static final NoteMap notemap = new NoteMap();

    static class NoteMap{
        static String map[] = new String[128];

        NoteMap() {
            for (int i = 0; i < 128; i++){
                int octave = i/12 - 1;
                String tonic = MethodsAndConstants.TONICS[i%12];
                map[i] = tonic + octave;
            }
        }   
    }

    public static int convert_midi_note(String name){
        return indexOf(NoteMap.map, name);
    }

    public static String convert_midi_note(int note_num){   
        return NoteMap.map[note_num];
    }

    public static int indexOf(String[] a, String item){
        return java.util.Arrays.asList(a).indexOf(item);
    }       
}

编辑 ------------------------------------------

经过深思熟虑,我认为在这种特定情况下,枚举可能过于复杂了。我最终可能会使用下面这段代码,同样采用静态导入的方法,但不再需要像上面那样使用NoteMap。

音符号码到名称的转换非常简单明了,而名称到音符号码的转换只需要进行字符串解析即可。

public abstract class MethodsAndConstants {
    public static final String[] TONICS = {"c","c#","d","d#","e","f","f#","g","g#","a","a#","b"};

    static String convert(int i) {
        String tonic = MethodsAndConstants.TONICS[i%12];
        int octave = (i / 12) - 1;
        return tonic + octave;
    }

    static int convert(String s) {
        int tonic = java.util.Arrays.asList(MethodsAndConstants.TONICS).indexOf(s.substring(0,1));
        if (s.contains("#")) tonic += 1;
        int octave = Integer.parseInt(s.substring(s.length()-1));
        if (s.contains("-")) octave -= 2;   // case octave = -1
        int note_num = ((octave + 1) * 12) + tonic;
        return note_num;
    }
}

Note 是一个相关的例子。 - trashgod
2个回答

3
你可以使用枚举来表示音高,但是我可能会尝试将音高封装在一个类中。
public class Pitch {

    private final int octave;
    private final Note note;

    public enum Note {
        C("C",4), CSHARP("C#/Db",5), DFLAT("C#/Db",5), //and so on

        private final String thePitch;
        private final int midiAdjust;

        private Note(final String thePitch, final int midiAdjust) {
            this.thePitch = thePitch;
            this.midiAdjust = midiAdjust;
        }

        String getThePitch() {
            return thePitch;
        }

        int getMidiAdjust() {
            return midiAdjust;
        }
    }

    public Pitch(Note note, int octave) {
        this.note = note;
        this.octave = octave;
    }

    public int getMidiNumber(){
        return 12*octave + note.getMidiAdjust();
    }

}

这可能解释了音符(C、C#、D、D#、E…)将是一个重复集合中的一个,但你可以有各种八度,这种情况下由一个int处理。它将大大减小你的枚举大小。
编辑:我在这里添加了几行作为一个想法。你可以传递第二个参数到枚举的构造函数中,以允许你返回表示音高的MIDI号码。在这个例子中,我假设最低的由MIDI表示的数字是A,但我可能是错误的。另外,12*octave旨在为每个增量添加整个八度的音高。你可能需要稍微调整一下,因为我看到你正在使用那个奇怪的符号。

1

类似这样的:

public enum Note {
    CNEG1("c-1"), CSNEG1("c#-1"), DNEG1("d-1");

    private final String tonicOctave;

    private Note(final String tonicOctave) {
        this.tonicOctave = tonicOctave;
    }

    public String getTonicOctave() {
        return this.tonicOctave;
    }

    public static Note fromTonicOctave(final String val) {
        for (final Note note: Note.values()) {
            if (note.getTonicOctave().equals(val)) {
                return note;
            }
        }
        return null;
    }
}

请注意,您可以在枚举中拥有尽可能多的参数,因此如果您需要区分音调和八度,您可以这样做。

看起来很有趣。目前只能勉强开始解析它,但我会进行深入研究。 - TOZ
顺便说一下,我想我知道你所说的关于能够分离音调和八度的能力。类似于CNEG1(“c”,-1)之类的吧?可能会有用。 - TOZ
@TOZ,是的,CNEG1("c",-1) 是可能的。 - user180100
好的,很酷。经过一番努力,我发现使用你上面的枚举代码,我可以像这样在数字和名称之间进行转换:int midi_note_number = Note.fromTonicOctave(my_note_name).ordinal() String my_note_name = Note.values()[midi_note_number].getTonicOctave()不错。现在要更仔细地看看@gobernador的想法。 - TOZ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接