/* * JFugue, an Application Programming Interface (API) for Music Programming * http://www.jfugue.org * * Copyright (C) 2003-2014 David Koelle * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jfugue.mitools; import java.util.Arrays; import java.util.List; import org.jfugue.pattern.Pattern; /** * Lets you... * * * @author David Koelle * */ public class Recombinator { private List<Object> things0AsList; private Object[] things0AsArray; private Object[] things0WorkingArray; private List<Object> things1AsList; private Object[] things1AsArray; private Object[] things1WorkingArray; public Recombinator() { } public Recombinator(List<Object> things0, List<Object> things1) { things0AsList = things0; things1AsList = things1; } public Recombinator(List<Object> things0, Object[] things1) { things0AsList = things0; things1AsArray = things1; } public Recombinator(Object[] things0, List<Object> things1) { things0AsArray = things0; things1AsList = things1; } public Recombinator(Object[] things0, Object[] things1) { things0AsArray = things0; things1AsArray = things1; } public Recombinator put(int index, List<Object> things) { switch (index) { case 0 : things0AsList = things; things0AsArray = null; break; case 1 : things1AsList = things; things1AsArray = null; break; default : throw new IllegalArgumentException("Index to Recombinator must be either 0 or 1; provided value is "+index); } return this; } public Recombinator put(int index, Object[] things) { switch (index) { case 0 : things0AsList = null; things0AsArray = things; break; case 1 : things1AsList = null; things1AsArray = things; break; default : throw new IllegalArgumentException("Index to Recombinator must be either 0 or 1; provided value is "+index); } return this; } public Pattern recombine(String instructions, LoopBehavior option) { createWorkingArrays(); switch (option) { case LOOP_BOTH: return loopBoth(instructions); case LOOP_0_FIRST: return loop0(instructions); case LOOP_1_FIRST: return loop1(instructions); default : return null; } } /** * Given $0 = { A, B } and $1 = { C, D }, loopBoth("$0v$1") gives { AvC, BvD } * If one array is longer than the other, the shorter array is repeated. * * @param instructions * @return */ private Pattern loopBoth(String instructions) { Pattern pattern = new Pattern(); for (int i=0; i < Math.max(things0WorkingArray.length, things1WorkingArray.length); i++) { String patternPiece = instructions.replaceAll("\\$0", things0WorkingArray[i % things0WorkingArray.length].toString()); pattern.add(patternPiece.replaceAll("\\$1", things1WorkingArray[i % things1WorkingArray.length].toString())); } return pattern; } /** * Given $0 = { A, B } and $1 = { C, D }, loop1("$0v$1") gives { AvC, AvD, BvC, BvD } * * @param instructions * @return */ private Pattern loop1(String instructions) { Pattern pattern = new Pattern(); for (Object obj0 : things0WorkingArray) { String patternPiece = instructions.replaceAll("\\$0", obj0.toString()); for (Object obj1 : things1WorkingArray) { pattern.add(patternPiece.replaceAll("\\$1", obj1.toString())); } } return pattern; } /** * Given $0 = { A, B } and $1 = { C, D }, loop1("$0v$1") gives { AvC, BvC, AvD, BvD } * * @param instructions * @return */ private Pattern loop0(String instructions) { Pattern pattern = new Pattern(); for (Object obj1 : things1WorkingArray) { String patternPiece = instructions.replaceAll("\\$1", obj1.toString()); for (Object obj0 : things0WorkingArray) { pattern.add(patternPiece.replaceAll("\\$0", obj0.toString())); } } return pattern; } private void createWorkingArrays() { if (things0AsArray != null) { things0WorkingArray = Arrays.copyOf(things0AsArray, things0AsArray.length); } else if (things0AsList != null) { things0AsList.toArray(things0WorkingArray); } else { throw new RuntimeException("Recombinator cannot recombine; there is no set of objects for $0"); } if (things1AsArray != null) { things1WorkingArray = Arrays.copyOf(things1AsArray, things1AsArray.length); } else if (things1AsList != null) { things1AsList.toArray(things1WorkingArray); } else { throw new RuntimeException("Recombinator cannot recombine; there is no set of objects for $1"); } } public enum LoopBehavior { LOOP_0_FIRST, LOOP_1_FIRST, LOOP_BOTH; } }