BrailleChord.java :  » XML » freedots » freedots » braille » Java Open Source

Java Open Source » XML » freedots 
freedots » freedots » braille » BrailleChord.java
/* -*- c-basic-offset: 2; indent-tabs-mode: nil; -*- */
/*
 * FreeDots -- MusicXML to braille music transcription
 *
 * Copyright 2008-2010 Mario Lang  All Rights Reserved.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details (a copy is included in the LICENSE.txt file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License
 * along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This file is maintained by Mario Lang <mlang@delysid.org>.
 */
package freedots.braille;

import java.util.Comparator;
import java.util.Iterator;

import freedots.Options;
import freedots.music.AbstractPitch;
import freedots.music.Accidental;
import freedots.music.Fingering;
import freedots.music.RhythmicElement;
import freedots.music.Slur;
import freedots.music.VoiceChord;
import freedots.musicxml.Note;

/** Represents several notes with same duration and start time, i.e., a chord.
 */
public class BrailleChord extends BrailleList {
  private final VoiceChord chord;
  private final BrailleNote topNote;

  /** Constructs the braille representation of the given chord.
   * @param chord is essentially a list of notes
   * @param comparator specifies how the list of notes should be sorted
   * @param lastPitch is used to decide if an {@link OctaveSign octave sign}
   *        should be printed.  It should be {@code null} if an octave sign
   *        should be printed regardless of the previous pitch.
   */
  public BrailleChord(final VoiceChord chord,
                      final Comparator<RhythmicElement> comparator,
                      final AbstractPitch lastPitch) {
    super();
    this.chord = chord;

    final VoiceChord sorted = (VoiceChord)chord.clone();
    java.util.Collections.sort(sorted, comparator);
    final Iterator<RhythmicElement> iterator = sorted.iterator();
    assert iterator.hasNext();

    final boolean allNotesTied = hasAllNotesTied();

    final Note firstNote = (Note)iterator.next();
    add(topNote = new BrailleNote(firstNote, lastPitch, !allNotesTied));

    assert iterator.hasNext();

    while (iterator.hasNext()) {
      add(new ChordStep((Note)iterator.next(), firstNote, !allNotesTied));
    }

    if (allNotesTied) add(new ChordTieSign());
  }
  @Override public String getDescription() {
    return "A chord.";
  }
  @Override public Object getScoreObject() { return chord; }

  /** Returns the pitch of the first note of this chord.
   * <p>
   * The first note is chord direction dependant, if the chord is written
   * from bottom to top note, this method returns the lowest pitch of the
   * chord.
   */
  public AbstractPitch getNotePitch() { return topNote.getPitch(); }

  private boolean hasAllNotesTied() {
    final Iterator<RhythmicElement> iterator = chord.iterator();
    while (iterator.hasNext()) {
      if (!((Note)iterator.next()).isTieStart()) return false;
    }
    return true;
  }

  /** Represents an interval in the braille chord.
   */
  public static class ChordStep extends BrailleList {
    private final Note note;

    ChordStep(final Note note, final Note relativeTo,
              final boolean allowTieSign) {
      super();
      this.note = note;

      final Options options = Options.getInstance();

      final Accidental accidental = note.getAccidental();
      if (accidental != null) add(new AccidentalSign(accidental));

      AbstractPitch thisPitch = note.getPitch();
      if (thisPitch == null) thisPitch = note.getUnpitched();
      AbstractPitch otherPitch = relativeTo.getPitch();
      if (otherPitch == null) otherPitch = relativeTo.getUnpitched();

      int diatonicDiff = Math.abs(thisPitch.diatonicDifference(otherPitch));
      if (diatonicDiff == 0 || diatonicDiff > 7) {
        add(new OctaveSign(thisPitch.getOctave()));
        while (diatonicDiff > 7) diatonicDiff -= 7;
      }
      add(new IntervalSign(diatonicDiff));

      if (options.getShowFingering()) {
        final Fingering fingering = note.getFingering();
        if (!fingering.getFingers().isEmpty())
          add(new BrailleFingering(fingering));
      }

      boolean addSingleSlur = false;
      boolean addDoubledSlur = false;
      for (Slur<Note> slur: note.getSlurs()) {
        if (slur.countArcs(note) >= options.getSlurDoublingThreshold()) {
          if (slur.isFirst(note)) {
            addDoubledSlur = true; addSingleSlur = false;
          } else if (slur.isLastArc(note)) {
            addDoubledSlur = false; addSingleSlur = true;
          } else {
            addDoubledSlur = false; addSingleSlur = false;
          }
          break;
        } else {
          if (!slur.lastNote(note)) {
            addDoubledSlur = false; addSingleSlur = true;
            break;
          }
        }
      }
      if (addDoubledSlur) {
        add(new SlurSign()); add(new SlurSign());
      } else if (addSingleSlur) {
        add(new SlurSign());
      }

      if (allowTieSign && note.isTieStart()) { add(new TieSign()); }
    }

    /** Returns the target note indicated by this interval.
     */
    @Override public Object getScoreObject() { return note; }
  }

  /** Represents an interval.
   */
  public static class IntervalSign extends Sign {
    private final int steps;
    IntervalSign(final int steps) {
      super(INTERVALS[steps]);
      this.steps = steps;
    }

    public String getDescription() {
      return "A " + INTERVAL_NAMES[steps] + " interval sign";
    }

    private static final String[] INTERVALS = new String[] {
      braille(36), braille(34), braille(346), braille(3456), braille(35),
      braille(356), braille(25), braille(36)
    };
    private static final String[] INTERVAL_NAMES = new String[] {
      "unison", "second", "third", "fourth", "fifth", "sixth",
      "seventh", "octave"
    };
  }

  public static class ChordTieSign extends Sign {
    ChordTieSign() { super(braille(46, 14)); }
    public String getDescription() {
      return "Indicates that all notes of a chord are tied to the next chord";
    }
  }
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.