示例#1
0
  /**
   * Look ahead at the next measure, build and determine a suitable SongPhrase to handle it.
   *
   * @param itM an iterator over the measures collection. It must be pointing so that itM.next()
   *     returns the current measure, which will be marked as a repeatStart.
   * @param itMTP an iterator over the measure-track pairs collection. It must be pointing so that
   *     itMTP.next() returns the first track of the current measure
   * @param tracks The tracks definitions
   * @return the next SongPhrase
   */
  private static SongPhrase phraseFactory(
      Song song,
      ListIterator<GPMeasure> itM,
      ListIterator<GPMeasureTrackPair> itMTP,
      List<GPTrack> tracks)
      throws GPFormatException {
    SongPhrase sp = null;

    GPMeasure measure = itM.next(); // peek inside the measure
    // and dispatch to the right
    // factory
    itM.previous(); // rewind before calling the right factory method

    // TODO add getter and setter for GP4Measure.repeatStart
    logger.finer("Measure " + measure.getNumber() + " repeat start " + measure.repeatStart);
    logger.finer(
        "Measure " + measure.getNumber() + " repeat count " + measure.getNumberOfRepetitions());

    // if it's the start of a repeat, then make a repeated phrase
    if (measure.repeatStart) {
      logger.fine("Creating a repeated phrase at " + measure.getNumber());
      sp = makeRepeatedSongPhrase(song, itM, itMTP, tracks);
    }

    // Failing everything else, just return a single measure
    if (sp == null) {
      logger.fine("Creating a measure phrase at " + measure.getNumber());
      sp = makeSongMeasure(song, itM, itMTP, tracks);
    }
    return sp;
  }
示例#2
0
  /**
   * Create and return a regular SongMeasure from the current position of the iterators.
   *
   * @param itM an iterator over the measures collection. It must be pointing so that itM.next()
   *     returns the current measure, which will be marked as a repeatStart.
   * @param itMTP an iterator over the measure-track pairs collection. It must be pointing so that
   *     itMTP.next() returns the first track of the current measure
   * @param tracks The tracks definitions
   * @return a new filled-out SongMeasure
   * @throws GP4AdaptorException
   */
  private static RepeatedSongPhrase makeRepeatedSongPhrase(
      Song song,
      ListIterator<GPMeasure> itM,
      ListIterator<GPMeasureTrackPair> itMTP,
      List<GPTrack> tracks)
      throws GPFormatException {
    SongPhraseList spl = new SongPhraseListImpl();

    // read the first measure without testing for the repeat marker again.
    spl.addPhrase(makeSongMeasure(song, itM, itMTP, tracks));

    // look back at the last measure processed to see if we've done
    GPMeasure measure = itM.previous();
    itM.next();
    int repeatCount = measure.getNumberOfRepetitions();

    // keep calling the phrase factory until you find a measure
    // that's marked with a repeat count. If you run out of measures
    // (Corneille)
    // then assume the last measure has a repeat count of 1.
    while (repeatCount == 0) {
      if (!itM.hasNext()) {
        logger.fine("Got to end of score before finding a closing repeat mark, assuming 1");
        repeatCount = 1;
        break;
      }
      SongPhrase phrase = phraseFactory(song, itM, itMTP, tracks);
      spl.addPhrase(phrase);
      measure = itM.previous();
      itM.next();
      repeatCount = measure.getNumberOfRepetitions();
      logger.fine("Repeat count measure at " + measure.getNumber() + " is " + repeatCount);
    }

    return new RepeatedSongPhraseImpl(spl, repeatCount);
  }
示例#3
0
  /**
   * Create and return a regular SongMeasure from the current position of the iterators.
   *
   * @param itM an iterator over the measures collection. It must be pointing so that itM.next()
   *     returns the current measure
   * @param itMTP an iterator over the measure-track pairs collection. It must be pointing so that
   *     itMTP.next() returns the first track of the current measure
   * @param tracks The tracks definitions
   * @return a new filled-out SongMeasure
   * @throws GP4AdaptorException
   */
  private static SongMeasure makeSongMeasure(
      Song song,
      ListIterator<GPMeasure> itM,
      ListIterator<GPMeasureTrackPair> itMTP,
      List<GPTrack> tracks) {
    GPMeasure measure = itM.next();

    int ending = measure.getNumberOfAlternateEnding();
    if (ending > 0) {
      logger.warning("Measure " + measure.getNumber() + " is alternate ending " + ending);
    }

    // TODO getNumber
    // TODO getNumberOfAlternateEnding
    // TODO getNumberOfRepetitions
    // TODO getTonality
    int numerator = measure.getNumerator();
    int denominator = measure.getDenominator();

    int measureLength = PPQ_HIGH_RESOLUTION * 4 * numerator / denominator;
    // OLD MGG logger.finer("Measure "+measure.getNumber()+",
    // "+numerator+"/"+denominator+", length " + measureLength);
    TimeSignature ts = new TimeSignature(numerator, denominator);
    SongMeasure sm = new SongMeasureImpl(measure.getNumber(), measureLength / PPQ_SCALE_FACTOR, ts);

    for (int trackIndex = 1; trackIndex <= tracks.size(); trackIndex++) {
      GPTrack track = tracks.get(trackIndex - 1);
      // TODO is12StringedGuitarTrack
      // TODO isBanjoTrack
      // TODO getter/setter for isDrumsTrack

      // TODO getChannelEffects
      // TODO getColor
      // TODO getName
      // TODO getNumberOfFrets
      // TODO getPort
      int capo = track.getCapo();
      int strings = track.getNumberOfStrings();
      int stringTuning[] = new int[strings];
      for (int i = 0; i < strings; i++) stringTuning[i] = track.getStringsTuning(i);

      // OLD  MGG logger.finer("Measure " + measure.getNumber() + " Track "+
      // trackIndex);
      GPMeasureTrackPair mtp = itMTP.next();
      SongMeasureTrack smt = new SongMeasureTrackImpl(song.getTrack(trackIndex));
      sm.addTrack(smt);

      List<GPBeat> beats = mtp.getBeats();
      int beatOffset = 0;
      for (Iterator<GPBeat> itBeat = beats.iterator(); itBeat.hasNext(); ) {
        GPBeat beat = itBeat.next();

        // TODO effects

        GPDuration duration = beat.getDuration();
        // TODO add getter and setter for GP4Beat.dottedNotes
        boolean dotted = beat.dottedNotes;
        int ntuplet = beat.getNTuplet();

        int beatDuration = calculateDuration(duration, dotted, ntuplet);

        if (beat.isNoteBeat()) {
          List<GPNote> notes = beat.getNotes();
          List<Integer> stringsPlayed = new LinkedList<Integer>();
          // TODO suggest an easier way of returning the played
          // string list
          for (int i = 6; i >= 0; i--) {
            if (beat.isStringPlayed(i)) {
              stringsPlayed.add(new Integer(i));
            }
          }

          Iterator<GPNote> itNotes = notes.iterator();
          Iterator<Integer> itStrings = stringsPlayed.iterator();

          while (itNotes.hasNext()) {

            //						OLD MGG Integer stringObject = (Integer) itStrings.next();
            // see TODO.TXT or NEWFEATURES.TXT
            //						this lines were added to fix the GTP playing error - BEGIN
            Integer stringObject;

            if (!itStrings.hasNext()) {
              // this error appears to happen when its *.GTP file
              // TODO show a friendly error
              break;
            }
            /*ELSE*/
            //						END

            stringObject = itStrings.next();
            // Note that the tuning array has the highest string
            // at index 0
            // but the track has the highest string at index 6.

            // TODO find out if this is correct. What about a
            // 4-string bass?
            int stringID = 6 - stringObject.intValue();

            GPNote note = itNotes.next();
            int noteDuration = beatDuration;

            // see if this note has time independent settings on
            // it
            // TODO getter/setter for GP4Note.duration
            GPDuration tiDuration = note.duration;
            if (tiDuration != null) {
              // TODO getter/setter for GP4Note.isDotted
              boolean tiDotted = note.isDotted;
              int tiTriplet = note.getNTuplet();
              noteDuration = calculateDuration(tiDuration, tiDotted, tiTriplet);
            }

            // TODO isDeadNote
            // TODO isGhostNote
            // TODO isTieNote
            // TODO effects

            // TODO Note effects are a little bit difficult.
            // Remember these are guitar effects
            // so we effectively need a 'virtual track' for
            // every string, so when we playback we
            // can assign a unique MIDI channel to that track
            // and so we can apply a channel-wide
            // controller to that effect (such as pitch bend).
            // Even the simple effect (let ring)
            // can't be done easily right now because we can't
            // tell when to really kill the note.
            // Of course if we don't need an effect, we should
            // try to use as few MIDI channels as
            // we can!

            int virtualTrackID = stringID;
            SongVirtualTrack svt = smt.getVirtualTrack(virtualTrackID);
            int noteStart = beatOffset / PPQ_SCALE_FACTOR;
            int noteEnd = (beatOffset + noteDuration) / PPQ_SCALE_FACTOR;

            // FIXME cover the tie note case by grabbing the
            // last fret
            if (note.isTieNote()) {
              svt.addEvent(new SongEventImpl(noteStart, new SongTieMessage(noteEnd - noteStart)));
            } else {
              int baseFret = note.getFretNumber(); // OLD
              // .getNumberOfFret();
              int fret = baseFret + capo;
              GPDynamic dynamic = note.getDynamic();
              int velocity = DynamicsMap.velocityOf(dynamic);
              int pitch = stringTuning[stringID] + fret;
              svt.addEvent(
                  new SongEventImpl(
                      noteStart,
                      new SongNoteOnMessage(pitch, velocity, noteEnd - noteStart, baseFret)));
            }
          }
        }
        beatOffset += beatDuration;
      }
      if (beatOffset != measureLength) {
        // an underfull one isn't fatal, but an overfull one is
        String reason =
            "Measure: "
                + measure.getNumber()
                + " track: "
                + trackIndex
                + " length mismatch, expected "
                + measureLength
                + ", got "
                + beatOffset;

        if (beatOffset > measureLength) {
          logger.fine(reason);
          System.err.println(reason);
        } else {
          logger.fine(reason);
        }
      }
    }
    return sm;
  }