Skip to content

Sequence Editing

Elizabeth Hudnott edited this page Oct 12, 2019 · 10 revisions

Find & Replace

Finding and replacing parameter changes uses the JavaScript iterator protocol.

Find

search = phrase.find(param, minValue, maxValue, changeTypes, begin, from, to, reverse)

Where search is an iterator, param is a parameter number (Synth.Param.xxx), minValue is the smallest value to search for and maxValue is the largest value to find. To find changes that set the parameter to one specific value make minValue and maxValue the same value. To search for all changes with values greater than or equal to some particular value set maxValue to undefined. To search for all changes with values less than or equal to some particular value set minValue to undefined. To search for all changes made to the parameter irrespective of the values it's changed to set both minValue and maxValue to undefined.

changeTypes is a Set of Change Types. You must specify which change types the search should match against. There are some predefined sets for denoting common groups of change types.

Set of Change Types Individual Change Types Contained Within this Set
Synth.ChangeTypes.SET Synth.ChangeType.SET
Synth.ChangeTypes.NONE Synth.ChangeType.NONE
Synth.ChangeTypes.ABSOLUTE Synth.ChangeType.SET, Synth.ChangeType.LINEAR, Synth.ChangeType.EXPONENTIAL
Synth.ChangeTypes.DELTA Synth.ChangeType.DELTA, Synth.ChangeType.DELTA + Synth.ChangeType.LINEAR, Synth.ChangeType.DELTA + Synth.ChangeType.EXPONENTIAL
Synth.ChangeTypes.MULTIPLY Synth.ChangeType.MULTIPLY, Synth.ChangeType.MULTIPLY + Synth.ChangeType.LINEAR, Synth.ChangeType.MULTIPLY + Synth.ChangeType.EXPONENTIAL
Synth.ChangeTypes.ALL Synth.ChangeType.SET, Synth.ChangeType.MARK, Synth.ChangeType.LINEAR, Synth.ChangeType.EXPONENTIAL, Synth.ChangeType.DELTA, Synth.ChangeType.DELTA + Synth.ChangeType.LINEAR, Synth.ChangeType.DELTA + Synth.ChangeType.EXPONENTIAL, Synth.ChangeType.MULTIPLY, Synth.ChangeType.MULTIPLY + Synth.ChangeType.LINEAR, Synth.ChangeType.MULTIPLY + Synth.ChangeType.EXPONENTIAL

The from and to parameters determine which block of rows within the phrase is searched. They can be omitted, in which case the entire phrase is searched. The row number denoted by to can be lower than the row number denoted by from. The search process will wrap around from the end of the phrase back to the beginning as needed. begin is the row number from which to begin searching. begin must refer to a row inside the range of rows denoted by from and to. Normally the current row number will increase as the search proceeds (except for when the search wraps around). Setting reverse to true searches the rows in the opposite order. The reverse parameter is optional.

Once we have our iterator we can iterate over the search results.

let result = search.next();
while (!result.done) {
  const rowNumber = result.value[0];
  const change = result.value[1];

  // Do something with the search result...

  result = search.next(reverse);
}

The directionality of the search can be changed mid-process if needed.

Find All

findAll() works in a similar way to find() except that it returns an array containing every match from anywhere within the phrase that matches the search criteria and you don't have to manage the iterator object yourself because it's all handled internally.

// Results is an array of two element arrays.
results = phrase.findAll(param, minValue, maxValue, changeTypes);

Replace

The first stage of performing a Find & Replace is almost identical to performing a normal Find operation. However, the iterator's next() method takes a two element array as its parameter. The first element is a Boolean that determines whether or not to perform replacement for the previous search result and the second element determines whether or not to traverse in the reversed direction.

search = phrase.replaceValues(param, minValue, maxValue, changeTypes, replacement, begin, from, to, reverse);
let result = search.next();
while (!result.done) {
  let doReplace = false;

  /* Determine if we want to replace the current instance and set doReplace = true; if we do want to perform replacement... */

  result = search.next([doReplace, reverse]);
}

replacement is a single, fixed value that is used to replace all existing values between minValue and maxValue.

Multiple Replacements

Going beyond replaceValues(), it's often useful to be able to search for a range of values and replace different values with a selection of alternative replacements. Various different mappings are supported between the original values and their replacements. Using any of these methods involves following the same essential protocol as I've demonstrated above for replaceValues(), just using a different method name and some different parameters in place of the replacement parameter used with replaceValues().

Method Replacement Pattern
replaceValues() Replaces with a fixed value
transposeValues() Adds or subtracts a fixed value from the original
multiplyValues() Multiplies the original values by a fixed value
quantizeValues() Rounds values
randomizeValues() Adds random values to the original values
mirrorValues() Flips values using their distance from a central value
swapValues() Replaces value1 with value2 and value2 with value1
changeParameter() Alters the parameter change to affect a different parameter entirely

Replace All

A replace all operation is performed by first obtaining one of the same kinds of iterator as is used with the interactive replacement protocol and then passing the iterator to the Sequencer.replaceAll() method to complete all possible replacements without further interaction with the user.

search = phrase.replaceValues(param, minValue, maxValue, changeTypes, replacement, begin, from, to);
Sequencer.replaceAll(search);

Copy and Paste Features

Two types of data can be copied and pasted, "notes" and "commands" (or both). Broadly speaking, "Notes" includes the pitches, durations, velocities, etc. that is all of the parameter changes necessary to convey the essential primary melodic or harmonic information and "commands" includes everything else. The commands convey most of the timbre information, although switching to a different instrument is considered note information for historical reasons.

There is no technical distinction between "notes" and "commands". Both are simply parameter changes. The distinction is only that some parameter names are considered to contribute to the description of the notes and others are not and are instead collectively called "commands". The distinction is partly logical, partly intuitive, partly historical legacy and partly arbitrary.

These parameters are the ones which are considered notes data by default.

Category Parameters
Pitch NOTES, FREQUENCY, CHORD_PATTERN
Triggering GATE, VELOCITY
Timing DURATION
Instrument Selection INSTRUMENT
Phrases PHRASE, PHRASE_OFFSET, PHRASE_TRANSPOSE

According to whatever you feel is appropriate for your application you may reclassify some parameters either to add more note parameters or to demote existing note parameters to command parameters. The object assigned to Sequencer.noteParameters is a JavaScript Set object which can be edited.

Method Functionality
clearAll() Removes all content from a block of rows, leaving empty rows
clearCommands() Removes all commands from a block, leaving the notes only
clearNotes() Removes notes from a block, leaving only commands
setLength() Shortens or lengthens a phrase by removing rows from or adding empty rows to the end of the phrase
insertEmpty() Inserts some new empty rows at a chosen row position
clone() Copies an entire phrase
copy() Copies a block of rows
insertAll() Adds additional rows to the phrase and pastes copied content into them (notes and commands)
insertCommands() Adds additional rows to the phrase and pastes copied content into them (commands only)
insertNotes() Adds additional rows to the phrase and pastes copied content into them (notes only)
insertEmpty() Adds additional rows to the phrase and leaves them empty (no notes or commands)
fill() Copies a single parameter change and pastes it onto every nth row.
mergeAll() Combines copied rows with a block of rows starting from the current cursor position (preserves both sets of changes as much as possible)
Clone this wiki locally