Skip to content

Commit cb8fa97

Browse files
magic numbers factored into config file
1 parent d41d56f commit cb8fa97

File tree

9 files changed

+148
-83
lines changed

9 files changed

+148
-83
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies {
1717
compile 'au.com.codeka:carrot:2.4.2'
1818
compile 'com.ganderband:abcj:1.8'
1919
compile group: 'com.google.guava', name: 'guava', version: '28.1-jre'
20+
compile 'org.yaml:snakeyaml:1.25'
2021
testCompile group: 'junit', name: 'junit', version: '4.12'
2122
}
2223

src/main/java/de/saar/coli/arranger/Arrange.java

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22

33
import com.google.common.collect.ArrayListMultimap;
44
import com.google.common.collect.ListMultimap;
5+
import de.saar.coli.arranger.abc.AbcParser;
6+
import de.saar.coli.arranger.abc.AbcWriter;
57

68
import java.io.FileReader;
79
import java.io.FileWriter;
810
import java.io.IOException;
11+
import java.io.InputStreamReader;
912
import java.util.*;
1013

1114
public class Arrange {
15+
private Config config;
16+
1217
private static final VoicePart[] VOICE_PARTS = new VoicePart[]{
1318
new VoicePart("Tenor", Note.create("G3", 0), Note.create("B4", 0)),
1419
new VoicePart("Lead", Note.create("C3", 0), Note.create("G4", 0)),
@@ -18,26 +23,17 @@ public class Arrange {
1823

1924
private static final int TENOR = 0, LEAD = 1, BARI = 2, BASS = 3;
2025

26+
public Arrange(Config config) {
27+
this.config = config;
28+
}
29+
2130
public static void main(String[] args) throws IOException, AbcParser.AbcParsingException {
31+
Config config = Config.read(new InputStreamReader(Arrange.class.getResourceAsStream("/config.yaml")));
2232
Score score = new AbcParser().read(new FileReader("down_our_way.abc"));
2333

24-
// print score
25-
score.foreachNoteAndChord(LEAD, (note, chord) -> {
26-
StringBuilder buf = new StringBuilder();
27-
28-
for (int chordNote : chord.getNotes()) {
29-
buf.append(Note.getNoteName(chordNote));
30-
buf.append(" ");
31-
}
32-
33-
// System.out.printf("%s %s -> %s\n", note, chord, buf.toString());
34-
});
35-
36-
Arrange arranger = new Arrange();
34+
Arrange arranger = new Arrange(config);
3735
Score bestArrangedScore = arranger.arrange(score);
3836

39-
// System.out.println(bestArrangedScore);
40-
4137
AbcWriter abcw = new AbcWriter();
4238
FileWriter fw = new FileWriter("arranged.abc");
4339
abcw.write(bestArrangedScore, fw);
@@ -46,25 +42,16 @@ public static void main(String[] args) throws IOException, AbcParser.AbcParsingE
4642
}
4743

4844
private Score arrange(Score score) {
49-
List<List<List<Note>>> possibleNotes = computePossibleNotes(score);
50-
// for (List<List<Note>> notesAtTime : possibleNotes) {
51-
// System.out.println();
52-
// System.out.println("Tn: " + notesAtTime.get(TENOR));
53-
// System.out.println("Ld: " + notesAtTime.get(LEAD));
54-
// System.out.println("Br: " + notesAtTime.get(BARI));
55-
// System.out.println("Bs: " + notesAtTime.get(BASS));
56-
// }
57-
5845
int n = score.countNotes(LEAD);
46+
47+
List<List<List<Note>>> possibleNotes = computePossibleNotes(score);
5948
assert n == possibleNotes.size();
6049

6150
Map<Item, Integer> bestScores = new HashMap<>();
6251
BackpointerColumn backpointers = new BackpointerColumn(null);
6352
int time = 0;
6453

6554
for (int pos = 0; pos < n; pos++) {
66-
// System.err.printf("Processing position %d ...\n", pos);
67-
6855
List<List<Note>> notesHere = possibleNotes.get(pos);
6956
Chord chordHere = score.getChordAtTime(time);
7057

@@ -147,9 +134,8 @@ public ListMultimap<Item, Backpointer> getBackpointers() {
147134

148135
private Score extractBestScore(Item bestFinalItem, BackpointerColumn backpointers, Score originalScore) {
149136
List<Note[]> notes = new ArrayList<>();
150-
Item item = bestFinalItem;
151137

152-
// System.err.printf("[%03d] %s\n", notes.size(), item);
138+
Item item = bestFinalItem;
153139
notes.add(item.lastNotes);
154140

155141
while (backpointers != null) {
@@ -161,7 +147,7 @@ private Score extractBestScore(Item bestFinalItem, BackpointerColumn backpointer
161147
break;
162148
} else {
163149
item = bp.getPreviousItem();
164-
System.err.printf("[%03d] %s\n", notes.size(), item);
150+
// System.err.printf("[%03d] %s\n", notes.size(), item);
165151
notes.add(item.lastNotes);
166152

167153
backpointers = backpointers.getPrevious();
@@ -172,7 +158,7 @@ private Score extractBestScore(Item bestFinalItem, BackpointerColumn backpointer
172158

173159
Score ret = new Score();
174160
ret.setTitle(originalScore.getTitle());
175-
ret.setComposer("AK arranger");
161+
ret.setComposer(config.getArranger());
176162
ret.setKey(originalScore.getKey());
177163
ret.setQuartersPerMeasure(originalScore.getQuartersPerMeasure());
178164
ret.setLyrics(originalScore.getLyrics());
@@ -197,7 +183,7 @@ private int scoreTransition(Note[] from, Note[] to) {
197183
for (int part = 0; part < 4; part++) {
198184
if (part == TENOR || part == BARI) {
199185
if (from[part].getAbsoluteDistance(to[part]) > 3) {
200-
score -= 20;
186+
score += config.getScores().getHarmonyJumps();
201187
}
202188
}
203189
}
@@ -207,7 +193,7 @@ private int scoreTransition(Note[] from, Note[] to) {
207193
for (int other = part + 1; other < 4; other++) {
208194
if (from[part].getAbsoluteDistance(from[other]) == 12) {
209195
if (to[part].getAbsoluteDistance(to[other]) == 12) {
210-
score -= 20;
196+
score += config.getScores().getParallelOctaves();
211197
}
212198
}
213199
}
@@ -227,7 +213,7 @@ private int scoreLexicalChord(Note tn, Note ld, Note br, Note bs, Chord chord) {
227213

228214
// Tn likes to be highest note
229215
if (tn.getAbsoluteNote() < ld.getAbsoluteNote() || tn.getAbsoluteNote() < br.getAbsoluteNote()) {
230-
score -= 10;
216+
score += config.getScores().getTenorCrossing();
231217
}
232218

233219
// Bs really wants to be lowest note
@@ -239,14 +225,14 @@ private int scoreLexicalChord(Note tn, Note ld, Note br, Note bs, Chord chord) {
239225
// disprefer unison
240226
Set<Integer> differentAbsoluteNotes = new HashSet<>(List.of(tn.getAbsoluteNote(), ld.getAbsoluteNote(), br.getAbsoluteNote(), bs.getAbsoluteNote()));
241227
if (differentAbsoluteNotes.size() < 4) {
242-
score -= 50;
228+
score += config.getScores().getUnisonNotes();
243229
}
244230

245231
// disprefer very wide spread
246232
int highest = Collections.max(differentAbsoluteNotes);
247233
int lowest = Collections.min(differentAbsoluteNotes);
248-
if (highest - lowest > 19) { // octave + third
249-
score -= 20;
234+
if (highest - lowest > 19) { // octave + fifth
235+
score += config.getScores().getWideSpread();
250236
}
251237

252238
return score;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package de.saar.coli.arranger;
2+
3+
import org.yaml.snakeyaml.Yaml;
4+
import org.yaml.snakeyaml.constructor.Constructor;
5+
6+
import java.io.Reader;
7+
import java.util.Map;
8+
9+
public class Config {
10+
private String arranger;
11+
private Scores scores;
12+
13+
public static Config read(Reader configReader) {
14+
Yaml yaml = new Yaml(new Constructor(Config.class));
15+
return (Config) yaml.load(configReader);
16+
}
17+
18+
public Scores getScores() {
19+
return scores;
20+
}
21+
public void setScores(Scores scores) {
22+
this.scores = scores;
23+
}
24+
25+
public String getArranger() {
26+
return arranger;
27+
}
28+
29+
public void setArranger(String arranger) {
30+
this.arranger = arranger;
31+
}
32+
33+
public static class Scores {
34+
private int harmonyJumps;
35+
private int parallelOctaves;
36+
private int tenorCrossing;
37+
private int unisonNotes;
38+
private int wideSpread;
39+
40+
public int getHarmonyJumps() {
41+
return harmonyJumps;
42+
}
43+
44+
public void setHarmonyJumps(int harmonyJumps) {
45+
this.harmonyJumps = harmonyJumps;
46+
}
47+
48+
public int getParallelOctaves() {
49+
return parallelOctaves;
50+
}
51+
52+
public void setParallelOctaves(int parallelOctaves) {
53+
this.parallelOctaves = parallelOctaves;
54+
}
55+
56+
public int getTenorCrossing() {
57+
return tenorCrossing;
58+
}
59+
60+
public void setTenorCrossing(int tenorCrossing) {
61+
this.tenorCrossing = tenorCrossing;
62+
}
63+
64+
public int getUnisonNotes() {
65+
return unisonNotes;
66+
}
67+
68+
public void setUnisonNotes(int unisonNotes) {
69+
this.unisonNotes = unisonNotes;
70+
}
71+
72+
public int getWideSpread() {
73+
return wideSpread;
74+
}
75+
76+
public void setWideSpread(int wideSpread) {
77+
this.wideSpread = wideSpread;
78+
}
79+
}
80+
}

src/main/java/de/saar/coli/arranger/ScoreViewer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import abcj.model.TuneList;
88
import abcj.ui.MainGUI;
99
import abcj.ui.MainPane;
10+
import de.saar.coli.arranger.abc.AbcWriter;
1011

1112
import java.io.IOException;
1213
import java.io.StringWriter;

src/main/java/de/saar/coli/arranger/AbcParser.java renamed to src/main/java/de/saar/coli/arranger/abc/AbcParser.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
package de.saar.coli.arranger;
1+
package de.saar.coli.arranger.abc;
2+
3+
import de.saar.coli.arranger.Chord;
4+
import de.saar.coli.arranger.Key;
5+
import de.saar.coli.arranger.Note;
6+
import de.saar.coli.arranger.Score;
27

38
import javax.annotation.processing.Filer;
49
import java.io.*;

src/main/java/de/saar/coli/arranger/AbcWriter.java renamed to src/main/java/de/saar/coli/arranger/abc/AbcWriter.java

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,22 @@
1-
package de.saar.coli.arranger;
1+
package de.saar.coli.arranger.abc;
22

33
import au.com.codeka.carrot.CarrotEngine;
44
import au.com.codeka.carrot.CarrotException;
55
import au.com.codeka.carrot.Configuration;
66
import au.com.codeka.carrot.bindings.MapBindings;
7-
import au.com.codeka.carrot.resource.FileResourceLocator;
87
import au.com.codeka.carrot.resource.MemoryResourceLocator;
98
import au.com.codeka.carrot.resource.ResourceLocator;
9+
import de.saar.coli.arranger.Chord;
10+
import de.saar.coli.arranger.Key;
11+
import de.saar.coli.arranger.Note;
12+
import de.saar.coli.arranger.Score;
1013

1114
import java.io.*;
1215
import java.util.HashMap;
1316
import java.util.List;
1417
import java.util.Map;
1518

1619
public class AbcWriter {
17-
public static void main(String[] args) throws IOException {
18-
Score s = new Score("Test Song", "AK", "C", 4);
19-
20-
s.addNote(0, Note.create("E4", 2));
21-
s.addNote(1, Note.create("C4", 2));
22-
s.addNote(2, Note.create("G3", 2));
23-
s.addNote(3, Note.create("C3", 2));
24-
25-
s.addNote(1, Note.create("D4", 2));
26-
s.addNote(1, Note.create("E4", 2));
27-
s.addNote(1, Note.create("F4", 2));
28-
s.addNote(1, Note.create("C4", 2));
29-
s.addNote(1, Note.create("D4", 2));
30-
31-
s.addNote(0, Note.create("E4", 2));
32-
s.addNote(0, Note.create("E4", 2));
33-
s.addNote(0, Note.create("E4", 2));
34-
s.addNote(0, Note.create("E4", 2));
35-
s.addNote(0, Note.create("E4", 2));
36-
s.addNote(2, Note.create("G3", 2));
37-
s.addNote(3, Note.create("C3", 2));
38-
s.addNote(2, Note.create("G3", 2));
39-
s.addNote(3, Note.create("C3", 2));
40-
s.addNote(2, Note.create("G3", 2));
41-
s.addNote(3, Note.create("C3", 2));
42-
s.addNote(2, Note.create("G3", 2));
43-
s.addNote(3, Note.create("C3", 2));
44-
s.addNote(2, Note.create("G3", 2));
45-
s.addNote(3, Note.create("C3", 2));
46-
47-
48-
PrintWriter w = new PrintWriter(new OutputStreamWriter(System.out));
49-
AbcWriter abc = new AbcWriter();
50-
abc.write(s, w);
51-
w.println();
52-
w.close();
53-
}
54-
5520
public void write(Score score, Writer writer) throws IllegalArgumentException, IOException {
5621
CarrotEngine engine = new CarrotEngine(new Configuration.Builder()
5722
.setResourceLocator(makeResourceLocator())
@@ -115,15 +80,11 @@ private String abcNote(Note note, Key key, Chord currentChord) {
11580
// note exists in key of current chord, use chord key's accidental
11681
// (only if chord is available in score)
11782
n = note.getNoteName(chordKey, true);
118-
119-
120-
121-
122-
System.err.printf("%s in chord key %s -> spell as %s\n", Note.getNoteName(note.getRelativeNote()), chordKey, n);
83+
// System.err.printf("%s in chord key %s -> spell as %s\n", Note.getNoteName(note.getRelativeNote()), chordKey, n);
12384
} else {
12485
// note exists in neither, use fallback tactics for key
12586
n = note.getNoteName(key);
126-
System.err.printf("%s fallback spell as %s (chord key was %s)\n", Note.getNoteName(note.getRelativeNote()), n, chordKey);
87+
// System.err.printf("%s fallback spell as %s (chord key was %s)\n", Note.getNoteName(note.getRelativeNote()), n, chordKey);
12788
}
12889

12990
// convert standard spelling of accidentals to ABC notation

src/main/resources/config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
arranger: Automatically arranged by Alexander's Arranger
2+
3+
scores:
4+
harmonyJumps: -20
5+
parallelOctaves: -20
6+
tenorCrossing: -10
7+
unisonNotes: -50
8+
wideSpread: -20
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package de.saar.coli.arranger;
2+
3+
import org.junit.Test;
4+
import static org.junit.Assert.*;
5+
6+
import java.io.InputStream;
7+
import java.io.InputStreamReader;
8+
import java.io.Reader;
9+
10+
public class ConfigTest {
11+
@Test
12+
public void testConfigReader() {
13+
InputStream is = getClass().getResourceAsStream("/config.yaml");
14+
assertNotNull(is);
15+
16+
Reader r = new InputStreamReader(is);
17+
Config config = Config.read(r);
18+
19+
assertEquals("Automatically arranged by Alexander's Arranger", config.getArranger());
20+
assertEquals(-20, config.getScores().getHarmonyJumps());
21+
}
22+
}

src/test/java/de/saar/coli/arranger/ScoreTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package de.saar.coli.arranger;
22

3+
import de.saar.coli.arranger.abc.AbcParser;
34
import org.junit.Test;
45

56
import java.io.IOException;

0 commit comments

Comments
 (0)