Dra*_*hix 4 java algorithm audio
我正在尝试创建一种算法,根据给定的比例和转置因子向上或向下转换音符.
当前算法:
public Note getNoteByScale(Scale scale, int transposeFactor) {
int newPitch = scale.getScaleIndex(this.pitch) + transposeFactor;
int newOctave = this.octave;
if (newPitch > 6) {
newPitch -= 7;
newOctave++;
}
if (newPitch < 0) {
newPitch += 7;
}
return Note.createNote(scale.getNotesInScale().get(newPitch),
newOctave, this.duration);
}
Run Code Online (Sandbox Code Playgroud)
每个尺度(表示为此目的的主要尺度)有7个音符.例如,C-Major Scale有以下注释:
C, D, E, F, G, A, and B
Run Code Online (Sandbox Code Playgroud)
如果您要使用上述算法的这个音阶来转换音符,例如,在C-Major音阶中的5个八度的八度音符上的'B'音符,算法将按预期工作并返回音符' C'(刻度的0指数)在6的倍频程上.
但是,假设我们使用了由笔记组成的D-Major Scale
D, E, F?, G, A, B, and C?
Run Code Online (Sandbox Code Playgroud)
对于这个音阶,最后一个音符'C♯'应该被认为比音阶中的其他音符高八度.例如,如果我们使用上面的算法将音符'B'(索引6)转换为5的八度音程,那么算法实际上会在5的八度音程上给出音符'C♯',这是完全错误的:它应该在6的八度.
Note original = Note.createNote(Pitch.B, 5, Duration.WHOLE);
// Prints: [Note: [pitch: C#],[octave: 5]]
System.out.println(original.getNoteByScale(Scale.D_MAJOR, 1));
Run Code Online (Sandbox Code Playgroud)
有没有办法解决上面的算法,以便它支持上述情况?
这我使用的Java类Note和Pitch和Scale类都可以在这里找到:杰米Craane旋律产生- googlecode上
您当前正在测试pitch(即该中的索引scale)以查看是否需要更改八度音程.
但是单个音阶可以包含多个八度音阶索引,这取决于音符本身相对于C的索引.我没有在这里使用该库的术语,因为我对它不太熟悉.因此,您需要知道相对于C的音符索引是否已经包裹(向下或向上)以便更改八度音程(向上或向下).
首先假设你从未超过一个transposeFactor值6.接下来在编写任何代码之前定义一些测试(见下文).然后我认为你只需要一个小的改变来使用Pitch.getNoteNumber()它返回相对于C的音符索引.我还假设你的getNoteByScale方法是一个方法Note,并且getScaleIndex是你创建的方法Scale,如下所示:
// this is a method on Scale
public int getScaleIndex(Pitch pitch) {
return notesInScale.indexOf(pitch);
}
...
public Note getNoteByScale(Scale scale, int transposeFactor) {
// rename to "newPitchIndex" to distinguish from the actual new Pitch object
int newPitchIndex = scale.getScaleIndex(this.pitch) + transposeFactor;
// only use pitch indexes for a scale in the range 0-6
if (newPitchIndex > 6) newPitchIndex -=7;
else if (newPitchIndex < 0) newPitchIndex += 7;
// create the new Pitch object
Pitch newPitch = scale.getNotesInScale().get(newPitchIndex);
// Get the note numbers (relative to C)
int noteNumber = this.pitch.getNoteNumber();
int newNoteNumber = newPitch.getNoteNumber();
int newOctave = this.octave;
if (transposeFactor > 0 && newNoteNumber < noteNumber) newOctave++;
else if (transposeFactor < 0 && newNoteNumber > noteNumber) newOctave--;
return Note.createNote(newPitch, newOctave, this.duration);
}
Run Code Online (Sandbox Code Playgroud)
现在我们已经拥有了它,我们可以轻松地将它扩展到一次移动超过八度.没有测试,这一切都不会那么容易:
public Note getNoteByScale(Scale scale, int transposeFactor) {
// move not by more than 7
int pitchIndex = scale.getScaleIndex(this.pitch);
int newPitchIndex = (pitchIndex + transposeFactor) % 7;
// and adjust negative values down from the maximum index
if (newPitchIndex < 0) newPitchIndex += 7;
// create the new Pitch object
Pitch newPitch = scale.getNotesInScale().get(newPitchIndex);
// Get the note numbers (relative to C)
int noteNumber = this.pitch.getNoteNumber();
int newNoteNumber = newPitch.getNoteNumber();
// Get the number of whole octave changes
int octaveChanges = transposeFactor / 7;
int newOctave = this.octave + octaveChanges;
// Adjust the octave based on a larger/smaller note index relative to C
if (transposeFactor > 0 && newNoteNumber < noteNumber) newOctave++;
else if (transposeFactor < 0 && newNoteNumber > noteNumber) newOctave--;
return Note.createNote(newPitch, newOctave, this.duration);
}
Run Code Online (Sandbox Code Playgroud)
需要比这更多的测试,但这是一个很好的启动器,所有这些都通过:
@Test
public void transposeUpGivesCorrectPitch() {
// ?~1?
// |D E F? G A B ?C?|D E F? G A B ?C? |
Note original = Note.createNote(Pitch.B, 5, Duration.WHOLE);
Note actual = original.getNoteByScale(Scale.D_MAJOR, 1);
Note expected = Note.createNote(Pitch.C_SHARP, 6, Duration.WHOLE);
assertEquals(expected.getPitch(), actual.getPitch());
}
@Test
public void transposeDownGivesCorrectPitch() {
// ?1~?
// |D E F? G A B ?C?|D E F? G A B ?C? |
Note original = Note.createNote(Pitch.C_SHARP, 6, Duration.WHOLE);
Note actual = original.getNoteByScale(Scale.D_MAJOR, -1);
Note expected = Note.createNote(Pitch.B, 5, Duration.WHOLE);
assertEquals(expected.getPitch(), actual.getPitch());
}
@Test
public void transposeUpOutsideScaleGivesCorrectPitch() {
// ??1?~2??3??4?
// ?C D E F G A B ?C D E F G A B |
Note original = Note.createNote(Pitch.A, 5, Duration.WHOLE);
Note actual = original.getNoteByScale(Scale.C_MAJOR, 4);
Note expected = Note.createNote(Pitch.E, 6, Duration.WHOLE);
assertEquals(expected.getPitch(), actual.getPitch());
}
@Test
public void transposeDownOutsideScaleGivesCorrectPitch() {
// ?4??3??2??1~?
// ?C D E F G A B ?C D E F G A B |
Note original = Note.createNote(Pitch.C, 6, Duration.WHOLE);
Note actual = original.getNoteByScale(Scale.C_MAJOR, -4);
Note expected = Note.createNote(Pitch.F, 5, Duration.WHOLE);
assertEquals(expected.getPitch(), actual.getPitch());
}
@Test
public void transposeUpGivesCorrectOctave() {
// ?~1?
// |D E F? G A B ?C?|D E F? G A B ?C? |
Note original = Note.createNote(Pitch.B, 5, Duration.WHOLE);
Note actual = original.getNoteByScale(Scale.D_MAJOR, 1);
Note expected = Note.createNote(Pitch.C_SHARP, 6, Duration.WHOLE);
assertEquals(expected.getOctave(), actual.getOctave());
}
@Test
public void transposeUp2GivesCorrectOctave() {
// ?~1??2??3??4??5??6??7?~1?
// |D E F? G A B ?C?|D E F? G A B ?C? |
Note original = Note.createNote(Pitch.B, 5, Duration.WHOLE);
Note actual = original.getNoteByScale(Scale.D_MAJOR, 1 + 7);
Note expected = Note.createNote(Pitch.C_SHARP, 7, Duration.WHOLE);
assertEquals(expected.getOctave(), actual.getOctave());
}
@Test
public void transposeDownGivesCorrectOctave() {
// ?1~?
// |D E F? G A B ?C?|D E F? G A B ?C? |
Note original = Note.createNote(Pitch.C_SHARP, 6, Duration.WHOLE);
Note actual = original.getNoteByScale(Scale.D_MAJOR, -1);
Note expected = Note.createNote(Pitch.B, 5, Duration.WHOLE);
assertEquals(expected.getOctave(), actual.getOctave());
}
@Test
public void transposeDown2GivesCorrectOctave() {
// ?1~?7??6??5??4??3??2??1~?
// |D E F? G A B ?C?|D E F? G A B ?C? |
Note original = Note.createNote(Pitch.C_SHARP, 6, Duration.WHOLE);
Note actual = original.getNoteByScale(Scale.D_MAJOR, -1 - 7);
Note expected = Note.createNote(Pitch.B, 4, Duration.WHOLE);
assertEquals(expected.getOctave(), actual.getOctave());
}
// ... and more tests are needed ...
Run Code Online (Sandbox Code Playgroud)