Pattern.java

package com.github.dakusui.symfonion.song;

import com.github.dakusui.json.JsonException;
import com.github.dakusui.json.JsonUtils;
import com.github.dakusui.symfonion.exceptions.SymfonionException;
import com.github.dakusui.symfonion.utils.Fraction;
import com.github.dakusui.symfonion.utils.Utils;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static com.github.dakusui.json.JsonUtils.asJsonElement;
import static com.github.dakusui.symfonion.exceptions.ExceptionThrower.illegalFormatException;
import static com.github.dakusui.symfonion.exceptions.ExceptionThrower.noteMapNotFoundException;
import static com.github.dakusui.symfonion.exceptions.SymfonionIllegalFormatException.NOTE_LENGTH_EXAMPLE;


public class Pattern {
  public static class Parameters {
    static final Fraction QUARTER = new Fraction(1, 4);
    double gate = 0.8;
    Fraction length = QUARTER;
    int transpose = 0;
    int velocityBase = 64;
    int velocityDelta = 10;
    int arpeggio;
    
    public Parameters(JsonObject json) throws SymfonionException, JsonException {
      init(json);
    }
    
    public double gate() {
      return this.gate;
    }
    
    private void init(JsonObject json) throws SymfonionException, JsonException {
      if (json == null) {
        json = JsonUtils.toJson("{}").getAsJsonObject();
      }
      this.velocityBase = JsonUtils.asIntWithDefault(json, 64, Keyword.$velocitybase);
      this.velocityDelta = JsonUtils.asIntWithDefault(json, 5, Keyword.$velocitydelta);
      this.gate = JsonUtils.asDoubleWithDefault(json, 0.8, Keyword.$gate);
      this.length = Utils.parseNoteLength(JsonUtils.asStringWithDefault(json, "4", Keyword.$length));
      if (this.length == null) {
        throw illegalFormatException(
            asJsonElement(json, Keyword.$length),
            NOTE_LENGTH_EXAMPLE
        );
      }
      this.transpose = JsonUtils.asIntWithDefault(json, 0, Keyword.$transpose);
      this.arpeggio = JsonUtils.asIntWithDefault(json, 0, Keyword.$arpeggio);
    }
    
    public Fraction length() {
      return this.length;
    }
    
    public int transpose() {
      return this.transpose;
    }
    
    public int velocitybase() {
      return this.velocityBase;
    }
    
    public int velocitydelta() {
      return this.velocityDelta;
    }
    
    public int arpegio() {
      return this.arpeggio;
    }
  }
  
  public static Pattern createPattern(JsonObject json, Map<String, NoteMap> noteMaps) throws SymfonionException, JsonException {
    NoteMap noteMap = NoteMap.defaultNoteMap;
    if (JsonUtils.hasPath(json, Keyword.$notemap)) {
      String noteMapName = JsonUtils.asString(json, Keyword.$notemap);
      noteMap = noteMaps.get(noteMapName);
      if (noteMap == null) {
        throw noteMapNotFoundException(asJsonElement(json, Keyword.$notemap), noteMapName);
      }
    }
    Pattern ret = new Pattern(noteMap);
    ret.init(json);
    return ret;
  }
  
  List<Stroke> body = null;
  NoteMap noteMap;
  Parameters params = null;
  
  Pattern(NoteMap noteMap) {
    this.noteMap = noteMap;
  }
  
  protected void init(JsonObject json) throws SymfonionException, JsonException {
    // Initialize 'body'.
    this.body = new LinkedList<>();
    this.params = new Parameters(json);
    JsonArray bodyJSON;
    if (asJsonElement(json, Keyword.$body).isJsonPrimitive()) {
      bodyJSON = new JsonArray();
      bodyJSON.add(asJsonElement(json, Keyword.$body));
    } else {
      bodyJSON = JsonUtils.asJsonArray(json, Keyword.$body);
    }
    int len = bodyJSON.size();
    for (int i = 0; i < len; i++) {
      JsonElement cur = bodyJSON.get(i);
      Stroke stroke = new Stroke(cur, params, this.noteMap);
      body.add(stroke);
    }
  }
  
  public List<Stroke> strokes() {
    return Collections.unmodifiableList(this.body);
  }
  
  public Parameters parameters() {
    return this.params;
  }
}