Measure.java

1
package com.github.dakusui.symfonion.song;
2
3
import com.github.dakusui.symfonion.compat.json.CompatJsonUtils;
4
import com.github.dakusui.symfonion.utils.Fraction;
5
import com.google.gson.JsonArray;
6
import com.google.gson.JsonElement;
7
import com.google.gson.JsonObject;
8
9
import java.util.ArrayList;
10
import java.util.HashMap;
11
import java.util.List;
12
import java.util.Map;
13
import java.util.Optional;
14
import java.util.function.Predicate;
15
16
import static com.github.dakusui.symfonion.compat.json.CompatJsonUtils.asJsonArray;
17
import static com.github.dakusui.symfonion.compat.json.CompatJsonUtils.asJsonObject;
18
import static com.github.dakusui.symfonion.song.Bar.extractBeatsFractionFrom;
19
import static com.github.dakusui.symfonion.song.Bar.resolveLabelsForBar;
20
import static com.github.dakusui.symfonion.song.Keyword.parts;
21
import static com.github.valid8j.fluent.Expectations.precondition;
22
import static com.github.valid8j.fluent.Expectations.value;
23
24
public class Measure {
25
  private final Groove                   groove;
26
  private final Fraction                 beats;
27
  private final List<String>             activePartNames;
28
  private final Map<String, PartMeasure> partMeasures;
29
  private final List<String>             labels;
30
31
  /**
32
   * // @formatter:off
33
   * [source, JSON]
34
   * .measureJsonObject
35
   * ----
36
   * {
37
   *   "beats": "<beatsDefiningString>",
38
   *   "parts": [
39
   *     {
40
   *         "name": "<partName1>",
41
   *         "notes": "<strokeSequence1>",
42
   *         "reverb": ["<number>", "...", "<number>"],
43
   *         "<otherArrayableControls>": ["..."]
44
   *     },
45
   *     {
46
   *         "name": "<partName2>",
47
   *         "...": "..."
48
   *     }
49
   *   ],
50
   *   "groove": "<groove:array@[object:grooveUnit]>",
51
   *   "labels": ["<label1>", "<label2>", "..."]
52
   * }
53
   * ----
54
   * // @formatter:on
55
   */
56
  public Measure(JsonObject measureJsonObject, Map<String, NoteMap> noteMaps, Predicate<String> partFilter) {
57
    this.beats           = extractBeatsFractionFrom(measureJsonObject);
58
    this.groove          = composeGroove(measureJsonObject).orElse(Groove.defaultGrooveOf(this.beats));
59
    this.activePartNames = resolvePartNames(measureJsonObject);
60
    this.partMeasures    = composePartMeasures(measureJsonObject, this.activePartNames, noteMaps, partFilter);
61
    this.labels          = resolveLabelsForBar(measureJsonObject);
62
  }
63
64
  public Groove groove() {
65 1 1. groove : replaced return value with null for com/github/dakusui/symfonion/song/Measure::groove → NO_COVERAGE
    return this.groove;
66
  }
67
68
  public List<String> activePartNames() {
69 1 1. activePartNames : replaced return value with Collections.emptyList for com/github/dakusui/symfonion/song/Measure::activePartNames → NO_COVERAGE
    return this.activePartNames;
70
  }
71
72
  public Fraction beats() {
73 1 1. beats : replaced return value with null for com/github/dakusui/symfonion/song/Measure::beats → NO_COVERAGE
    return this.beats;
74
  }
75
76
  public List<String> labels() {
77 1 1. labels : replaced return value with Collections.emptyList for com/github/dakusui/symfonion/song/Measure::labels → NO_COVERAGE
    return this.labels;
78
  }
79
80
  public PartMeasure partMeasureFor(String partName) {
81
    assert precondition(value(this.partMeasures).invoke("containsKey", partName)
82
                                                .asBoolean()
83
                                                .toBe()
84
                                                .trueValue());
85 1 1. partMeasureFor : replaced return value with null for com/github/dakusui/symfonion/song/Measure::partMeasureFor → NO_COVERAGE
    return this.partMeasures.get(partName);
86
  }
87
88
  private static List<String> resolvePartNames(JsonObject measureJsonObject) {
89
    assert precondition(value(measureJsonObject).toBe().notNull());
90
    JsonArray partsArray = asJsonArray(measureJsonObject, parts);
91
    List<String> names = new ArrayList<>();
92
    for (JsonElement elem : partsArray) {
93 1 1. resolvePartNames : negated conditional → NO_COVERAGE
      if (elem.isJsonObject()) {
94
        String name = CompatJsonUtils.asString(elem.getAsJsonObject(), Keyword.name);
95 1 1. resolvePartNames : negated conditional → NO_COVERAGE
        if (!names.contains(name)) names.add(name);
96
      }
97
    }
98 1 1. resolvePartNames : replaced return value with Collections.emptyList for com/github/dakusui/symfonion/song/Measure::resolvePartNames → NO_COVERAGE
    return List.copyOf(names);
99
  }
100
101
  private static Map<String, PartMeasure> composePartMeasures(JsonObject measureJsonObject, List<String> partNames, Map<String, NoteMap> noteMaps, Predicate<String> partFilter) {
102
    JsonArray partsArray = asJsonArray(measureJsonObject, parts);
103
    Map<String, PartMeasure> partMeasures = new HashMap<>();
104
    for (JsonElement elem : partsArray) {
105 1 1. composePartMeasures : negated conditional → NO_COVERAGE
      if (!elem.isJsonObject()) continue;
106
      JsonObject partObj  = elem.getAsJsonObject();
107
      String     partName = CompatJsonUtils.asString(partObj, Keyword.name);
108 1 1. composePartMeasures : negated conditional → NO_COVERAGE
      if (!partFilter.test(partName)) continue;
109 1 1. composePartMeasures : negated conditional → NO_COVERAGE
      if (!partMeasures.containsKey(partName)) {
110
        partMeasures.put(partName, composePartMeasure(partObj, noteMaps.getOrDefault(partName, NoteMap.defaultNoteMap)));
111
      }
112
    }
113 1 1. composePartMeasures : replaced return value with Collections.emptyMap for com/github/dakusui/symfonion/song/Measure::composePartMeasures → NO_COVERAGE
    return partMeasures;
114
  }
115
116
  private static PartMeasure composePartMeasure(JsonObject partMeasureJsonObject, NoteMap noteMap) {
117 1 1. composePartMeasure : replaced return value with null for com/github/dakusui/symfonion/song/Measure::composePartMeasure → NO_COVERAGE
    return new PartMeasure(partMeasureJsonObject, composePartMeasureParameters(partMeasureJsonObject, noteMap));
118
  }
119
120
  private static PartMeasureParameters composePartMeasureParameters(JsonObject partMeasureJsonObject, NoteMap noteMap) {
121 1 1. composePartMeasureParameters : replaced return value with null for com/github/dakusui/symfonion/song/Measure::composePartMeasureParameters → NO_COVERAGE
    return new PartMeasureParameters(asJsonObject(partMeasureJsonObject, "parameters"), noteMap);
122
  }
123
124
  private static Optional<Groove> composeGroove(JsonObject measureJsonObject) {
125 1 1. composeGroove : negated conditional → NO_COVERAGE
    if (CompatJsonUtils.hasPath(measureJsonObject, Keyword.groove))
126 1 1. composeGroove : replaced return value with Optional.empty for com/github/dakusui/symfonion/song/Measure::composeGroove → NO_COVERAGE
      return Optional.of(Groove.createGroove(CompatJsonUtils.asJsonArray(measureJsonObject, Keyword.groove)));
127
    return Optional.empty();
128
  }
129
}

Mutations

65

1.1
Location : groove
Killed by : none
replaced return value with null for com/github/dakusui/symfonion/song/Measure::groove → NO_COVERAGE

69

1.1
Location : activePartNames
Killed by : none
replaced return value with Collections.emptyList for com/github/dakusui/symfonion/song/Measure::activePartNames → NO_COVERAGE

73

1.1
Location : beats
Killed by : none
replaced return value with null for com/github/dakusui/symfonion/song/Measure::beats → NO_COVERAGE

77

1.1
Location : labels
Killed by : none
replaced return value with Collections.emptyList for com/github/dakusui/symfonion/song/Measure::labels → NO_COVERAGE

85

1.1
Location : partMeasureFor
Killed by : none
replaced return value with null for com/github/dakusui/symfonion/song/Measure::partMeasureFor → NO_COVERAGE

93

1.1
Location : resolvePartNames
Killed by : none
negated conditional → NO_COVERAGE

95

1.1
Location : resolvePartNames
Killed by : none
negated conditional → NO_COVERAGE

98

1.1
Location : resolvePartNames
Killed by : none
replaced return value with Collections.emptyList for com/github/dakusui/symfonion/song/Measure::resolvePartNames → NO_COVERAGE

105

1.1
Location : composePartMeasures
Killed by : none
negated conditional → NO_COVERAGE

108

1.1
Location : composePartMeasures
Killed by : none
negated conditional → NO_COVERAGE

109

1.1
Location : composePartMeasures
Killed by : none
negated conditional → NO_COVERAGE

113

1.1
Location : composePartMeasures
Killed by : none
replaced return value with Collections.emptyMap for com/github/dakusui/symfonion/song/Measure::composePartMeasures → NO_COVERAGE

117

1.1
Location : composePartMeasure
Killed by : none
replaced return value with null for com/github/dakusui/symfonion/song/Measure::composePartMeasure → NO_COVERAGE

121

1.1
Location : composePartMeasureParameters
Killed by : none
replaced return value with null for com/github/dakusui/symfonion/song/Measure::composePartMeasureParameters → NO_COVERAGE

125

1.1
Location : composeGroove
Killed by : none
negated conditional → NO_COVERAGE

126

1.1
Location : composeGroove
Killed by : none
replaced return value with Optional.empty for com/github/dakusui/symfonion/song/Measure::composeGroove → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1