Skip to content

Commit d0e616a

Browse files
committed
Add positions apart from middle C calculator
- gonna use to help draw notes on a staff - we'll know the height of individual notes, and we know where middle C will be drawn - thus, knowing how far away from middle c, we'll know where to draw each note (y position)
1 parent 5ce09be commit d0e616a

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.ataulm.notes;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
class PositionsApartFromMiddleCCalculator {
7+
8+
private static final Map<Key, String[]> CHROMATIC_SCALES_FROM_C = new HashMap<>();
9+
private static final Note MIDDLE_C = Note.create(60);
10+
11+
static {
12+
CHROMATIC_SCALES_FROM_C.put(Key.C_MAJ, new String[]{"C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "A♯", "B"});
13+
CHROMATIC_SCALES_FROM_C.put(Key.G_MAJ, new String[]{"C", "C♯", "D", "D♯", "E", "F♮", "F", "G", "G♯", "A", "A♯", "B"});
14+
CHROMATIC_SCALES_FROM_C.put(Key.F_MAJ, new String[]{"C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "B", "B♮"});
15+
}
16+
17+
int positionsApartFromMiddleC(Key key, Note note) {
18+
if (MIDDLE_C.equals(note)) {
19+
return 0;
20+
}
21+
22+
String[] notes = CHROMATIC_SCALES_FROM_C.get(key);
23+
if (note.isHigherThan(MIDDLE_C)) {
24+
return -positionsApart(MIDDLE_C.midi(), note.midi(), notes);
25+
} else {
26+
return positionsApart(note.midi(), MIDDLE_C.midi(), notes);
27+
}
28+
}
29+
30+
private int positionsApart(int lowerPitch, int higherPitch, String[] notes) {
31+
int positionsAway = 0;
32+
33+
String last = notes[lowerPitch % notes.length];
34+
for (int pitch = lowerPitch; pitch <= higherPitch; pitch++) {
35+
String next = notes[pitch % notes.length];
36+
if (!next.startsWith(last.substring(0, 1))) {
37+
positionsAway++;
38+
}
39+
last = next;
40+
}
41+
return positionsAway;
42+
}
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.ataulm.notes;
2+
3+
class Fixtures {
4+
5+
static final Note C3 = Note.create(48);
6+
static final Note C_S3 = Note.create(49);
7+
static final Note D3 = Note.create(50);
8+
static final Note D_S3 = Note.create(51);
9+
static final Note E3 = Note.create(52);
10+
static final Note F3 = Note.create(53);
11+
static final Note F_S3 = Note.create(54);
12+
static final Note G3 = Note.create(55);
13+
static final Note G_S3 = Note.create(56);
14+
static final Note A3 = Note.create(57);
15+
static final Note A_S3 = Note.create(58);
16+
static final Note B3 = Note.create(59);
17+
18+
static final Note C4 = Note.create(60);
19+
static final Note C_S4 = Note.create(61);
20+
static final Note D4 = Note.create(62);
21+
static final Note D_S4 = Note.create(63);
22+
static final Note E4 = Note.create(64);
23+
static final Note F4 = Note.create(65);
24+
static final Note F_S4 = Note.create(66);
25+
static final Note G4 = Note.create(67);
26+
static final Note G_S4 = Note.create(68);
27+
static final Note A4 = Note.create(69);
28+
static final Note A_S4 = Note.create(70);
29+
static final Note B4 = Note.create(71);
30+
31+
static final Note C5 = Note.create(72);
32+
static final Note C_S5 = Note.create(73);
33+
static final Note D5 = Note.create(74);
34+
static final Note D_S5 = Note.create(75);
35+
static final Note E5 = Note.create(76);
36+
static final Note F5 = Note.create(77);
37+
static final Note F_S5 = Note.create(78);
38+
static final Note G5 = Note.create(79);
39+
static final Note G_S5 = Note.create(80);
40+
static final Note A5 = Note.create(81);
41+
static final Note A_S5 = Note.create(82);
42+
static final Note B5 = Note.create(83);
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package com.ataulm.notes;
2+
3+
import org.junit.Test;
4+
import org.junit.runner.RunWith;
5+
import org.junit.runners.Parameterized;
6+
7+
import java.util.Arrays;
8+
9+
import static com.ataulm.notes.Fixtures.A3;
10+
import static com.ataulm.notes.Fixtures.A4;
11+
import static com.ataulm.notes.Fixtures.A_S3;
12+
import static com.ataulm.notes.Fixtures.A_S4;
13+
import static com.ataulm.notes.Fixtures.B3;
14+
import static com.ataulm.notes.Fixtures.B4;
15+
import static com.ataulm.notes.Fixtures.B5;
16+
import static com.ataulm.notes.Fixtures.C3;
17+
import static com.ataulm.notes.Fixtures.C4;
18+
import static com.ataulm.notes.Fixtures.C5;
19+
import static com.ataulm.notes.Fixtures.C_S4;
20+
import static com.ataulm.notes.Fixtures.D4;
21+
import static com.ataulm.notes.Fixtures.D_S4;
22+
import static com.ataulm.notes.Fixtures.E4;
23+
import static com.ataulm.notes.Fixtures.F4;
24+
import static com.ataulm.notes.Fixtures.F_S4;
25+
import static com.ataulm.notes.Fixtures.G4;
26+
import static com.ataulm.notes.Fixtures.G_S4;
27+
import static org.fest.assertions.api.Assertions.assertThat;
28+
29+
@RunWith(Parameterized.class)
30+
public class PositionsApartFromMiddleCCalculatorTest {
31+
32+
@Parameterized.Parameters(name = "Given {1} in Key {0}, expected expectedPositionFromMiddleC: {2}")
33+
public static Iterable<Object[]> data() {
34+
return Arrays.asList(new Object[][]{
35+
{Key.C_MAJ, C3, 7},
36+
{Key.C_MAJ, A3, 2},
37+
{Key.C_MAJ, A_S3, 2},
38+
{Key.C_MAJ, B3, 1},
39+
{Key.C_MAJ, C4, 0},
40+
{Key.C_MAJ, C_S4, 0},
41+
{Key.C_MAJ, D4, -1},
42+
{Key.C_MAJ, D_S4, -1},
43+
{Key.C_MAJ, E4, -2},
44+
{Key.C_MAJ, F4, -3},
45+
{Key.C_MAJ, F_S4, -3},
46+
{Key.C_MAJ, G4, -4},
47+
{Key.C_MAJ, G_S4, -4},
48+
{Key.C_MAJ, A4, -5},
49+
{Key.C_MAJ, A_S4, -5},
50+
{Key.C_MAJ, B4, -6},
51+
{Key.C_MAJ, C5, -7},
52+
{Key.C_MAJ, B5, -13},
53+
54+
{Key.G_MAJ, C3, 7},
55+
{Key.G_MAJ, A3, 2},
56+
{Key.G_MAJ, A_S3, 2},
57+
{Key.G_MAJ, B3, 1},
58+
{Key.G_MAJ, C4, 0},
59+
{Key.G_MAJ, C_S4, 0},
60+
{Key.G_MAJ, D4, -1},
61+
{Key.G_MAJ, D_S4, -1},
62+
{Key.G_MAJ, E4, -2},
63+
{Key.G_MAJ, F4, -3},
64+
{Key.G_MAJ, F_S4, -3},
65+
{Key.G_MAJ, G4, -4},
66+
{Key.G_MAJ, G_S4, -4},
67+
{Key.G_MAJ, A4, -5},
68+
{Key.G_MAJ, A_S4, -5},
69+
{Key.G_MAJ, B4, -6},
70+
{Key.G_MAJ, C5, -7},
71+
{Key.G_MAJ, B5, -13},
72+
73+
{Key.F_MAJ, C3, 7},
74+
{Key.F_MAJ, A3, 2},
75+
{Key.F_MAJ, A_S3, 1},
76+
{Key.F_MAJ, B3, 1},
77+
{Key.F_MAJ, C4, 0},
78+
{Key.F_MAJ, C_S4, 0},
79+
{Key.F_MAJ, D4, -1},
80+
{Key.F_MAJ, D_S4, -1},
81+
{Key.F_MAJ, E4, -2},
82+
{Key.F_MAJ, F4, -3},
83+
{Key.F_MAJ, F_S4, -3},
84+
{Key.F_MAJ, G4, -4},
85+
{Key.F_MAJ, G_S4, -4},
86+
{Key.F_MAJ, A4, -5},
87+
{Key.F_MAJ, A_S4, -6},
88+
{Key.F_MAJ, B4, -6},
89+
{Key.F_MAJ, C5, -7},
90+
{Key.F_MAJ, B5, -13}
91+
});
92+
}
93+
94+
@Parameterized.Parameter(0)
95+
public Key key;
96+
97+
@Parameterized.Parameter(1)
98+
public Note note;
99+
100+
@Parameterized.Parameter(2)
101+
public int expectedPositionFromMiddleC;
102+
103+
PositionsApartFromMiddleCCalculator calculator = new PositionsApartFromMiddleCCalculator();
104+
105+
@Test
106+
public void positionFromMiddleC() {
107+
int positionFromMiddleC = calculator.positionsApartFromMiddleC(key, note);
108+
109+
assertThat(positionFromMiddleC).isEqualTo(expectedPositionFromMiddleC);
110+
}
111+
112+
}

0 commit comments

Comments
 (0)