| 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 |
|
| 69 |
1.1 |
|
| 73 |
1.1 |
|
| 77 |
1.1 |
|
| 85 |
1.1 |
|
| 93 |
1.1 |
|
| 95 |
1.1 |
|
| 98 |
1.1 |
|
| 105 |
1.1 |
|
| 108 |
1.1 |
|
| 109 |
1.1 |
|
| 113 |
1.1 |
|
| 117 |
1.1 |
|
| 121 |
1.1 |
|
| 125 |
1.1 |
|
| 126 |
1.1 |