## Developing a heuristic for evolving guitar blues licks

Towards the development of a pseudo simulated annealing genetic heuristic for evolving blues ideas

### Re: Developing a heuristic for evolving guitar blues licks

Ok, I hope everyone had a chance by now to get acquainted with Constructor Theory. David Deutsch and others are doing big things with it like:

Fixing the circular reasoning in Shannon's information theory.

Providing deeper understanding of life (no not that life)

And providing a new framework for quantum theory.

All very heady stuff indeed. I will being using it in more modest way, i.e. to create blues licks.

I suppose it's fairly obvious why constructor theory provides a great paradigm for developing my heuristic, so I'll just state the basics for the sake of completeness.

At the heart of Constructor theory are constructors which perform a transformation on an input substrate(s) to produce an output substrate. i.e. input substrate(s) -> Constructor -> output substrate. That along with counter-factuals ('X is possible' or 'X is impossible') is all that is needed to define the fundamental laws of - well I'm thinking anything!

Applying this to my little self defined blues universe: Licks are substrates and the constructor is the set of mutations and spawnings that I define. Each specific mutation, e.g. the one that substitutes a rest note for a played note, is a sub-constructor that is a part of the overall constructor that (along with the counter-factuals) defines all possible lick transformations.

The counter-factuals add additional constraints than those implied by the constructor on what licks are, and are not, possible. This is where my metrics like: pitch entropy, rhythm entropy, harmony entropy, sweetness, sourness, average lick tension ( I haven't described that yet but I'll get to it shortly) etc. etc. come in.

By setting parameters, of min and max entropy (or any other metric), the boundaries for the universe for what licks are possible is defined. And other parameters, like max lick density as a function of entropy will guide the distribution of licks within that universe.

That's the overall guiding principle of my heuristic.

Any questions?
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

On top of the constructor theory paradigm I'm going to be using what I call "a pseudo simulated annealing genetic heuristic" for evolving blues ideas.

I'll break down what I mean by that now.

Annealing is a process where you recrystallize a metal to make it easy to work. You get the metal very hot so that atoms can migrate and dislocation in the crystal decrease. When the metal is very hot, the atoms are most capable of change. You bring the temperature down slowly so that they atoms settle into a crystal structure.

Simulated annealing is a search process that allows more exploration of solutions, rather than just choosing the best local option. It has the concept of temperature in simulation, which generally speaking translates into, in the early stages of the search a lot of exploration is allowed and local optimizations aren't too important, as time goes on, less drastic exploration is allowed and more time is spent on local optimization, eventually the best global area found by exploration is searched for a local minimum.

I'm doing something related but not exactly that - for one thing, I'm combining simulated annealing with a genetic alogrightm. I'm trying to fill a defined space with specific density distributions of licks. At the beginning, "when the temperature is hot", I'll be trying to get some licks throughout the natural universe for licks that I define. Large mutations will be used when the temperature is hot. As time goes on, "the temp cools", and smaller mutations will help flesh out the areas where some licks were deposited by the large mutations.

The genetic aspect of my heuristic should be clear by now. I'm mutating and spawning new licks from old ones to create variations.

The heuristic part is that I'm using rules of thumb to arrive at a hopefully acceptable solution rather than an algorithm which is a precisely defined set of steps to solve a problem. (There are other definitions of these words, some people like to argue about them, but this is what I mean when I use them.)

This video of swarming combined with simulation annealing gives a good idea of what I'll be doing. The various valleys are like the various areas in my lick space that I'm searching for solutions for. As the temperature cools, I'll concentrate around the areas where licks are.

Hmmm. perhaps I need to add swarming to the name of my project.

A pseudo simulated annealing genetic heuristic with swarming technology based on constructor theory for evolving blues ideas.

To make this all a bit more concrete. Here's an example of the entropy space explored with cool mutations on the founder set of licks. About 1,000 licks in total.

And here's the entropy space explored with a warm spawning mutation added. Again, about 1,000 licks total.

It's easy to see how much more space is explored when the temperature is turned up.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

Taking a step backwards a bit, I added some measures of how much tension the pitch is creating throughout the lick. For example, Lick 0 is:

And plotting tension through the lick, I get:

The exact amount of tension each pitch creates is debatable and not so important at this moment as I'm more interested in having this kind of measurement infrastructure in place.

Valuse of tension from the root are as follow:
tdic={ 0:0, 1:11, 2:4, 3:7, 4:2, 5:5, 6:10, 7:1, 8:9, 9:3, 10:8, 11:6}

If someone has another idea of what the tension values should be I'd love to hear about it. I haven't found much that quantifies this.

I generate a bunch of different metrics, I image the tension integral and tension integral average is most relevant. The total amount of swing in tension is also interesting, I'm calling that sum delta tension.

Here's an example showing how the M3 releases the tension form the piece of the min7 chord.

A lick ending with a fair amount of tension.

The tension is held through rest notes.

I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

As I was reading David Deutsch's paper on Constructor theory the concept of programmable constructors vs non programmable constructors got me thinking. (An example of a non programmable constructor is a catalyst of a chemical reaction.) Now from one perspective, my lick constructor, which is composed of many sub constructors is in a sense programmable- i.e. I did program all sub constructors, however from another perspective, once programed and launched they just do what they do, in that sense they are as fixed as the catalyst. All this, and the need for a good way to make a hot rhythm constructor got me thinking about self programed constructors. i.e. a constructor that learns to make transformations by observing what transformations occur.

I won't go into all the details but I built a constructor that can learn from watching trial and error mutations what transformations a given lick (or a lick with similar characteristics) can undergo. And this self learning programmable constructor, once it has learned that lick A has a mutation path : A->B->C->D also knows that A->D, and B->D. And this smart constructor can make these transformations with foreknowledge, which is very different than how my other constructors work. Also, while it was learning about possible transformations, it learns about the characteristics of the resulting lick. i.e., it's various entropy metrics, etc.. So a smart constructor like this doesn't have to just produce a random mutation but can attempt to create a mutation with certain characteristics. And it can learn other things while it's at it. For example, by collecting sets of notes used in licks and remembering how sweet and sour they are, it can fulfill a request for a lick with a certain sweet and sourness.

It's like this: at the start, LickMaker is like a child playing with blocks and by trial and error building what he can build with them. But soon the child learns what he can build and then can build some things from experience. With smart programmable constructors, LickMaker can learn from experience and acquire a lot of knowledge about how a given lick can be transformed and that gives it another level of capability.

All of this raises all kinds of interesting questions about how much time LickMaker spends learning about the transformations it makes by trial an error and how much time it spends evolving licks. And what licks does it learn about, and when does it learn about them ...

For now I'm going to keep things fairly simple and see what I can learn from my self learning, self programmed, hot rhythm constructor.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

I've become a bit smitten by the idea of self programmed constructors and looking for other areas for LickMaker to learn from the mutations it makes. One area is learning what pitches are needed in a lick to create a specific sweet and sour vector. (The sweet and sour vector is a metric that says something about the amount of dissonance in the palette of pitches used in a lick. It's similar to what colors you'd find on a painters palette for a given painting.)

Here's the sweet and sour space covered by LickMaker after 5000 mutations of the 14 original licks. It seems that a good mapping of what pitches are needed for many/most sweet and sour vectors can be learned. Note: some areas of the space are probably not accessible, for example, a the note set can't be both very very sweet and very very sour.

And here's where standard chords map relative to the above scale.

Now the sweet and sour metric is a measure of the pitch palette used but it says nothing about the exact use of the pitches in the lick. It doesn't convey how much tension is created by the specific use of pitch order and duration, including duration of rests in the lick. To get a sense of that relative to sweet and sour I plotted the sum of the change in tension throughout a lick along with the sweet and sour metric for about 4000 lick mutations. There are other tension metrics but in my next comment I'll explain more about why I chose this one to use. I imagine that the sweet and sour space that have few variations of licks would if more generations of those licks were allowed to mutate, That is, they represent recent spaces being explored (although in some cases, power chords for example, there may not be tension alternatives that LickMaker can make.

I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

I've been working on understanding the usefulness of the tension metrics and ways to mutate tension without changing entropy or sweet and sourness. The tension metric that seems to most lend itself to that is the sum of the change in tensions of the pitches as the lick is played. I.e. change in tension/time. I'll give an example of doing this with lick 0.

Here's where Lick 0 plots in sweet, sour, and sum of delta tension space.

And after mutating Lick 0 to with an eye towards creating tension variation and leaving other metrics unchanged. It's easy to see that the sweet and sourness didn't change but more variety of tensions are now available.

To do this I created a constructor that mutates the lick in ways that only effect delta tension and also limits the density of licks near a delta tension value. The number of permutations is n factorial the number of notes that can swap position so it's helpful to limit the number of varieties produced yet still get as wide a range of tension varieties as possible.

One type of mutation that can change delta tension without effecting other metrics is to permute note positions in the lick. Here's various tension metrics for the 6 versions of Lick 0 that I ended up with. They are sorted from lowest tension to highest tension. I don't allow bends to have note order changed so the g going to g# can't be swapped. It's pretty easy to see from the charts that the minimum tension has less peaks and valleys than the max tension version of Lick 0.

And here's the entropy plot for the set of 6 licks. They all fall on the same spot, so this mutation didn't change entropy.

It's a bit hard to know how much to trust the meaningfulness of these tension metrics. To help with that I sorted the founder set of licks by the sum of delta tension metric. The begging and end look right, the general trend looks reasonable. Here's the order sorted by tension. The tension value is printed next to the lick position number.

And here's how they sound in sorted order.

The first and last seem in the right place, and the trend seems right, but I find it harder to know if the rest are where they belong. That just may mean that my computer is more sensitive to small tension differences in a lick than I am.

You can also hear the variations of Lick 0 in sorted order here.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

Now it's time to develop what amounts to the cockpit of my heuristic. This will provide input controls to how LickMaker goes about developing licks. Using Constructor Theory terminology, these are the counter-factuals, i.e. what is possible and what is not possible for licks. If a counter-factual prohibits a lick, then that lick will not be able to exist in lick space. However, Constructor theory has a concept that seems similar to imaginary numbers to me. It goes something like this: It may be true that a->a', and/or b->b' are not possible transformations, however a',b' ->c may be possible. This means that the "laws of nature" of a systems will obviously make impossible states (substrates) impossible, but the laws may also make it possible to transform a given impossible state (substrate) into a possible one. This presents a bit of an issue in deciding how to handle these substrates that the laws of nature of the system deem non-natural but can never-the-less effect change in nature by helping to transform another substrate, or be themselves transformed into another substrate. David Deutsch gives some examples of these impossible states doing possible things in his paper. I could give a guitar lick example if anyone is interested. I need a term for these impossible states, i.e. states that the laws of nature prohibit, calling them supernatural states seems appropriate.

In short, a supernatural state, (substrate - in my case - lick) is one that violates one or more counter-factuals yet may still effect the transformation (mutation) of another lick or be transformed itself to a state compatable with the laws of nature. i.e. a supernatural state can be made natural.

I'm going to start with a basic set of counter-factuals for lickmaker and add to them as the need arises or when I'm in a better position to take on more complexity, like dealing with alternate fret positions, chord types, etc. For now the counter-factuals are:

1) Entropy space. This is the 3D, pitch, rhythm, and vertical entropy space that I've been demonstrating. For a lick to exist in nature it must exist in one or more defined regions of entropy space. Many separate regions of entropy space may be defined and different regions may have different characteristics. The general format for defining these regions is:

lentropy= [
[ entropy region 0 ]
[ entropy region 1 ]
[ entropy region n ]
]

A dictionary of n entropy regions is defined, each entropy region has a definition for each of its 3 dimensions as follows:

entropy region n = [ [ pitch entropy specification ], [rhythm entropy specification], [vertical entropy specification]]

Each entropy region specification is defined in a similar way as follows:

pitch entropy specification = [ min pitch entropy, max pitch entropy, min pitch density, max pitch density, crystal fac, shape]

The min and max pitch entropy values define where in pitch entropy space this region is. The min and max pitch density set the desired min and max number of licks to inhabit that region/unit. The crystal fac sets how regular a lattice is desired for licks in the space (more on that later), and the shape is used to specify the contour of the region. More on that later also.

I'm finding this simple definition pretty powerful, rather than giving detailed examples of this now I think it best to list the other counter-factuals in this comment.

Similar to entropy space is another space with three dimensions, sweet n sour n tension space. It is defined in a way similar to entropy space.

lsnsnt= [
[ sweet n sour n tension region 0 ]
[ sweet n sour n tension region 1 ]
[ sweet n sour n tension region n ]

sweet n sour n tension region n = [ [sweetness specification ] [ sourness specification] [ tension specification ]]

An example of a counter-factual that specifies what is not allowed is

lcount_no ={
'+-t-l':0,
'a-t-l':0,
'+-t-al':0,
'a-t-al':0,
}

This makes triplets across a beat boundary non natural.

Similiary:

starting_tension_no={}

ending_tension_no={
'min2_nt':[1],
'Maj2_nt':[2],
'min3_nt':[3],
'dim5_nt':[6],
'min6_nt':[8],
'Maj7_nt':[11]
}

Specify non natural starting and ending tensions. the empty starting_tension_no dictionary allows all starting tensions.

A few more counter- factuals.

fretposition={0:0}

max_num_licks = 10000

That should be a fair introduction to the counter-factuals that I'm starting with and how they are used to guide the heuristic towards which licks to make.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

Here are some examples of using the entropy space counter-factuals to define some different regions of entropy space.

Four regions in space, each with different densities would be defined like:

lentropy=[
[ [.5, 2., 10, 20, cry, 'r'], [.5, 1., 10, 20, cry, 'r'], [0., 1., 3, 20, cry, 'r'] ],
[ [.5, 2., 5, 20, cry, ''], [2.5,4., 10, 20, cry, 'r'], [0., 1., 2, 20, cry, 'r'] ],
[ [3., 4., 2, 20, cry, 'r'], [.5, 2., 2, 20, cry, 'r'], [0., 3., 2, 20, cry, 'r'] ],
[ [3., 4., 20, 30, cry, 'r'], [2.5, 4., 20, 20, cry, 'r'], [0., 4., 15, 20, cry, 'r'] ]
]

Each line defines a different region. Each list on a line is for pitch, rhythm, and vertical entropy.
Each list defines min entropy, max entropy, min density, max density, crystal factor, and shape.

The above would produce a space similar (I think I changed a few variables a bit) to this: (At this point I'm calling a uniform random number generator to find objects to attempt to fill the regions, eventually I'll try to fill the regions with licks.)

And by changing the shape variable, wedges and triangular shapes can be specified. I added this mostly to accomidate sweet and sour possible profiles, I'll add other shapes if there seems to be a need for them.

By adjusting the density and crystal factor more or less regular lattice spacing can be specified. I'm not sure how useful this is, it's just something that came to mind as I was trying to think about the problem of selecting licks (or random anything) to fit a volume and how one might go about doing that.)

Pretty regular.

And more regular.

Regions can overlap each other and one thing this makes possible is the ability specify density gradients.

And thinking about overlapping regions, gave me an idea on how to handle impossible substrates that can never-the-less influence the transformation of possible substrates. Impossible substrates are those that the counter-factuals deem unnatural. However, per Construction Theory, impossible substrates may be transformed into possible substrates or influence other possible substrate transformations. These impossible substrates cannot inhabit the natural world, they reside in what I'm calling the supernatural realm or region. My syntax provides an easy way to add a region, the supernatural region, where the normal laws of nature are suspended, this is where impossible substrates that have the power to influence possible substrates can reside. I call these impossible substrates that can influence the transformation of possible substrates "angel substrates".

Here's plot of a single dense region of possible substrates engulfed by a supernatural region populated by angel substrates.

And after thinking about all this some more, I'm liking the idea of having each region have the ability to define their own counter-factuals. This should not only make it possible to have clear laws for the natural vs supernatural but allow regions for different chords and intros and turnarounds, etc..
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

Building on the last comment, I added sweet and sour and tension space in parallel with the 3D entropy space. The goal of lick maker is to fill the defined regions in these spaces with licks that meet the density conditions set for the regions as well as all the other counter-factuals. I'm going to continue to develop using uniformly distributed random numbers to simulate finding licks for the early part of the heuristic development because it's easier to predict and check results- and just easier to do. Random number generators allow best possible solutions for reasonable definitions of spaces to be easily computed. For example here's a solution that fills entropy space as desired and does as good a job as possible given the constraints I set for sweet n sour n tension space. Red dots are valid solutions, black squares are missing solutions, and yellow angles are hovering around it all.

By not giving the heuristic enough time to brute force a solution I can simulate a more difficult problem- i.e. trying to find licks that meet all constraints. With less time more black squares signifying missing solutions result.

And with less time, more black squares.

The first goal of the heuristic will be to find less than perfect but better than no solutions where the black boxes are when time is limited, i.e. brute force won't work.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

I need to get caught up with this thread. I'll check it out over the weekend.
"Walla Walla Bonga!" — Witticism

felltoearth

Posts: 11609
Age: 52

Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

felltoearth wrote:I need to get caught up with this thread. I'll check it out over the weekend.

If you have a bit of extra time I would recommend spending it first on the David Deutsch videos about his Constructor Theory. He is looking for a new paradigm for understanding- well pretty much everything and I've been amazed at how his ideas can transform how you look at things.

And if you have any questions ...
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

So I've been constructing the scaffold for the simulated annealing heuristic beneath the constructor theory framework. Still using the uniform distribution random number generator to create test cases so the simulated annealing is marginally useful but I think it will be more helpful when I replace the ransom number generator with lick mutations which are not uniformly distributed and have gaps in what is actually possible to do.

Here's entropy space followed by sweet and sour and tension space showing "licks" found (red), angels (yellow), and licks not found (black).

It's hard to see the missing "licks' so here I'm just plotting those:

And here with the annealing turned on:

(no empty spaces in entropy space)

And less empty spaces in sweet n sour n tension space:

I must confess that what I've done for this simulated annealing is a bit hokey, but it's a start and I'll improve it as actual licks are introduced into the picture.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

It's been a while since I updated this thread. I took a bit of a vacation but before that I was working on porting the mutation code to the new heuristic framework. The project has gotten complex enough that a fair amount of restructuring was needed so that it was manageable to work with. So tidied up a bit, and with some new code so that allows me to define n lick spaces, each with their own counter-factuals things are moving along nicely.

Here's a chart showing a lick multiverse with two lick universe spaces defined. The first one is the standard founder set I've been using throughout the thread, the second one is a turnaround lick universe. (the turnarounds can be used for intros as well as turnarounds). This is just an example, I could imagine more spaces being defined, perhaps a unique space for I, IV, and V chords at some point)

The chart shows the entropy space on the left and the sweet, sour, tension space on the right for each lick space/universe. The turnaround space is shown by the bottom two graphs.

I only have one supernatural space (where the angels exist) in the project so each universe shares the same supernatural space. I'm not sure that's the best way to go but it simplifies things a bit and they are already complicated enough. If the need arises, I'll give each universe it's own supernatural space.

The counter-factuals act like a filter for each lick space. If a counter factual makes a lick impossible for that space then it either becomes an angel lick and is placed in supernatural space or it ceases to exist. Some of the founder and turnaround licks were impossible according to the counter-factuals I have in place and they were made angels. (the yellow ones)

The counter-factuals I have in place now are.

not allowed counts
allowed positions
required starting notes
required ending notes or chords
not allowed gesture types (licks with bends or whatever could be easily filtered out)
required gesture types

It should be easy to add new counter-factuals as the need arises.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

I integrated the cool and warm (spawining) mutation constructors into the heuristic and did some trial runs. The complexity of the project has gotten a bit away from me so that integration was a bit of a challenge. There's probably still an issue or two with how with heuristic controls the population of the density space that needs to be worked out but it's basically working.

Here's the results from a 4 generation run of the original founder set (the top two charts showing entropy and sweet, sour, and tension space). The turnaround space (the bottom two charts) haven't been mutated. The shaded ghostly looking areas are where the space defined by the counter-factuals and missing licks. And the yellow angels are were the counterfactuals (I would expect mostly because of a density issue) prevents a lick from inhabiting a "normal" space and the lick got bumped to supernatural space. All lick spaces share the same supernatural space so you get a bitter view of the angles in the turnaround space charts where there are only the founder licks that met the counter-factuals.

Another view of the same results. It shows that pitch and rhythm entropy are covered pretty well, along with sweet and sour spaces. As one might expect, there's not much vertical entropy when there's not much pitch entropy and not much low tension when the lick is sour. I think both these situations can be improved a bit and I'm going to check into that.

And two views of a 10 generation run.

All in all, this looks promising. I'm going to try to fill the space a bit better and then concentrate more on selecting licks and attempting to make actual music from the selections- which should be more interesting.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

I worked on filling in the space a bit. I decided to try adding a few select founder licks to help get more licks with vertical entropy when the note entropy and rhythm entropy is on the low side. And that worked pretty well. It seems that the right founder licks can have a big effect on the final population. Here's a new 10 gen run.

I also worked on trying to explore the tension dimension around the whole sweet and source space. To do that I ported a stripped down version of my tension mutation function. The original tension mutation function, which is explained here, was modified to just randomly give one new tension variation of a lick when called instead of creating all possible variations (when that's practical to do). I ran this new tension mutation generator for a considerable time, and while it filled in areas of the sweet n sour n tension space, I think the general 3D curve that is emerging is representative of what part of the space is inhabitable. I tried to make a custom lick to see if it could be sour with low tension (quick Jimmy Hendrix chord and long duration resolution) but that didn't do it. Maybe a quick stab at a very dissonant mess of a chord followed by a lot of resolution will do it but I'm not sure how interesting that is.

Here's what the space looked like after adding a lot of tension variations. It filled in some but didn't change the basic shape of the curve.

Because I don't have a great way to represent 6 dimensional space, you can't see the relationships between a given area in entropy space and sweet n sour n tension space. To get a better view of that, for the licks I have on hand, I created six sub spaces, each one limiting entropy space to a plane (a thick plane ) sliced in various ways. With this you get a better view of how those regions contain licks that have certain sweet n sour n tension values. Here's what those regions look like:

The top two charts for each image is the entire space. The bottom two are for one of the plane slices. Left is entropy space, right is sweet n sour n tension space.

slices in a rhythm plane.

I'm liking how these spaces work along with the other counter-factuals to filter what licks are possible. It's a nice paradigm.

Once you have a new space, you can mutate the licks in it if you want to add to the space. I ran 10 generations of mutations for the last plane I showed above. Here's what the results look like:

On a bit of a different topic, I ran some mutations of the turnaround licks and got a space that looks like on the bottom of this chart:

Now all of this is pretty abstract and rather than work on improving the heuristic so it's better at filling the nooks and crannies of the spaces I think it more productive to work on making some actual music from the licks generated so that I can get feedback on how effective these entropy and sweet n sour metrics are. So I'm going to switch my focus a bit on that.

I'll need a mechanism for selecting which lick to play. For that, I'm planning on building on an idea the Moog Music uses in Animoog to control sample playback. You set a path and control orbits around that path.

I'll also need a simple language to program songs.

So that's what will be next.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

Next I've developed a mechanism that allows me to specify a pick pointer which can later be used to pick a lick in a given part of a region.

You can have any number of pick pointers per region, and also use the definition of a pick pointer for one region in another region. A pick pointer is defined as a set of line segments, (they don't have to be continuous, as in the example I'm about to show). At bar 0 (music bar) the pickpointer picks from the beginning of the first segment, it increments a specified distance along the segment every music bar. When it gets past the end of a segment it jumps to the beginning of the next segment. When all segments have been traversed it starts all over again. This simple mechanism allows for all kinds of picking.

Here's the same path defined in entropy space of two regions. And also a path in sweetnsour space of the first region around a Major blues pentatonic scale.

The pointer doesn't just pick points on the lines but rather from a distribution defined around the pickpoints of the line. You can make the distribution as tight or as wide as you like. The pick points above had with a very tight distribution from it's defined pickpoint. Here I show a more relaxed distribution space.

And in the region in the bottom of this chart the distribution is even set wider.

Of course, at any given time you're picking a specific point. Here's what that would look like for these pickpointer definitions.

I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

It's probably getting near time for a review of where I am but I'll just give a brief summary and push on in this post.

At this point I can start with a few blues licks and mutate them. I can create independent regions where counter-factuals control which licks can exist in a given region. To make this a bit more concrete. I took the founder licks and mutated them into a set of about 2000 licks, then I loaded that set into regions with varied counter-factuals. The regions are as follows:

spacenames = ['angels','scratch', '1bar_Maj_bs','2bar_Maj_bs','2bar_min_bs','2bar_turns']

This python code. the [] define a list, so the list spacenames has elements:

"angels" - which is a region where licks that can't survive the counter-factual of the region they would otherwise be in end up if there is room. At this point I don't use angel space for much but it is useful for giving an indication of where the density of licks is overflowing a region. And I'm trying to get used to the concept of angels.

"scratch" - this is a wild west region without a lot of counter-factual restrictions that I can used to create new licks on the fly as they might be needed for a song. I also can store licks that I specifically want to use here.

'1bar_Maj_bs' - This regions is set up to only allow licks that are 1 bar in length and match up pretty well with Major blues scale.

'2bar_Maj_bs', - This regions is set up to only allow licks that are 2 bar in length and match up pretty well with Major blues scale.

'2bar_min_bs',- This regions is set up to only allow licks that are 2 bar in length and match up pretty well with minor blues scale.

'2bar_turns'-This regions is set up to only allow licks that are 2 bar in length and is for turnarounds.

I loaded the 2000 general licks into each region and they were filtered appropriately, then each region went through 5-10 generations of mutations to populate that regions lick space. All in all I ended up with about 4000 licks.

Next I need a language to pick licks from those spaces to create a song- which I'm doing mostly to test my lick metrics but there are other motivations too.

What follows is a description of the song writing language that I have so far and an example. I'm using python friendly constructs- the dictionary and list.

bsdic={} defines a dictionary named bsdic (curly brackets instead of straight brackets for a list)

entries in bsdic point to lists of descriptions of groups of lick specifications that play in order one after the other.

For example:

bsdic['bs_intro']= [ ['name','intro_0','scratch']]

puts an entry into bsdic which describes a list of a single lick specifier, that being: ['name','intro_0','scratch']]
the first element of the lick specifier is the operation code - "name" means get the lick with a specific name,
the next element of the lick specifier is the name of the lick - in this case: 'intro_0'
the next element of this lick specifier is the region where that lick can be found. In this case, the "scratch" region.

Basically, I'm defining the intro lick of my song.

Next I specify a 12 bar lick pattern. 12 bars is a common blues chunk of music, but I could have broken this into smaller chunks but 12 bars is what I'm using here:

bsdic['bs_12b_0']=[
means I'm adding a new list of lick specifiers to the dictionary and this list is called " bs_12b_0"

Now I'll going through the various lick specifiers for the 12 bars.

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'],

adds a "plick" operation code which means, use lick pointer, "e_1bar_Maj_bs" to pick a lick. "e_1bar_Maj_bs" is set up to point to licks in region '1bar_Maj_bs' using an entropy pointer as I described in my last comment.

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'], ['match_n','bs_12b_0',0],

next I add a lick specification that has a "match_n" operation code, this is saying, find a lick that best matches the notes (but isnt' the same lick) of, in this case, the previous lick but you specifiy the dictionary entry name and position so it can be for any previously assigned lick.

Notice I'm not saying exactly what lick to pick but just giving general guidelines. Match_n using the pattern matching software that I describe here to determine what chord a lick was lick but in this case that software is being used to find another a lick that uses similar notes to a given lick.

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'], ['match_n','bs_12b_0',0], ['alt','bs_12b_0',0],

"alt" adds a lick specifer that says, pick a lick in the same way that you did for the first specifier in the list. I could have just used the same command ['plick','e_1bar_Maj_bs'], but I'm trying to build some structure into the song language so that repeated memes are more obvious.

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'], ['match_n','bs_12b_0',0], ['alt','bs_12b_0',0], ['match_n','bs_12b_0',2,'rentropy'],

Next antother "match_n" command, but this one, besides asking for similar notes is also specifying similar rhythm entropy.

And that's four single bar licks being specified.

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'], ['match_n','bs_12b_0',0], ['alt','bs_12b_0',0], ['match_n','bs_12b_0',2,'rentropy'],
['plick','sour_2bar_min_bs'],

Next I specifiy a 2 bar lick using a pick pointer that I set up in sweet-n-sour-n-tension space that's not too sour - this is a very happy major sounding blues song.

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'], ['match_n','bs_12b_0',0], ['alt','bs_12b_0',0], ['match_n','bs_12b_0',2,'rentropy'],
['plick','sour_2bar_min_bs'],
['posit','bs_12b_0',0,12],['posit','bs_12b_0',3 ,14],

The next two lick specifiers request that two licks already played be replayed and moved up an octave or so. That command used the lick position transpose software that I explained here

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'], ['match_n','bs_12b_0',0], ['alt','bs_12b_0',0], ['match_n','bs_12b_0',2,'rentropy'],
['plick','sour_2bar_min_bs'],
['posit','bs_12b_0',0,12],['posit','bs_12b_0',3 ,14],
['chordit','bs_12b_0',0,7,'7','scratch'],['chordit','bs_12b_0',1,5,'7'],

Next the "chordit" command is used to take two licks that have been previously played and change the notes to use those in a V dominant seventh chord and a !V dominant seventh chord. So B7 and A7. The software that does this was described here

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'], ['match_n','bs_12b_0',0], ['alt','bs_12b_0',0], ['match_n','bs_12b_0',2,'rentropy'],
['plick','sour_2bar_min_bs'],
['posit','bs_12b_0',0,12],['posit','bs_12b_0',3 ,14],
['chordit','bs_12b_0',0,7,'7','scratch'],['chordit','bs_12b_0',1,5,'7'],
['plick','e_2bar_turns'] ]

Finally I specifiy a 2 bar turnaround be selected using an entropy pick pointer.

Since this is my first song I'm going to keep it simple and use the same template for most of the song.

bsdic['bs_12b_1']= [['altbs','bs_12b_0']]
bsdic['bs_12b_2']= [['altbs','bs_12b_0']]
bsdic['bs_12b_3']= [['altbs','bs_12b_0',[0,10]]]

adds 3 more lists to the dictionary and they are specifying that 'bs_12b_0" be used as the template

bsdic['bs_12b_4']=[['rep','bs_12b_1',[5,7]],['rep','bs_12b_2',[0,2]],['rep','bs_12b_3',[3,8]], ['name','fin','scratch'] ]

Uses the 'rep' repeat command which specifices that the exact licks used at specific points be used again, and it wraps things up with a "name" command specifying the final lick.

All that's left is to define a structure that describes which lists of licks from bsdic should be used in the song and in what order.
A simple list does that:

score=['bs_intro',
'bs_12b_0',
'bs_12b_1',
'bs_12b_2',
'reset_bar',
'bs_12b_3',
'bs_12b_4'
]

I added a command to reset the entropy bar pointer in the middle - and that's how you specify a song. I'll just repeat it without interrupt:

bsdic['bs_intro']=[ ['name','intro_0','scratch']]

bsdic['bs_12b_0']=[ ['plick','e_1bar_Maj_bs'], ['match_n','bs_12b_0',0], ['alt','bs_12b_0',0], ['match_n','bs_12b_0',2,'rentropy'],
['plick','sour_2bar_min_bs'],
['posit','bs_12b_0',0,12],['posit','bs_12b_0',3 ,14],
['chordit','bs_12b_0',0,7,'7','scratch'],['chordit','bs_12b_0',1,5,'7'],
['plick','e_2bar_turns']
]

bsdic['bs_12b_1']= [['altbs','bs_12b_0']]
bsdic['bs_12b_2']= [['altbs','bs_12b_0']]
bsdic['bs_12b_3']= [['altbs','bs_12b_0',[0,10]]]

bsdic['bs_12b_4']=[['rep','bs_12b_1',[5,7]],['rep','bs_12b_2',[0,2]],['rep','bs_12b_3',[3,8]], ['name','fin','scratch'] ]

score=['bs_intro',
'bs_12b_0',
'bs_12b_1',
'bs_12b_2',
'reset_bar',
'bs_12b_3',
'bs_12b_4'
]

It's very basic at this point with only a few regions etc. but it's a start. I won't post the lillypond score unless someone wants to see that but you can hear the results here.

Any questions?
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

As I was "composing" the song I discussed in my last comment I became aware that something important was missing. A blues lead isn't just lick, lick, lick, no matter how good the licks may be it gets to be a bit too much if you don't break them up from time to time by contrasting them with some other tickling of notes up and down the length of the neck. Playing scales or arpeggios to connect licks is often used to do this. They can be especially effective if licks are separated by some distance on the fretboard. In that case, a scale can be used to connect the last note of one lick to the first note of the next lick. So I decided I needed a way to tell lickmaker to connect two licks in a song with an appropriate scale or arpeggio. These are often called "runs".

There are several problems that need to be solved to do this.

1) You need to find the notes of a given scale that are between the notes you are trying to connect with the scale.

2) You don't want to only be able to use those notes in the natural order they fall between the scale- that tends to sound too much like you're just playing a scale - so different patterns of playing notes, in different order, sometimes repeating a note are needed.

3) You need to be able to expand or contract the set of notes selected so you end up with an appropriate number of notes for the amount of time you want them to play in- for now, I'm talking one bar worth of notes.

4) You need to be able to pick a rhythm pattern to play the scale or arpeggio with. You don't want to always play machine gun like 16 notes. You want different rhythm patterns to be available- for blues, some shuffle patterns often work well.

5) There's a connection between the rhythm pattern selected and the number of notes you need so 4) effects 3)

Now all of those are interesting problems and I'd be happy to talk more about any or all of them if anyone is interested but the problem I found most interesting in all of this is:

6) After the desired notes are selected you have to decide where to play them because a guitar, unlike a piano, often has multiple places where the same note can be played. So, if I want lickmaker to compose some scale run between two points it needs to come up with a reasonable way to play those notes. Unreasonable would be bouncing back and forth between the high and low end of the fretboard on alternate notes of the run- you want a more smooth transition of notes. You also don't want to just bounce up one string playing all the notes because that doesn't make best use of all your fingers.

Some example might be helpful at this point.

Let's say you want lickmaker to compose a minor blues scale run from e, (that the lowest e note on a guitar in lilypond speak) to e'' (e two octaves up from e,). Now guitar players typically know what patterns are available on a fretboard to play these notes but the general problem of how to choose where to play each note depends on a lot of different things and in the end amounts to personal choice. Let's say you want to play these notes:

['e,', 'g,', 'a,', 'bes,', 'ces', 'd', 'e', 'g', 'a', 'bes', 'b', "d'", "e'"]

There is only one place to play the "e," and one place to play the "g," but lots of places to play the "b".

Below, next to each note is a list containing a list showing the possibilities of where each note could be played. e.g. the e, note can only be played on the 6th string with an open fret. the g, can only be played on the 6th string at the 3rd fret. But there's a lot of places where the b note can be played.

e, [[6, 0]]
g, [[6, 3]]
a, [[5, 0], [6, 5]]
bes, [[5, 1], [6, 6]]
ces [[5, 2], [6, 7]]
d [[4, 0], [5, 5], [6, 10]]
e [[4, 2], [5, 7], [6, 12]]
g [[3, 0], [4, 5], [5, 10], [6, 15]]
a [[3, 2], [4, 7], [5, 12], [6, 17]]
bes [[3, 3], [4, 8], [5, 13], [6, 18]]
b [[2, 0], [3, 4], [4, 9], [5, 14], [6, 19]]
d' [[2, 3], [3, 7], [4, 12], [5, 17]]
e' [[1, 0], [2, 5], [3, 9], [4, 14], [5, 19]]

This problem had me for a while because I wanted to solve it in a general way that would work for all sorts of scales and arpeggios and it's kind of tricky because there is no one solution. The best choice of which notes to play depends on all sorts of things- for a run - where you're starting from and where you want to end up is important- but other things matter too.

After thinking about it for a while I realized that this is essentially a special case of the traveling salesman problem. i.e. how to schedule a route to x cities traveling the shortest distance. This is a bit different but the concept is similar.

One solution that is often desired by guitar players is to play the notes as much across the neck as possible. That is, keep the notes in the smallest lengthwise area of fretboard as possible. If that's what you want then you can often eliminate a lot of the note position choices and make the overall problem easier- sometimes the solution pops out of a fairly simple search like that. But not always.

Rather than complicate this comment with how that sort of search works I'll just move on to the general case and show one way, a heuristic way, of solving it in all? cases. In keeping with the spirit of the thread, I'm using a genetic heuristic to solve it.

This idea is to come up with a set of metrics that describe favorable or unfavorable solutions. For example, more that 3 notes on a given string might be unfavorable - so that gets penalized. An overall short distance between notes is a favorable metric. Playing open strings may or may not be favorable- you want to be able to select for that.

With metric in place, lickmaker just randomly picks a bunch of solutions from the possibility space. Then it computes how well each solution did. It keeps the best 50% and tosses the others. Then is uses the best solutions to randomly crate a new set of possible solutions to take the place of those that were tossed. Again it keeps the best 50% from the new and old solutions, and keeps repeating this until a stable best solution is found. So for our example:

e, [[6, 0]]
g, [[6, 3]]
a, [[5, 0], [6, 5]]
bes, [[5, 1], [6, 6]]
ces [[5, 2], [6, 7]]
d [[4, 0], [5, 5], [6, 10]]
e [[4, 2], [5, 7], [6, 12]]
g [[3, 0], [4, 5], [5, 10], [6, 15]]
a [[3, 2], [4, 7], [5, 12], [6, 17]]
bes [[3, 3], [4, 8], [5, 13], [6, 18]]
b [[2, 0], [3, 4], [4, 9], [5, 14], [6, 19]]
d' [[2, 3], [3, 7], [4, 12], [5, 17]]
e' [[1, 0], [2, 5], [3, 9], [4, 14], [5, 19]]

It came up with:

0 e, [6, 0]
1 g, [6, 3]
2 a, [6, 5]
3 bes, [5, 1]
4 ces [5, 2]
5 d [4, 0]
6 e [4, 2]
7 g [4, 5]
8 a [3, 2]
9 bes [3, 3]
10 b [3, 4]
11 d' [2, 3]
12 e' [2, 5]

Given some different priorities, Lickmaker came up with a perhaps more conventional choice:

0 e, [6, 0]
1 g, [6, 3]
2 a, [5, 0]
3 bes, [5, 1]
4 ces [5, 2]
5 d [4, 0]
6 e [4, 2]
7 g [3, 0]
8 a [3, 2]
9 bes [3, 3]
10 b [2, 0]
11 d' [2, 3]
12 e' [1, 0]

And if we go up another octave on our run using this set of notes;

['e,', 'a,', 'ces', 'e', 'g', 'a', 'bes', 'b', "d'", "e'", "g'", "a'", "bes'", "ces''", "d''", "e''"]

These are the possibilities of where each note can be played:

e, [[6, 0]]
a, [[5, 0], [6, 5]]
ces [[5, 2], [6, 7]]
e [[4, 2], [5, 7], [6, 12]]
g [[3, 0], [4, 5], [5, 10], [6, 15]]
a [[3, 2], [4, 7], [5, 12], [6, 17]]
bes [[3, 3], [4, 8], [5, 13], [6, 18]]
b [[2, 0], [3, 4], [4, 9], [5, 14], [6, 19]]
d' [[2, 3], [3, 7], [4, 12], [5, 17]]
e' [[1, 0], [2, 5], [3, 9], [4, 14], [5, 19]]
g' [[1, 3], [2, 8], [3, 12], [4, 17]]
a' [[1, 5], [2, 10], [3, 14], [4, 19]]
bes' [[1, 6], [2, 11], [3, 15], [4, 20]]
ces'' [[1, 7], [2, 12], [3, 16]]
d'' [[1, 10], [2, 15], [3, 19]]
e'' [[1, 12], [2, 17]]

And this is the solution lickmaker came up with:

0 e, [6, 0]
1 a, [6, 5]
2 ces [6, 7]
3 e [5, 7]
4 g [5, 10]
5 a [4, 7]
6 bes [4, 8]
7 b [4, 9]
8 d' [3, 7]
9 e' [3, 9]
10 g' [3, 12]
11 a' [2, 10]
12 bes' [2, 11]
13 ces'' [2, 12]
14 d'' [1, 10]
15 e'' [1, 12]

Now there's a bit more to it that this, there are other options available, other optimizations you could deem important but perhaps this is complicated enough for an introduction to the topic. It's a bit of AI technology buried in lickmaker to help it create sensible runs to play.
I like to imagine ...

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

[quote][/quote]Drilling a bit deeper into the problem of deciding where to play a given set of notes on a guitar fretboard:

Asking to play a couple of octaves of: a minor blues scale, i.e. these notes:
['a,', 'c', 'd', 'dis', 'e', 'g', 'a', "c'", "d'", "ees'", "e'", "g'", "a'"]

Turning on the mechanism that tries to find the smallest fret span (no of frets not actual length) that these notes can be played on makes short work of the problem.

Here are the possible places to play those note:

a, [[5, 0], [6, 5]]
c [[5, 3], [6, 8]]
d [[4, 0], [5, 5], [6, 10]]
dis [[4, 1], [5, 6], [6, 11]]
e [[4, 2], [5, 7], [6, 12]]
g [[3, 0], [4, 5], [5, 10], [6, 15]]
a [[3, 2], [4, 7], [5, 12], [6, 17]]
c' [[2, 1], [3, 5], [4, 10], [5, 15], [6, 20]]
d' [[2, 3], [3, 7], [4, 12], [5, 17]]
ees' [[2, 4], [3, 8], [4, 13], [5, 18]]
e' [[1, 0], [2, 5], [3, 9], [4, 14], [5, 19]]
g' [[1, 3], [2, 8], [3, 12], [4, 17]]
a' [[1, 5], [2, 10], [3, 14], [4, 19]]

Playing them on frets 5 to 8 is shorter fretboard span than playing them on 1 to 5. So the solution falls out:

a, [[6, 5]]
c [[6, 8]]
d [[5, 5]]
dis [[5, 6]]
e [[5, 7]]
g [[4, 5]]
a [[4, 7]]
c' [[3, 5]]
d' [[3, 7]]
ees' [[3, 8]]
e' [[2, 5]]
g' [[2, 8]]
a' [[1, 5]]

And in general I find I get decent solutions to where to play notes. But if you take an example like: play a couple of octaves of A Dorian scale from a, to a' . i.e. these notes:

['a,', 'a,', 'b', 'c', 'd', 'e', 'fis', 'g', 'a', 'b', "c'", "d'", "e'", "fis'", "g'", "a'"]

then LickMaker has these places to choose from to play those notes:

a, [[5, 0], [6, 5]]
a, [[5, 0], [6, 5]]
ces [[5, 2], [6, 7]]
c [[5, 3], [6, 8]]
d [[4, 0], [5, 5], [6, 10]]
e [[4, 2], [5, 7], [6, 12]]
fis [[4, 4], [5, 9], [6, 14]]
g [[3, 0], [4, 5], [5, 10], [6, 15]]
a [[3, 2], [4, 7], [5, 12], [6, 17]]
b [[2, 0], [3, 4], [4, 9], [5, 14], [6, 19]]
c' [[2, 1], [3, 5], [4, 10], [5, 15], [6, 20]]
d' [[2, 3], [3, 7], [4, 12], [5, 17]]
e' [[1, 0], [2, 5], [3, 9], [4, 14], [5, 19]]
fis' [[1, 2], [2, 7], [3, 11], [4, 16]]
g' [[1, 3], [2, 8], [3, 12], [4, 17]]
a' [[1, 5], [2, 10], [3, 14], [4, 19]]

If you select for the shortest fretboard fret spacing length then it quickly finds:

[[6, 5], [6, 5], [5, 2], [5, 3], [5, 5], [4, 2], [4, 4], [4, 5], [3, 2], [3, 4], [3, 5], [2, 3], [2, 5], [1, 2], [1, 3], [1, 5]]

If you turn that off and let it rely on its genetic heuristic then it finds:

[[6, 5], [6, 5], [6, 7], [5, 3], [5, 5], [5, 7], [4, 4], [4, 5], [4, 7], [3, 4], [3, 5], [3, 7], [2, 5], [2, 7], [1, 3], [1, 5]]

Both of which are not bad, in fact they may be fine solutions but they may not be what comes to mind when a guitar player thinks of A Dorian. Guitar players tend to learn patterns to play scales in. If you know 5 patterns and know how to move them around a fretboard then you can play any mode in any Major or minor key. But in the above examples, lickmaker wasn't concerned about how a guitar player might use patterns to help them figure out how to play a given scale- it was just trying to group the notes as it thought best.

Thinking about this I thought I'd add the notion of the 5 patterns that guitar players often use - I call it the CAGED system- it goes by other names and people don't label the patterns the same way. Sometimes the patterns are a bit different, etc. etc.

But I showed lickmaker the 5 patterns I tend to use- not linking the patterns to any key or mode (perhaps I'll do that at some point) and added a bonus to the genertic heuristics fitness function if the notes are played in a way that one of these patterns can be used.

With the pattern bonus in effect, lickmaker decided to play A Dorian notes in these positions:

[[6, 5], [6, 5], [6, 7], [6, 8], [5, 5], [5, 7], [4, 4], [4, 5], [4, 7], [3, 4], [3, 5], [3, 7], [2, 5], [2, 7], [2, 8], [1, 5]]

Which is more to my liking if no other factors are in play.

John Platko

Name: John Platko
Posts: 9411

Country: US
Print view this post

### Re: Developing a heuristic for evolving guitar blues licks

Y'all are WAY to smart for me. I just find the root chord and drop a standard blues scale on it. Need about 5 patterns up the whole neck. Works in bars for most stuff, and they're usually too drunk to get the subtleties anyway. FREE BIRD!!!!
A man who carries a cat by the tail learns something he can learn in no other way. - Mark Twain
The sky is falling! The sky is falling! - Chicken Little
I never go without my dinner. No one ever does, except vegetarians and people like that - Oscar Wilde

laklak
RS Donator

Name: Florida Man
Posts: 19641
Age: 65

Country: The Great Satan
Print view this post

PreviousNext

### Who is online

Users viewing this topic: No registered users and 1 guest