Tag Archives: contour grammar

Cranking out Engines

It's almost mid-March already.  I don't like that fact the the samples haven't improved appreciably in a while.  As I noted earlier, it's mostly due to the fact that I've been upgrading internals rather than working on sound.  Still, it's time to step on it.

Over the past few weeks, I've been working like mad to re-code all the old engines in c++, taking advantage of the massive optimizations possible therein.  So far, the following engines are now at least partially-functional as part of the new c++ library:

  • Artificial Neural Network Engine (was actually never implemented in AHK and has yet to be used in a plugin)
  • Contour Grammar
  • Evolutionary Engine
  • Fraccut
  • Markov Engine
  • Multi-State Engine

ALL of the new implementations are better than their predecessors, both in terms of efficiency and ease-of-use.  Certain complex engines such as the Markov engine may see speed increases of over a thousand fold thanks to redesigning.

By the end of the month, these myriad engines should be coming together to form some really powerful new plugins.  All it takes is code.

Fractal Grammar

For some time now I have been thinking about using random cutting as a "base" method for a hybrid engine, using the cutting space to control the behavior of another process. These thoughts came to a head a few nights ago when, despite an enormous amount of brainstorming and coding, contour grammar failed to deliver the immediate results for which I was looking. I wasn't joking when I suggested a "fractal grammar" in the last post. Indeed, having now toyed around with implementations of the idea, I believe that this hybrid technique will capitalize on both the contextual coherence of random cutting as well as the internal consistency of grammatical systems. I will refer to the method as fractal grammar from now on.

Fractal grammar is, to put it simply, a grammar system driven by a random cutting engine (which, as discussed previously, falls under the category of fractal methods - specifically, Brownian motion). The engine first performs the same preliminary steps used in Fraccut, placing cutting blocks on the roots (or another specified interval) of each chord, then performing random cutting to subdivide the blocks. Instead of mapping the subdivided blocks directly to pitch space, however, the fractal grammar engine maps block offsets to indexes of words.

Here's an overview of the basic fractal grammar process:

  1. Create a space for random cutting
  2. Map chord progression to blocks in the cutting space
  3. Perform random cutting on the space
  4. Create a phrase (in the style of Contour Grammar)
  5. Map the cutting space to the phrase
    1. Iterate through blocks, for each:
      1. Map the vertical position (traditionally pitch offset) to the index of a word and add the corresponding word to the active phrase
      2. Map the width (traditionally duration) to the duration of the specific element of the active phrase
  6. Convert the phrase into a polystream
  7. Apply final mappings (offset->pitch, time scaling, etc.)
  8. Convert the polystream to a pattern

Note that the first three steps are precisely the steps taken by Fraccut, while the last three steps are precisely those taken by Contour Grammar.  The middle steps, then, are the most important - it is the mapping between the fractal engine and the grammar system that is most crucial to the final product.

Thankfully, fractal grammar has already produced some nice results.  Though not quite up to par with Fraccut yet, I have no doubt that the fractal grammar method, when it reaches maturity, will far surpass the abilities of random cutting and contour grammar.

Sample 15, the first in three months, will come online shortly!

Contour Grammar vs. Fractal Cutting

Finally, having completed a basic implementation of Contour Grammar, I am getting to see what the idea sounds like in musical form. Indeed, some very interesting effects have been achieved thanks to the functional phrase language as well as the use of coherent random sources (which I will discuss at some point in another post). However, even this idea is lacking the coherence of Fraccut, and it bothers me enormously that such an elaborate idea as Contour Grammar can't even beat a relatively simple implementation of random fractal cutting, a rudimentary mathematical process.

Of course, it's very obvious why Fraccut still holds the record for best melodies. Since the cutting engine essentially starts with the chord progression as a seed, coherence is almost guaranteed. It's a powerful effect. Yet, the reality is that Fraccut is hardly aware of what it is doing. In a sense, the coherence generated by Fraccut is nothing more than a cheap trick stemming from the clever picking of the seed. Nonetheless, it undeniably works better than anything else. In the end, I am concerned only with the audible quality of the results, not with the route taken to achieve said results.

That being said, the big question now is: how can Contour Grammar pay closer attention to context in order to achieve greater contextual coherence? It would be nice to somehow combine the internal consistency of Contour Grammar with the external, contextual coherence of Fraccut.

Grammatical fractal cutting, anyone?

Contour Grammar Process Flowchart

The Contour Grammar engine, though still young, is already evolving into a complex system of data handling that will, if expectations are met, provide a great deal of both creativity and coherence in future melodic plugins.

The data structure, in brief, works as follows:

  • Words comprise an array of offsets
  • dWords comprise a word dedicated to pitch offsets and a word dedicated to rhythmic blocks
  • Dictionaries comprise many words or dWords
  • Phrases comprise a pointer to the base dictionary of the language in which the phrase is "spoken," a word that provides the rhythmic structure of the phrase (think: rhythmic shells technique), a dWord array that contains the words within the phrase and an array of lengths for the words; this last piece of data is only necessary if the structure word is omitted
  • Polystreams comprise separate arrays for the different elements of a musical note

It is far easier to understand the process through visualization:

Note that, if the engine is instructed to use the accent list (i.e. use the array of lengths for phrase rhythmic structure rather than a word), then this technique requires random or chaotic sources in two places. If the plugin uses words for rhythmic structure, then the technique requires a total of three such sources. This requirement provides ample opportunity for creativity, as we could try different combinations of random sources and observe the results.

Though work on Contour Grammar is progressing at a rather sluggish pace due to an unusually busy week, I anticipate a very productive weekend.

Functional Phrase Language for Contour Grammar

Unfortunately, most of my work over the past week has been devoted entirely to the internals of Contour Grammar.  The format of the data structures will completely govern the quality of the plugin's future, so I wish to spend a great deal of time and thought on the layout of the grammar engine.

A minor breakthrough (which, oddly enough occurred in an airport) did provide a boost of inspiration. One of the current problems with Contour Grammar lies in the ambiguity in defining phrases. How should phrases be picked to maximize coherence? My newest solution to the problem entails a sub-grammar that I call functional phrase language, since it uses functions to indicate derivations of new words from parent words. In this way, rather than filling phrases with a random array of words, the program will fill the phrase with a random array of functional instructions that should ensure greater coherence.

Here's an example of what a line of such instructions might look like:

1,2,1.up.up,2.invert,1.maxdown

And here's how the Contour Grammar engine would read and interpret the instructions:

  1. Draw a random word from the active dictionary, label it "1," and add it to the active phrase
  2. Draw a random word from the active dictionary, label it "2," and add it to the active phrase
  3. Take the first word, translate all pitches up 1 step, then translate all pitches up another step, and add the resulting derived word to the active phrase
  4. Take the second word, invert the pitches (horizontal reflection), and add the resulting derived word to the active phrase
  5. Take the first word, determine the maximum pitch, then translate each occurrence of the maximum pitch up 1 step, and add the resulting derived word to the active phrase

If everything goes according to plan, Contour Grammar should be off the ground and getting cold, hard results by the end of the week. As I mentioned before, I really hope to have some unique samples up for February before it comes to a close. Audible progress is real progress!

Contour Grammar: Initial Results

It's been a long, bumpy road to the first functional mGen plugin written in c++. Nonetheless, tonight has seen preliminary results of the work-in-progress contour grammar system embodied in c++.

Contour grammar is, essentially, a marriage of two previously-brainstormed ideas: rhythmic shells and curve splicing. The name refers to the fact that, at heart, the engine is grammatical, using the method of rhythmic shells to handle words and phrases in context, but that words are defined using basic contours like those described in the curve-splicing method.

Unlike the grammar engine of GGrewve or GrammGen, contour grammar is functional in form, meaning that a word is not necessarily limited to a certain length. Rather than using an array of pitch or rhythmic offsets to characterize a word, contour grammar uses an array of coefficients that determine the properties of an infinite contour. Rhythmic shells then give precise instructions for transforming sets of these infinite contours into concrete, finite note streams.

Some expected advantages of contour grammar:

  • Arbitrary note size makes words extremely flexible (any given word can fill up any given amount of space, so no length-checking is necessary)
  • Rhythmic shells preserve rhythmic integrity of phrases
    • Shells still allow for variation by providing direct access to the words upon which the shell is built
    • Tweaking a single word's coefficients will change a specific part of the shell while preserving everything else, allowing for great coherence
  • Object-oriented data structures provide means of easily manipulating high-level variables that result in subtle, low-level changes
  • Very little conversion necessary between rhythmic shell and raw pattern
    • Rhythmic shell -> Polystream
    • Polystream -> Contextual Polystream (snap to key, duration *= quanta, etc.)
    • Contextual Polystream -> Pattern

So, in summary, contour grammar provides a flexible, coherent, and easily-variable data structure while still remaining concrete enough to require only a few minor steps to convert to pattern format.  In general, abstractions such as those made by grammar engines suffer from either a lack of coherence or a difficulty in de-abstraction (returning them to the base format).  Contour grammar, it seems, circumvents these drawbacks with a well-designed data structure.

Preliminary results with contour grammar already display some degree of coherence, a great deal of variability, and, most importantly, the potential for continued development and improvement.  February will surely bring some new, interesting samples!

Rhythmic Shells

With the contour grammar engine in development, I am still searching for ways to simplify and optimize grammatical representations. At the moment, the most restrictive element of the engine is the separation between rhythm and pitch. In current engines, the two are completely separated into different streams driven by different grammar sets. Not only does this approach render it difficult to work with both streams at the same time, but it also negatively impacts the ability of the engine to produce coherence between pitch and rhythm.

A new idea I call "rhythmic shells," however, might promise an enormous simplification of the process, combining both streams into one while offering greatly improved coherence potential at the same time. The method focuses on stripping pitch words of all length dependency and transforming rhythm into a specification of pitch words. In essence, a rhythmic "shell" is selected, which contains a prescribed number of "slots," each with a distinct duration, and the slots are then filled with pitch words. The method requires that pitch words be functions rather than definitions - that is, they must be of arbitrary length and cannot be precomputed.

Here's a simple diagram of the method:

The shell stream can be specified with a simple data structure like this:

13:2,4,5
15:2,8,6
13:2,4,6

The number on the left side indicates the index of the pitch shell to be used, while the comma-delimited numbers indicate the indices of the pitch functions with which to fill each shell slot. Notice that the phrase produced by a shell can be variated by leaving one or more elements intact while changing the others, creating a different, but still somewhat similar phrase. This will certainly guarantee more coherence.

It is worth noting that, given the functional nature of the pitch words in this description, the method of rhythmic shells if very much like a generalized method of curve-splicing, which was discussed several weeks ago!

In the next few days I put a great deal of work into the contour grammar engine to try to implement the method of rhythmic shells. I also hope to continue finding new innovations for the simplification, unification, and overall improvement of grammar techniques.

Grammatical Representation of Contour

Though the mathematical melodies of Entropic Root provide excellent and oftentimes interesting background patterns, they still lack the coherence of a genuine, human-crafted melody. I do not wish to imply that no progress has been made towards that ultimate goal of realistic melodies, however, I must be realistic in admitting that a mathematical method like Entropic Root cannot achieve the same level of composition as a human because Entropic Root, at its core, does not have any concept of what it is creating: it is not intentional.

Contour seems to be a reasonable way to mold a melody before determining actual pitches. In the past, great success has been achieved with grammatical representations of music. GrammGen, the first I ever wrote, implemented a very simple grammatical system for generating melodies. Though not up to par with the performance of modern plugins, GrammGen often provided interesting melodies. Like Entropic Root, however, GrammGen had very little deliberateness in its actions. In order to resolve this, I hope to combine the premeditative abilities of contour shaping with the structural simplification of grammar engines to achieve a deliberate and coherent melody generation engine.

Essentially, I am introducing yet another grammatical engine. This engine, however, will be based on a “contour as a language” paradigm. In other words, it will treat the words of the grammar as having contextual significance because of a contour correspondence. Rather than assigning progressive, numerical values to randomly-generated words and jumbling them together to create a phrase, this “contour grammar” engine will recognized the contextual significance of each word by its parent type. There are eight parent types, which correspond directly to fundamental units of contour: two jump contours, two linear contours, and four “bounce” or “pivot” contours. Words will then be randomly generated under parent types, but the engine will know to which type of contour a given word belongs. A Markov engine or simple multi-state engine will determine the contextual significance of contour units.

Below is a quick sketch of the eight fundamental units of contour.

If we imagine that each line segment has an arbitrary magnitude (but that segments equal in size in the diagram have equal magnitudes), then it is not hard to see that these eight fundamental units actually characterize most possible monophonic melodies. This is especially true if one considers certain transformations such as stretching and splitting.

I am hopeful that the method of contour grammar will be a historic step towards intentionality in output for mGen, starting with melodies.