public static void main(String[] args) {

    int number_of_voices = voice_array.length;
    Random my_roll = new Random();

    Pattern[] rhythm_patterns = james.generate(piece_length, number_of_voices);
    for (int i = 0; i < number_of_voices; i++) {
      MelodicVoice this_voice = new MelodicVoice();
      this_voice.setRange(voice_array[i]);
      AccentListener my_accent_listener = new AccentListener();
      this_voice.setNoteArray(my_accent_listener.listen(rhythm_patterns[i]));
      System.out.println("adding voice " + i + " to unbuiltvoices");
      unbuilt_voices.add(this_voice);
    }
    int ub_size = unbuilt_voices.size();
    for (int i = 0; i < number_of_voices; i++) {
      // int voice_index = my_roll.nextInt(unbuilt_voices.size());
      int voice_index = i;
      System.out.println(" about to build voice pitches for " + voice_index);
      MelodicVoice nextVoice =
          buildVoicePitches(unbuilt_voices.get(voice_index), number_of_voices, my_mode_module);
      ArrayList<MelodicNote> verify_array = nextVoice.getNoteArray();
      System.out.println("Return Me: ");
      for (MelodicNote verify : verify_array) {
        if (verify.getRest()) System.out.println("rest " + verify.getDuration() + "  ");
        else System.out.println(verify.getPitch() + " " + verify.getDuration() + "   ");
      }
      if (i == 0) {
        harmonic_prog = nextVoice;
        harmonic_prog_built = true;
      } else built_voices.add(nextVoice);
      // unbuilt_voices.remove(voice_index);
    }
    unbuilt_voices.clear();
    Pattern music_output = new Pattern();
    music_output.addElement(new Tempo(tempo_bpm));

    for (byte i = 0; i < built_voices.size(); i++) {
      // create a jfugue musicstring from the built voice
      MelodicVoice final_voice = built_voices.get(i);
      ArrayList<MelodicNote> final_note_array = final_voice.getNoteArray();
      Voice jf_voice = new Voice(i);
      music_output.addElement(jf_voice);
      for (MelodicNote final_note : final_note_array) {
        int jf_int = 0;
        Note jf_note = new Note();
        jf_note.setDecimalDuration(final_note.getDuration());
        if (final_note.getPitch() != null && final_note.getRest() == false) {
          jf_int = final_note.getPitch();
          byte jf_note_byte = (byte) jf_int;
          jf_note.setValue(jf_note_byte);
          if (!final_note.getAccent()) jf_note.setAttackVelocity((byte) 40);
        } else {
          // System.out.println("setting jf note to rest");
          jf_note.setRest(true);
          jf_note.setAttackVelocity((byte) 0);
          jf_note.setDecayVelocity((byte) 0);
        }

        music_output.addElement(jf_note);
      } // add the musicstring to a pattern
    }

    // save and play the pattern
    System.out.println(music_output.getMusicString());
    Player my_player = new Player();
    my_player.play(music_output);
    Date today = new Date(System.currentTimeMillis());
    // Date format: "yyyy-MM-dd_HH:mm:ss"
    SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd-yyyy-HH-mm");
    String dateString = DATE_FORMAT.format(today);
    try {
      my_player.saveMidi(
          music_output,
          new File(
              "C:\\Documents and Settings\\alyssa\\Desktop\\Species Midi\\species-"
                  + tempo_bpm
                  + "-"
                  + dateString
                  + ".mid"));
    } catch (IOException ex) {
    }
  }
  public static MelodicVoice buildVoicePitches(
      MelodicVoice alter_me, int number_of_voices, ModeModule my_mode_module) {
    MelodicVoice return_me = new MelodicVoice();

    int previous_cp_pitch = -13;
    int previous_melodic_interval = 0;
    trough = 200;
    trough_count = 0;
    peak = 0;
    peak_count = 0;
    same_consonant_count = 0;
    int voice_pitch_count = 0;
    LinkedList<MelodicNote> chord_prog_stack = new LinkedList<>();

    System.out.println(
        "voiceRange min " + alter_me.getRangeMin() + "   voicerange max " + alter_me.getRangeMax());
    Integer pitch_center =
        my_mode_module.getPitchCenter(alter_me.getRangeMin(), alter_me.getRangeMax());
    System.out.println("pitchcenter = " + pitch_center);

    if (harmonic_prog_built) {
      ArrayList<MelodicNote> chord_prog_temp = harmonic_prog.getNoteArray();
      for (MelodicNote b_voice_note : chord_prog_temp) {
        chord_prog_stack.add(b_voice_note);
      }
    }

    if (!built_voices.isEmpty())
      for (MelodicVoice built_voice : built_voices) {
        LinkedList<MelodicNote> cf_stack = new LinkedList<>();
        ArrayList<MelodicNote> temp = built_voice.getNoteArray();
        for (MelodicNote b_voice_note : temp) {
          cf_stack.add(b_voice_note);
        }
        built_voice_queues.add(cf_stack);
        System.out.println("created stack of melodic notes for each previously built voice ");
      }
    else {

      System.out.println("built voices Empty - start first melody");
    }

    ArrayList<MelodicNote> current_cf = new ArrayList();
    MelodicNote[] holdover_cf = new MelodicNote[built_voice_queues.size()];
    Integer[] previous_cf_pitch = new Integer[built_voice_queues.size()];
    for (int h = 0; h < built_voice_queues.size(); h++) previous_cf_pitch[h] = 1111;
    ArrayList<MelodicNote> pending_rests = new ArrayList();
    Integer current_cp_index = -13;
    ArrayList<Integer> pitch_candidate_values = new ArrayList();
    ArrayList<PitchCandidate> pitch_candidates = new ArrayList();

    MelodicNote this_cf = null;
    Integer melodic_prev_cp = 0;

    for (int i = 0; i < alter_me.getVoiceLength(); i++) { // for each melodic note in the CP voice
      System.out.println("assigning pitch to note " + i + " of " + alter_me.getVoiceLength());

      MelodicNote CP_note = alter_me.getMelodicNote(i);
      if (!CP_note.getRest()) {
        if (current_cp_index >= 0) {
          if (previous_cp_pitch == 9999) previous_cp_pitch = melodic_prev_cp;
          System.out.println(
              "starting melody check on current cp"
                  + current_cp_index
                  + " of "
                  + alter_me.getVoiceLength());
          Boolean got_accent = alter_me.getMelodicNote(current_cp_index).getAccent();
          System.out.println("the current cp note's accent value is " + got_accent);

          // MELODICALLY EVALUATE Pitch Candiates for Previous Note - Choose CP WinnerS - Previous
          // CP = CP Winner
          pitch_candidates =
              melodicCheck(
                  pitch_candidates,
                  my_mode_module,
                  alter_me,
                  pitch_center,
                  voice_pitch_count,
                  previous_cp_pitch,
                  previous_melodic_interval,
                  got_accent);
          Integer cp_winner = pickWinner(pitch_candidates);
          // re-assign variables and move on to next CP note
          pitch_candidates.clear();
          System.out.println("CP winner" + cp_winner + " to note " + current_cp_index);
          MelodicNote current_cp = alter_me.getMelodicNote(current_cp_index);
          current_cp.setPitch(cp_winner);
          return_me.addMelodicNote(current_cp);
          if (!pending_rests.isEmpty())
            for (MelodicNote my_rest : pending_rests) {
              return_me.addMelodicNote(my_rest);
            }
          pending_rests.clear();
          // Calculating Peaks and Troughs and note counts and save variables
          if (previous_cp_pitch != -13) {
            if (voice_pitch_count > 1) {
              if (previous_melodic_interval < 0
                  && cp_winner - previous_cp_pitch
                      > 0) { // will there be a change in direction from - to +  ie trough?
                if (previous_cp_pitch == trough) {
                  trough_count++;

                } else if (previous_cp_pitch != trough) {

                  trough = previous_cp_pitch;
                  trough_count = 1;
                  System.out.println("setting new trough = " + previous_cp_pitch);
                }
              }

              if (previous_melodic_interval > 0
                  && cp_winner - previous_cp_pitch
                      < 0) { // will there be a change in direction from - to +  ie trough?
                if (previous_cp_pitch == peak) peak_count++;
                else {
                  if (previous_cp_pitch > peak) {
                    peak = previous_cp_pitch;
                    peak_count = 1;
                    System.out.println("setting new peak = " + previous_cp_pitch);
                  }
                }
              }
            }

            previous_melodic_interval = cp_winner - previous_cp_pitch;
            System.out.println("previous melodic interval = " + previous_melodic_interval);

            boolean add_pitch = true;
            for (int pc = 0; pc < pitch_counts.size(); pc++) {
              if (pitch_counts.get(pc).getPitch() == previous_cp_pitch % 12) {
                pitch_counts.get(pc).incrementCount();
                add_pitch = false;
              }
            }
            if (add_pitch == true) {
              PitchCount my_pitch_count = new PitchCount(previous_cp_pitch % 12);
              pitch_counts.add(my_pitch_count);
            }

            boolean add_motn = true;
            for (int mc = 0; mc < motion_counts.size(); mc++) {
              if (motion_counts.get(mc).getPreviousPitch() == previous_cp_pitch % 12
                  && motion_counts.get(mc).getSucceedingPitch() == cp_winner % 12) {
                motion_counts.get(mc).incrementCount();
                add_motn = false;
              }
            }
            if (add_motn == true) {
              MotionCount my_motionCount = new MotionCount(previous_cp_pitch % 12, cp_winner % 12);
              motion_counts.add(my_motionCount);
            }
          }

          previous_cp_pitch = cp_winner;
          melodic_prev_cp = cp_winner;
          voice_pitch_count++;
        }

        // get pitch_candidate pitches for this note from mode_module

        if (harmonic_prog_built) {
          do {

            MelodicNote prog_stack_note = (MelodicNote) chord_prog_stack.pop();
            if (prog_stack_note.getPitch() != 0) this_key.setPitch(prog_stack_note.getPitch());
            this_key.setTotalVoiceDuration(prog_stack_note.getPreviousDuration());
            System.out.println("this key = " + this_key.getPitch());
            System.out.println("this key prevduration = " + this_key.getPreviousDuration());
            if (this_key.getPreviousDuration() >= CP_note.getStartTime()) {
              key_transpose = this_key.getPitch() % 12;
            }
          } while (this_key.getPreviousDuration() < CP_note.getPreviousDuration());
        }

        if (voice_pitch_count == 0) { // If there is no previous pitch ie this is the first note
          pitch_candidate_values =
              my_mode_module.getFirstNotePitchCandidates(
                  alter_me.getRangeMin(), alter_me.getRangeMax(), key_transpose);
          System.out.println("using first note pitch candidates");
        } else {
          System.out.println("getting pitch candidates from my modemodule");
          pitch_candidate_values =
              my_mode_module.getPitchCandidates(previous_cp_pitch, key_transpose);
          if (pitch_candidate_values.isEmpty()) System.out.println("EMPTY ARRAY!!!!");
        }
        System.out.println("voice_pitch_count" + voice_pitch_count);
        System.out.print("pitch candidates: ");

        // build pitch_candidate object array with info from rhythm patterns and mode module
        for (Integer pitch_candidate_value : pitch_candidate_values) {
          System.out.print(pitch_candidate_value + " ");
          PitchCandidate myPC = new PitchCandidate();
          myPC.setPitch(pitch_candidate_value);
          pitch_candidates.add(myPC);
        }
        System.out.println();

        // Reset Current CP index
        current_cp_index = i;
      }
      // If note is a Rest  add it to the voice
      else {
        System.out.println(" is rest ");
        if (current_cp_index == -13) {
          return_me.addMelodicNote(CP_note);
          System.out.println("adding rest to beginning of voice");
          continue;
        } else {
          pending_rests.add(CP_note);
          System.out.println("adding rest to pending rest array");
        }
      }
      /*
      Regardless if note or rest run HARMONIC CHECKS on the current cp
      If a rest, then we are still deciding the counterpoint for the
      immediately previous place in the melody.

      If this is the very first voice, then there are no prebuilt voices
      so skip this section
      */
      if (!built_voice_queues.isEmpty()) {
        for (int b = 0; b < built_voice_queues.size(); b++) {
          do {
            boolean CF_root = false;
            if (b == 0) CF_root = true;
            boolean skip_me = false;
            if (!built_voice_queues.get(b).isEmpty()) {
              if (holdover_cf[b] != null) this_cf = holdover_cf[b];
              else
                this_cf =
                    (MelodicNote) built_voice_queues.get(b).pop(); // pop from builtvoicequeues[b];
              System.out.println(" pitch = " + this_cf.getPitch());
              System.out.println(" rest = " + this_cf.getRest());
              System.out.println(" duration up to  = " + this_cf.getPreviousDuration());
            } else {
              System.out.println("cf voice is empty");
              break;
            }
            if (this_cf.getRest()) {
              if (this_cf.getDuration() > .5 || previous_cf_pitch[b] == -1 || CP_note.getRest())
                skip_me = true;
            }

            if (!skip_me) {
              // HARMONICALLY EVALUATE cp candidates against this_cf
              if (previous_cf_pitch[b] != 1111)
                pitch_candidates =
                    harmonicChecks(
                        pitch_candidates,
                        this_cf,
                        CF_root,
                        previous_cf_pitch[b],
                        previous_cp_pitch,
                        CP_note,
                        voice_pitch_count,
                        b);
              else
                pitch_candidates =
                    harmonicChecksSuperBasic(
                        pitch_candidates,
                        this_cf,
                        CF_root,
                        alter_me.getMelodicNote(current_cp_index));
              previous_cp_pitch =
                  9999; // 9999 is assigned in case CP might hold over into next CF note
            } // in which case the while loop repeats. When you break out
            // of while loop previous_cp_pitch will be checked and re-assigned above
            else {
              System.out.println("current cf index" + b + "is null");
              break;
            }
            if (this_cf.getPreviousDuration() > CP_note.getPreviousDuration())
              holdover_cf[b] = this_cf;
            else holdover_cf[b] = null;

            if (!skip_me) previous_cf_pitch[b] = this_cf.getPitch();
          } while (this_cf.getPreviousDuration() < CP_note.getPreviousDuration());
        }
      }
      /*
      If this is the last melodic placeholder, run some closing procedures

      */
      if (i == alter_me.getVoiceLength() - 1) {
        // MELODICALLY EVALUATE Current CP
        System.out.println("Last note of voice");
        Boolean last_accent = true;
        if (!CP_note.getRest()) {
          pitch_candidates =
              melodicCheck(
                  pitch_candidates,
                  my_mode_module,
                  alter_me,
                  pitch_center,
                  voice_pitch_count,
                  previous_cp_pitch,
                  previous_melodic_interval,
                  last_accent);
          Integer cp_winner = pickWinner(pitch_candidates);
          System.out.println("CP winner" + cp_winner);
          pitch_candidates.clear();
          CP_note.setPitch(cp_winner);
          return_me.addMelodicNote(CP_note);
        } else {
          Boolean got_accent = alter_me.getMelodicNote(current_cp_index).getAccent();
          System.out.println("this note's accent value is " + got_accent);
          // MELODICALLY EVALUATE Current CP - Choose CP WinnerS - Previous CP = CP Winner
          pitch_candidates =
              melodicCheck(
                  pitch_candidates,
                  my_mode_module,
                  alter_me,
                  pitch_center,
                  voice_pitch_count,
                  previous_cp_pitch,
                  previous_melodic_interval,
                  got_accent);
          Integer cp_winner = pickWinner(pitch_candidates);
          pitch_candidates.clear();
          System.out.println("CP winner" + cp_winner + " to note " + current_cp_index);
          MelodicNote current_cp = alter_me.getMelodicNote(current_cp_index);
          current_cp.setPitch(cp_winner);
          return_me.addMelodicNote(current_cp);
          if (!pending_rests.isEmpty())
            for (MelodicNote my_rest : pending_rests) {
              return_me.addMelodicNote(my_rest);
            }
          pending_rests.clear();
        }
      }
    } // loop through next CP note

    return return_me;
  } // end method