The following lists the terminology used in the SoundHelix documentation, the SoundHelix API and the SoundHelix sourcecode.
Note that this documentation is mainly intended for end-users. Developers should additionally look at the Javadocs available for SoundHelix.
A beat is a beat is a beat. Look here for a better definition.
An integer number of beats forms a bar. Song lengths are specified as numbers of bars, but other than that, bars are currently not used by SoundHelix.
The basic time unit in SoundHelix is a tick. A tick divides a beat into an integer number of parts. Songs usually use 4 ticks per beat, but other numbers (3, 8, 12, 16 or 24 ticks per beat) are also common. For the MidiPlayer the number of ticks per beat must be a divider of 24 (but only if MIDI time synchronization is used, so that an integer number of MIDI timing ticks is sent per tick, because MIDI timing ticks need to be sent 24 times per beat), so 16 would not be a valid number in this case, but the others would. If you want to be able to use triplets, make sure that the number of ticks per beat is a multiple of 3 (e.g., 12 allows you to use triplets and quarter notes within the same song).
In SoundHelix a pitch represents a relative note frequency, counted in halftones and provided as a signed integer. Pitches are normalized to "c". Therefore, pitch 0 equals "c", pitch 1 equals "c#", pitch 2 equals "d", pitch -1 equals "B", etc. SoundHelix does not support fractions of halftones for pitches. Many aspects in SoundHelix implicitly assume that a heptatonic western scale with 12 halftones per octave is used, meaning for instance that increasing a pitch by 12 doubles the note's frequency.
SoundHelix supports arbitrary 3-note chords (triads), provided that the 3 notes are different and that their lowest and highest note are not farther apart than 11 halftones. Standard chord types (major, minor, diminished and augmented) with an inversion indicator can be specified using an easy syntax (e.g., "C" for C major without inversion, "Em4" for E minor with first inversion, "Am6" for A minor with second inversion, "Gdim4" for G diminished in first inversion or "Eaug" for E augmented without inversion). For arbitrary chords, you can list the 3 pitches directly, separated by colons, to specify the chord (e.g., "-7:-3:4" for the non-standard chord F, A, e).
Starting with SoundHelix 0.5, "fake" seventh chords that consist of 3 instead of 4 notes are supported using an easy syntax (e.g., "C7" for C major seventh, "Am7" for A minor seventh). From the usual 4 notes (e.g., C, E, G, A#), the third one is omitted. This still pretty much sounds like a seventh chord; after all, it contains the root note, the third that distinguishes major and minor and the seventh, whose existence distinguishes normal major/minor chords from seventh major/minor chords. Inversions of these chords are also available (e.g., "C76", "C74", "Am76", "Am74").
Chords are used in many places throughout SoundHelix, especially in HarmonyEngines and SequenceEngines.
Upto version 0.2, SoundHelix only supported major and minor chords, each in one of 3 flavors (without inversion, with first inversion or with second inversion), but the inversion for each chord could not explicitly be chosen in the PatternHarmonyEngine of that version.
A chord offset is a signed integer that selects a specific note from a chord. Offset 0 references the low note, offset 1 the middle and offset 2 the high note, offset 3 the low note transposed up by one octave, -1 the high note transposed down by one octave, etc.
In many components in SoundHelix (especially patterns), pitches are not used directly, but are provided as chord offsets, which are then converted to pitches by using the current chord when the song is generated.
A chord can be rotated up or down, which cycles the chord through the 3 possible chord inversion types. Rotating a chord up means transposing the low pitch of a chord up by one octave, rotating a chord down means transposing the high pitch down by one octave. Rotating the chord "Am" up and down results in the following pattern (..., Am6 <-> Am <-> Am4 <-> Am6 <-> Am, ...), where a step to the left means "rotate down", a step to the right means "rotate up". Note that rotating a chord up 3 times effectively transposes the chord up by one octave, rotating 3 times down transposes the chord down by one octave.
Chord rotation is possible for all chords, i.e., even for chords that have no standard notation.
Normalizing a chord means rotating the chord up or down or leaving it unchanged, so that the chord's low pitch equals the chord's root pitch. For example, this converts both an "Am4" and an "Am6" chord to its normalized counterpart "Am", whereas "Am" stays "Am", because it is already normalized. The rule is simple: "6" chords are rotated up once to normalize them, "4" chords are rotated down once.
Normalization is only possible for chords that have a uniquely identifiable root pitch, which is currently possible for all major, minor, major seventh, minor seventh and diminished chords. It is not possible to determine a unique root pitch for augmented chords (e.g., the chords "Caug", "Eaug6" and "G#aug4" are not distinguishable if you look at their pitches, because augmented chords are the only chords that have a completely symmetric pitch distribution of 0-4-8, which is independent of the inversion used). For all other chords no root pitch is defined, and so they also cannot be normalized, which means that the chords always remain unchanged if they are normalized.
Chords with more than three notes
SoundHelix could support chords with more than three notes in the future (e.g., real rather than fake sevenths chords) , but this currently would be incompatible with the usage of chord offsets. It would be unclear, for example, how to interpret chord offsets if 3-note and 4-note chords were used within the same song (3 would mean the low pitch transposed one octave up for 3-note chords, but would mean the pitch of the 4th note for 4-note chords). If you have any ideas about how to solve this problem, please let me know.
A harmony is a sequence of chords that is used as a repeating template throughout the song. Each chord in the template has a length that is usually counted in beats. A chord template usually forms a chord section. Within a chord section the active instruments generally don't change. However, it is also possible to subdivide a chord template into more than one chord section. For example, you might have a chord section for the song's stanzas and another one for the chord's refrain (chorus). The chord sections don't need to have the same length.
Harmonies are created using HarmonyEngines.
All notes have an associated velocity, which (like in the MIDI specification) determines the speed or strength of pushing a keyboard key down, which can be used to influence the sound of the note. Usually the velocity is used to control the volume of a note, but it is up to the player how to interpret the velocity. In SoundHelix, velocities are specified in the range of 0 (off) to a configurable maximum (full velocity). Using a velocity of 0 is the same as using a pause. Configuring the maximum velocity is possible since version 0.7. Prior to version 0.7, the maximum velocity was always 32767.
Some components which deal with velocity generation support the usage of a velocity exponent. For example, the CrescendoPatternEngine generates a pattern with increasing (or decreasing) velocity. You can define a real exponent that specifies if the increase/decrease is linear, quadratic, cubic, etc. For example, instead of using 32767 * x (with x between 0 and 1) to interpolate linearly between minimum and maximum velocity, SoundHelix will use 32767 * xa, where a is the velocity exponent. An exponent of 2 starts off slower than linear and ends faster than linear, 3 is even slower in the beginning and even faster in the end, etc. An exponent of 0.5 (resembling a square root) will start off faster than linear and ends slower than linear, 0.3333 (resembling a cube root) is even faster in the beginning and slower in the end. Negative exponents are handled a bit differently: Instead of using "xa", SoundHelix will use "1 - x-a", which converts a velocity increase into a velocity decrease of the same speed.
As diagrams say more than a thousands words, here are 4 diagrams that show different velocity exponent examples (the x axis shows time, the y axis shows the output velocity, with 0 meaning minimum velocity and 1 meaning maximum velocity). Notice the symmetry between the diagrams:
|Exponents 1, 2, 5 and 8 (from left to right)||Exponents 1, 1/2, 1/5 and 1/8 (from bottom to top)|
|Exponents -1, -2, -5 and -8 (from left to right)||Exponents -1, -1/2, -1/5 and -1/8 (from top to bottom)|
A sequence is an ordered list of notes and pauses for one voice. A note has a pitch, a length in ticks, a velocity between 0 and the maximum velocity as well as a legato flag. A pause just has a length in ticks. If the legato flag is set, the player will make sure that the note-on for the immediately following note will be sent before the note-off for the current note, unless the following note has the same pitch as the current note (in this case the legato flag is ignored). This makes it possible to change the pitch of a note without restarting the ADSR (attack, decay, sustain, release) cycle. Together with portamento (if available), this makes nice slides possible. Note however, that legato must be supported by the playback device if it is to be used. Also note that the legato flag is ignored for a note if that note is followed by a pause, because then the legato flag would have no effect. All generated sequences span the whole song.
Sequences are created by SequenceEngines. Most SequenceEngines can create more than one sequence, so in general, they create tracks.
Like sequences, patterns are sequences of notes and pauses (for one voice or several voices) and may serve, for example, as inputs for SequenceEngines. In contrast to sequences, patterns are often used repetitively to create a sequence, however, certain SequenceEngines (e.g., the conditional patterns in the DrumSequenceEngine) use a given pattern only once. While applying a pattern to create a sequence, often the pattern's notes are transposed according to the current chord. Therefore, patterns usually don't use pitches directly, but chord offsets, which are then converted to pitches when a sequence is created, based on the current chord. Additionally (and unlike sequences), patterns may contain wildcard characters, which may have a special meaning that is interpreted by the SequenceEngine. For example, the PatternSequenceEngine supports a wildcard character for choosing a pitch that can be used to make a transition from one chord to the next.
Patterns can be created programmatically, but can also be entered manually, for example in the StringPatternEngine. Here, patterns are comma-separated strings of either an offset (syntax: "offset", e.g., "5"), which is a note of 1 tick using the maximum velocity, or a combination of offset and length (syntax: "offset/length", e.g., "5/2"), which is a note of the given number of ticks using the maximum velocity, or a combination of offset, length and velocity (syntax: "offset/length:velocity", e.g., "5/2:22000"), which is a note of the given number of ticks and the given velocity. For all 3 constructs, an optional "~" character can be used after the offset (syntax: "offset~/length:velocity", e.g., "5~/2:22000"), which enables legato for the note: for the following note the NOTE_ON will be sent before the NOTE_OFF of the previous note, which can be used for slides, etc., if supported by the playing device. For the first two constructs, instead of an offset the character "-" can be used, which equals a pause (syntax: "-" and "-/length").
Patterns are created by PatternEngines.
Pattern entries can be grouped by using the syntax "(patternfragment)*count", which will be expanded to the pattern fragment concatenated count times, with a "," in between. These constructs can be nested. For example, the string "((0/2)*3,1/2)*2" will be expanded to "0/2,0/2,0/2,1/2,0/2,0/2,0/2,1/2" before parsing this as a pattern string. Such pattern expansion is available since version 0.5.
One or more sequences form a track. A whole track is assigned to an instrument. A track can be of melodic or of rhythmic type. Melodic tracks are subject to note transposition by the player whereas rhythmic tracks are not subject to transposition. Rhythmic tracks can be used in cases where the pitch defines the sound to play rather than the frequency to use, e.g., for drum machines or for the special drum channel (channel number 10) in the General MIDI specification.
Currently, all SequenceEngines create melodic tracks, except for the DrumSequenceEngine, which creates rhythmic tracks.
Tracks are generated by SequenceEngines.
An arrangement is a set of tracks, which represents the entire song. Each track in an arrangement is assigned a unique name, which can be referenced by a Player.
Arrangements are created by ArrangementEngines and are played back by Players.
An ActivityVector is a vector of bits that defines for each tick of the song whether an instrument should be active or not, and therefore spans the whole song. SequenceEngines take one or more ActivityVectors as input and together with the provided patterns or other logic produce one or more sequences that are active or inactive according to the ActivityVectors.
A SequenceEngine need not strictly adhere to the ActivityVectors it receives. For example, the DrumSequenceEngine supports conditional patterns, which allow creating notes whenever ActivityVector activity changes. This allows for example to create a snare crescendo before the base drum starts. This creation of notes is allowed even if the ActivityVector is inactive at that time.
A consecutive subsection of active bits (surrounded by an inactive bit on the left and the right or the song start or end, respectively) of an ActivityVector is called an activity segment (or simply segment). An ActivityVector can have any number of activity segments (even 0, if the ActivityVector is never active).
A consecutive subsection of inactive bits (surrounded by an active bit on the left and the right) of an ActivityVector is called a pause segment. Note that by using this definition an initial or final subsection of inactive bits is not considered to be a pause segment, as these cannot be surrounded by an active bit on the left and the right. An ActivityVector can have any number of pause segments (even 0, if the ActivityVector is never active or if it only has one activity segment).
A player is a component that is used to play an arrangement in realtime. Certain aspects of the player (for example, the number of beats per minute) can be remote-controlled at runtime.
In various locations in SoundHelix XML files, a Java class can be chosen for providing a certain functionality. At runtime, an instance of the class will be created and will be configured using the configuration provided by the XML block in the XML file where the class is referenced. Such a configured class instance is called a component. Components can be nested. For example, a SequenceEngine component might include a PatternEngine component. In this case, the SequenceEngine is the parent component and the PatternEngine is the child component. A component can have any number of children, but it can only have one parent. Cross-referencing components in the XML file is not supported (for example, it is not possible to create one PatternEngine and use it within two SequenceEngines).