SimpleArrangementEngine

The SimpleArrangementEngine is an ArrangementEngine that generates arrangements based on a list of ActivityVectors (including activity constraints), SequenceEngines and other parameters.

The SimpleArrangementEngine generates a song activity matrix similar to this one and then generates the sequences/tracks from that:


     Section #: 000000000011111111112222222222333333333344444444
                012345678901234567890123456789012345678901234567
=======================================================================
      arpeggio: ------******-------****--------********---------  37,5%
        accomp: -----*************----****-************-----****  68,8%
        melody: ----***-------------------------**-------**-----  14,6%
base_and_snare: ---********----********--********-----********--  66,7%
         hihat: ----**********------*********--******---*****---  62,5%
           pad: *******--*******-*********----***-----*******---  68,8%
          bass: -**********--********-------********-----*****--  64,6%
    randombass: --******--***********---*****------************-  70,8%
=======================================================================
      # active: 123467865675454545456453453453467545435346656421

Vertically between the bars you can see the named ActivityVectors. Horizontally you can see the activity/non-activity of each ActivityVector on a per-chord-section basis (the first lines also contain the chord section numbers, starting with 0). Every "*" depicts an active chord section, every "-" an inactive chord section of the ActivityVector. The numbers on the right indicate the total activity of the ActivityVector in percent (this is based on the actual number of ticks the ActivityVector is active relative to the total number of ticks, not just on the number of chord sections it is active relative to the number of chord sections). The first row(s) contain the chord section numbers from left to right (starting from 0), shown as one or multiple lines (depending on how many digits are needed for the largest used section number). The last row contains the number of ActivityVectors that are simultaneously active during the chord section (0-9 stands for 0-9, a-z for 10-35, A-Z for 36-61).

In the last line you should see the list as specified in the <startActivityCounts> tag at the beginning and the <stopActivityCounts> at the end. In between, the numbers should be between what is configured in <minActivityCount> and <maxActivityCount>, while the absolute difference from one chord section to the next does not exceed what is configured in <maxActivityChangeCount>.

The activity matrix generation can be done using one of two constraint modes:

  • exact - This mode uses a randomized backtracking algorithm for finding a valid activity matrix which fulfills all constraints at the same time. The running time for the algorithm scales super-linearly (probably exponentially) with the number of ActivityVectors, and the likelihood for finding a valid matrix decreases with the strictness of the constraints. This mode can fail, which leads to starting the whole song generation from scratch. The number of iterations before failing can be set, which is the total number of steps while generating the whole song (a number like 1000000 or more works fine in most cases). This is the mode used prior to version 0.6 and it is still the default.
  • greedy - This mode uses a greedy algorithm which builds the activity matrix step-by-step by making the best-looking local choice in every step, without the ability to backtrack. Given a current state, this mode tries out a number of choices and uses the one which leads to the lowest constraint violation score (each constraint violation type is scored and those scores are summed up for every choice made). This mode is much faster than "exact", but it only results in an approximation of the constraints, because violating constraints is allowed (but the algorithm tries to keep the constraint violation score low). The mode is suitable also for very large numbers of ActivityVectors and very long songs. This mode never fails. The number of iterations for every chord section can be set (a number like 1000 works fine in most cases). This mode is available since version 0.6.

For each track, (among other parameters) a SequenceEngine plus its configuration and a list of ActivityVector names are required. The number of provided ActivityVector names must match the number of names that the SequenceEngine requires. The number depends on how the SequenceEngine is configured. The order of the ActivityVector names is relevant. An ActivityVector name can appear any number of times in the list.

If an ActivityVector is defined (with or without constraints), but is not used in any of the tracks, the ActivityVector will silently be ignored for generating the song activity matrix.

By using "activityVectorModification" tags it is possible to apply any number of logical operations on any range of the ActivityVectors of the generated ActivityMatrix. The provided modifications are executed in the order provided in the XML. This gives you the ability to apply some generic changes to the ActivityMatrix which would otherwise not be possible. The 3 basic operations "clear", "set" and "flip" work directly on a given ActivityVector, while the logical operations (e.g. "AND", "OR") work on any two ActivityVectors (the operands) and apply the result to a given target ActivityVector (which can also be one of the two operand ActivityVectors). For example, if your song absolutely requires the melody to be present from chord section 4 to the end of the song and to be inactive before that, you can apply two operations, the first clearing the chord sections 0 to 3 (using the "clear" operation), the second one setting it from 4 to the end (using the "set" operation), like this: <activityVectorModification operator="clear" from="0" to="3" target="melody" /><activityVectorModification operator="set" from="4" to="-1" target="melody" />. Or, you might have two ActivityVectors, one for a closed hihat and one for an open hihat and want to enforce across the whole song that the closed hihat is only active if the open hihat is also active: <activityVectorModification operator="and" operand1="closedhihat" operand2="hihat" from="0" to="-1" target="closedhihat" />. You may also have two different bass lines which you never want active at the same time. Simply use <activityVectorModification operator="andNot" operand1="bass1" operand2="bass2" from="0" to="-1" target="bass1" /> (this makes sure that only bass2 is active if normally both would be active, but otherwise leaving bass1 and bass2 as-is - swap bass1 and bass2 for the opposite result). You should be careful that a set of modifications does not result in 0 ActivityVectors being active at a time, which would lead to silence. Note that all of the operations are applied after ActivityMatrix generation, but before applying any shifts via the "startShift" or "stopShift" tag (see below).

The startShift and stopShift tags can be used to simulate upbeat for a given ActivityVector. For example, let's suppose you have a melody that requires an upbeat of (let's say) 8 ticks. Simply shift the corresponding ActivityVector's start (startShift) and end (stopShift) by -8 ticks. This will enable the ActivityVector 8 ticks earlier than normal and will end it 8 ticks earlier than normal. Note that this will not work for the very first chord section.

Individual tracks can be soloed or muted by using the "solo" and "mute" attributes in the "track" tag. This is useful if you want to enable/disable specific tracks. If any of the tracks is soloed (i.e. if any track has solo set to true), only the soloed tracks are used for generating the song. Otherwise, all tracks which are not muted are used to generate the song. In any case, ActivityVectors which are not used by any track are removed, and the activity matrix is generated without those ActivityVectors. Note that soloing or muting tracks might interfere with ActivityVector constraints, especially in "exact" mode. For example, if you have an ActivityVector which should start after chord section 0 and you solo a track which only uses this ActivityVector, the constraints cannot be fulfilled in "exact" mode.

Configuration

Tag Attribute Type # Example Description
constraintMode - string 0-1 greedy The algorithm to use for fulfilling the constraints. Valid values are "exact" (using backtracking) and "greedy" (using a greedy approximation). Defaults to "exact", which is the mode used before version 0.6. Available since version 0.6.
maxIterations - int 1 200000 The maximum number of iterations to use while trying to fulfill all constraints before failing. For the constraint mode "exact" this is the total number of steps for generating the whole song. For the constraint mode "greedy" this is the number of iterations per chord section.
minActivityCount - int 1 3 The minimum number of ActivityVectors that must be active outside the start/end sections.
maxActivityCount - int 1 8 The maximum number of ActivityVectors that must be active outside the start/end sections. If this is greater than the number of available ActivityVectors, that latter number will be used instead.
maxActivityChangeCount - int 1 2 The maximum number of ActivityVectors that can be added/subtracted from the active number of ActivityVectors for each chord section.
startActivityCounts - list of ints 1 1,2,3,4 The list of ActivityVector counts that should be used at the beginning of the song, one for each chord section.
stopActivityCounts - list of ints 1 4,3,2 The list of ActivityVector counts that should be used at the end of the song, one for each chord section.
activityVector name string 1 accomp The name of the ActivityVector.
activityVector - - 1-n - The ActivityVector definition as defined by the subtags.
activityVector/startShift - int 0-1 -2 Moves the start of each activity segment of the ActivityVector by this number of ticks to the left (if negative) or to the right (if positive).
activityVector/stopShift - int 0-1 -2 Moves the end of each activity segment of the ActivityVector by this number of ticks to the left (if negative) or to the right (if positive).
activityVector/minActive allowInactive boolean 0-1 true Boolean indicating whether the ActivityVector is allowed to be completely silent even though this is less than the minActive percentage. Defaults to false. For example, if the minActive value is set to 30% and allowInactive is true, the activity must be 0% or at least 30%.
activityVector/minActive - int 0-1 30 The minimum activity of the ActivityVector in percent (between 0 and 100).
activityVector/maxActive - int 0-1 80 The maximum activity of the ActivityVector in percent (between 0 and 100).
activityVector/startBeforeSection - int 0-1 2 Constraint that forbids the ActivityVector to be active at or after the given chord section number (counted from 0).
activityVector/startAfterSection - int 0-1 2 Constraint that forbids the ActivityVector to be active before or at the given chord section number (counted from 0).
activityVector/stopBeforeSection - int 0-1 2 Constraint that forbids the ActivityVector to be active at or after the given chord section number (counted from the end, 0 is the last chord section, 1 the second-to-last, etc.).
activityVector/stopAfterSection - int 0-1 2 Constraint that forbids the ActivityVector to be active before or at the given chord section number (counted from the end, 0 is the last chord section, 1 the second-to-last, etc.).
activityVector/minSegmentCount - int 0-1 2 The minimum number of activity segments of the ActivityVector.
activityVector/maxSegmentCount - int 0-1 4 The maximum number of activity segments of the ActivityVector.
activityVector/minSegmentLength - int 0-1 4 The minimum number of chord sections each segment must span. Will be ignored for all ActivityVectors with 0 segments. Available since version 0.2.
activityVector/maxSegmentLength - int 0-1 4 The maximum number of chord sections each segment must span. Will be ignored for all ActivityVectors with 0 segments. Available since version 0.2.
activityVector/minPauseLength - int 0-1 4 The minimum number of chord sections for each pause between two segments. Will be ignored for all ActivityVectors with 0 or 1 segment. Available since version 0.2.
activityVector/maxPauseLength - int 0-1 4 The maximum number of chord sections for each pause between two segments. Will be ignored for all ActivityVectors with 0 or 1 segment. Available since version 0.2.
activityVectorModification - - 0-n - Defines a modification operation of any ActivityVector of the ActivityMatrix after it has been generated. All modification operations are executed in the order provided. Available since version 0.9.
activityVectorModification operator string 1 set Defines the modification operation. Allowed values are "set", "clear" and "flip" (those 3 require target, from and to), as well as "not" (requires operand1, target, from and to), and "and", "andNot", "or" and "xor" (those quire operand1, operand2, target, from and to). Available since version 0.9.
activityVectorModification from string 1 20% Defines the start point of the modification, either as a chord section number (counted from 0, or negative for counting from the end) or as a percentage value of the song's ticks if it ends with a "%" sign (if within a chord section, ticks are rounded down to the chord section start). Available since version 0.9.
activityVectorModification to string 1 60% Defines the end point of the modification, either as a chord section number (counted from 0, or negative for counting from the end) or as a percentage value of the song's ticks if it ends with a "%" sign (if within a chord section, ticks are rounded up to the next chord section start). If to is smaller than from, to and from are swapped. Available since version 0.9.
activityVectorModification operand1 string 0/1 base Defines the name of the ActivityVector of the first operand. Whether the first operand is required depends on the operator used. Available since version 0.9.
activityVectorModification operand2 string 0/1 snare Defines the name of the ActivityVector of the second operand. Whether the second operand is required depends on the operator used. Available since version 0.9.
activityVectorModification target string 1 melody Defines the name of the ActivityVector the operation should be applied on. Available since version 0.9.
track solo boolean 0/1 true Sets solo mode. If any track is soloed, only soloed tracks are considered for generating the song. Defaults to false. Available since version 0.8.
track mute boolean 0/1 true Sets mute mode. Muted tracks are excluded from consideration when the song is generated, unless at least one track is soloed. Defaults to false. Available since version 0.8.
track - - 1-n - The track definition as defined by the subtags.
track/instrument - string 1 percussion The name of the instrument. This name can be referenced by the Player.
track/transposition - int 0-1 12 The number of halftones that the track should be transposed (positive numbers increase the pitch, negative numbers decrease the pitch).
track/velocity - int 0-1 500 If provided, the velocity of all notes is scaled by the given velocity divided by the maximum song velocity (e.g., if the maximum velocity is 1000 and you specify 500, the velocity is halved). Defaults to the maximum song velocity, i.e. no scaling. Available since version 0.8.
track/sequenceEngine class class 1-n MelodySequenceEngine The name of the SequenceEngine implementation to use. Starting with version 0.6, you can specify more than one SequenceEngine (previous to version 0.6, only one could be provided). One of the provided SequenceEngines will be chosen at random for the whole song.
track/sequenceEngine - - 1 - The configuration of the SequenceEngine implementation.
track/activityVector - string 0-n accomp The name of the ActivityVector to use. The number of required ActivityVector names depends on the chosen SequenceEngine and its configuration.

Configuration example


  <arrangementEngine class="SimpleArrangementEngine">
    <maxIterations>200000</maxIterations>
    <minActivityCount>3</minActivityCount>
    <maxActivityCount>8</maxActivityCount>
    <maxActivityChangeCount>2</maxActivityChangeCount>
    <startActivityCounts><random list="1,2,3,4|1,2,3,4,5"/></startActivityCounts>
    <stopActivityCounts><random list="2,1|3,2|4,3,2"/></stopActivityCounts>
    <activityVector name="arpeggio"/>
    <activityVector name="accomp">
      <stopShift>-2</stopShift>
    </activityVector>
    <activityVector name="melody">
      <startAfterSection>0</startAfterSection>
      <stopBeforeSection>0</stopBeforeSection>
      <stopShift>-3</stopShift>
    </activityVector>
    <track>
      <instrument>arpeggio</instrument>
      <transposition>-12</transposition>
      <sequenceEngine class="MultiPatternSequenceEngine">
            <obeyChordSubtype>true</obeyChordSubtype>
                <patternEngines>
                  <patternEngine class="StringPatternEngine">
                    <string>-/6,4/2</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>-/4,3/4</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>-/2,2/6</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>0/8</string>
                  </patternEngine>
                </patternEngines>
                <patternEngines>
                  <patternEngine class="StringPatternEngine">
                    <string>2/8</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>-/2,0/6</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>-/4,1/4</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>-/6,0/2</string>
                  </patternEngine>
                </patternEngines>
                <patternEngines>
                  <patternEngine class="StringPatternEngine">
                    <string>3/8</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>-/2,1/6</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>-/4,2/4</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                    <string>-/6,0/2</string>
                  </patternEngine>
                </patternEngines>
      </sequenceEngine>
      <activityVector>arpeggio</activityVector>
    </track>
    <track>
      <instrument>accomp</instrument>
      <transposition>-24</transposition>
      <sequenceEngine class="MultiPatternSequenceEngine">
        <patternEngines>
                  <patternEngine class="StringPatternEngine">
                  <string>-,-,-,-,5,-,-,-,-,-,-,-,5,-,-,-</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                  <string>-,-,-,-,4,-,-,-,-,-,-,-,4,-,-,-</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                  <string>-,-,-,-,3,-,-,-,-,-,-,-,3,-,-,-</string>
                  </patternEngine>
                  <patternEngine class="StringPatternEngine">
                  <string>0,-,-,0,-,-,0,-,-,-,0,-,-,-,-,-,0,-,-,0,-,-,0,-,-,-,0,-,-,-,-,-,0,-,-,0,-,-,0,-,-,-,0,-,-,-,-,-,0,-,-,0,-,-,0,-,-,-,0,-,-,-,+,-,0,-,-,0,-,-,0,-,-,-,0,-,-,-,-,-,0,-,-,0,-,-,0,-,-,-,0,-,-,-,-,-,0,-,-,0,-,-,0,-,-,-,0,-,-,-,-,-,0,-,-,0,-,-,0,-,-,-,0,-,-,-,-1,+</string>
                  </patternEngine>
                </patternEngines>
      </sequenceEngine>
      <activityVector>accomp</activityVector>
    </track>
    <track>
      <instrument>melody</instrument>
      <transposition>12</transposition>
      <sequenceEngine class="MelodySequenceEngine">
        <patternEngine class="RandomPatternEngine">
          <patternTicks>16</patternTicks>
          <patternString><random list="A1,A2,A1,A3,A1,A2,A1,B1"/></patternString>
          <noteProbability>75</noteProbability>
          <legatoProbability>0</legatoProbability>
          <minVelocity>32767</minVelocity>
          <maxVelocity>32767</maxVelocity>
          <minActiveTicks>7</minActiveTicks>
          <maxActiveTicks>13</maxActiveTicks>
          <offsets>0,0,0,0,0,0,+,+</offsets>
          <noteLengths>2,2,2,3,2,2,2,1,2</noteLengths>
          <pauseLengths>2,2,2,2,1,2</pauseLengths>
          <pitchVelocityCorrelation>100</pitchVelocityCorrelation>
          <velocityExponent>3</velocityExponent>
        </patternEngine>
          </sequenceEngine>
      <activityVector>melody</activityVector>
    </track>
  </arrangementEngine>

Add new comment