我试图创建一种算法,根据它们给定的音阶和转换因子,将音符向上或向下转换。
电流算法:
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);
}每个比额表(表示为这一目的的主要比额表)有7个音符。例如,C-主要比额表有以下说明:
C, D, E, F, G, A, and B如果要将这个音阶与上面的算法一起使用,来转换音符,例如,在C-主音阶上的一个5倍音阶上的'B‘音符,该算法将按预期的方式工作,并将音符'C’(音阶的索引0)返回为6的八度音阶。
然而,假设我们使用了由音符组成的D-专业音阶。
D, E, F♯, G, A, B, and C♯对于这个音阶,最后一个音符'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)); 是否有任何方法来修正上述算法,使其能够支持上述情况?
我为Note、Pitch和Scale类使用的Java类可以在这里找到:杰米·克雷恩·梅洛迪世代- GoogleCode
发布于 2015-02-21 20:11:36
您目前正在测试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);
}现在我们有了这个,我们可以很容易地把它扩展到一次超过八度的移动。如果没有测试,这一切都不会那么容易:
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);
}需要进行更多的测试,但这是一个很好的开始,所有这些都通过了:
@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 ...发布于 2015-02-21 19:29:44
我想当你通过音阶结束时,你不想要+1倍频程(在这个例子中是ScaleIndex 7)。当你通过C时,你想要+1倍频程。
编辑:
我已经很久没有用java编程了,我没有为它安装IDE,所以我会编写一些伪代码(没有类型)。另外,这只适用于正转置因子,它应该很容易调整负片,但我不想再模糊它了。我们的想法是首先知道我们上升了多少倍频度,这意味着我们至少要增加那么多的八度音阶。然后添加其余部分(必须小于一个完整的刻度),并在添加该值时查看是否通过了C。我们通过查看新编号来实现这一点,如果新的notenumber比旧的小,我们肯定已经超过了C。
public Note getNoteByScale(Scale scale, int transposeFactor) {
numberOfNotesInScale = scale.getNotesInScale().size();
numberOfScalesToTraverseAtLeast = transposeFactor / number_of_notes_in_scale; // this should be integer division
newOctave = this.octave + numberOfScalesToTraverseAtLeast;
restAfterDivide = transposeFactor % numberOfNotesInScale;
newScaleIndex = (scale.getScaleIndex(this.pitch) + restAfterDivide) % numberOfNotesInScale; // we are not gonna do +1 when we pass the end of the scale, so just do a modulo on the number of notes of the scale
newPitch = scale.getNotesInScale().get(newScaleIndex)
if (newPitch.getNoteNumber < this.pitch.getNoteNumber) // then we have passed C, so another octave
newOctave++;
return Note.createNote(scale.getNotesInScale().get(newPitch), newOctave, this.duration);
}对于一些测试驱动的开发,这将是一个理想的候选函数,我至少会围绕它编写一堆单元测试;)
发布于 2018-05-28 19:00:37
是的,我知道这是个老问题,但我需要类似的东西。基本上,这个问题可以分解为:给定一个注释("D")和一些正或负的半步(1),返回一个新的注,即原注转置(D#)。
这里的答案太复杂了。
试试这个:
public class Transposer {
enum TARGET { FLAT, SHARP };
static String[] SHARPS = { "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#" };
static String[] FLATS = { "A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab" };
static String transpose(String note, int halfSteps, TARGET target) {
if (target == null) {
// By default we like flats
target = TARGET.FLAT;
}
String[] scale = FLATS;
if (target == TARGET.SHARP) {
scale = SHARPS;
}
int index = findIndex(scale, note);
if (index < 0) return note; // Not found, just return note
String everythingelse = "";
if (note.length() > scale[index].length()) {
everythingelse = note.substring(scale[index].length());
}
index = index + halfSteps;
while (index < 0) {
index += scale.length; // Make the index positive
}
index = index % scale.length;
return scale[index]+everythingelse;
}
public static int findIndex(String[] scale, String note) {
int r = -1;
String root = note.substring(0,1);
if (note.charAt(1) == '#' || note.charAt(1) == 'b') {
root = note.substring(0,2);
}
for (int i=0; i<scale.length; ++i) {
if (scale[i].equalsIgnoreCase(root)) {
// Match.
return i;
}
}
return r;
}
public static void main(String args[]) {
String note = args[0];
int halfsteps = Integer.parseInt(args[1]);
System.out.println(note+" transposed "+halfsteps+" halfsteps is "+transpose(note, halfsteps, TARGET.FLAT));
}
}主要()是测试:
java -cp . Transposer A 1
A transposed 1 halfsteps is Bb
java -cp . Transposer Eb -3
Eb transposed -3 halfsteps is C
java -cp Transposer C7 2
C7 transposed 2 halfsteps is D7采用一个比额表是微不足道的:
String[] scale = { "C", "D", "E", "F", "G", "A", "B" };
for (String snote: scale) {
System.out.print(Transposer.transpose(snote,1,null));
}
System.out.println();
=> Db Eb F Gb Ab Bb Chttps://stackoverflow.com/questions/28650156
复制相似问题