Creating emergent particles using a harmony search

Being a musician myself, this recipe is one that is close to my heart. Imagine a group of musicians with a base theme in mind. But, they've never played with each other, and as the song changes, they must adapt to the core tones with their instruments and their styles. The emulation of this adaptation is implemented using an algorithm called harmony search.

Getting ready…

We will need to define an objective function as a delegate in order to set it up before calling the function.

How to do it…

We will now implement the algorithm in a class:

  1. Create the HarmonySearch class:
    using UnityEngine;
    using System.Collections;
    
    public class HarmonySearch : MonoBehaviour
    {
    
    }
  2. Define the public inputs that are to be tuned:
    [Range(1, 100)]
    public int memorySize = 30;
    public int pitchNum;
    // consolidation rate
    [Range(0.1f, 0.99f)]
    public float consRate = 0.9f;
    // adjustment rate
    [Range(0.1f, 0.99f)]
    public float adjsRate = 0.7f;
    public float range = 0.05f;
    public int numIterations;
    [Range(0.1f, 1.0f)]
    public float par = 0.3f;
  3. Define a list of bounds. This is a Vector2, so x will represent the lowest bound and y the highest bound. The number of bounds must be equal to the number of pitches:
    public Vector2[] bounds;
  4. Define the private members for the algorithm:
    private float[,] memory;
    private float[] solution;
    private float fitness;
    private float best;
  5. Implement the initialization function:
    private void Init()
    {
        memory = new float[memorySize, pitchNum];
        solution = new float[memorySize];
        fitness = ObjectiveFunction(memory);
    }
  6. Start defining the function for creating harmony:
    private float[] CreateHarmony()
    {
        float[] vector = new float[pitchNum];
        int i;
        // next steps
    }
  7. Iterate through the number of pitches (instruments):
    for (i = 0; i < pitchNum; i++)
    {
        // next steps
    }
  8. Compute the new number of the possible new harmonies, given a random value:
    if (Random.value < consRate)
    {
        int r = Random.Range(0, memory.Length);
        float val = memory[r, i];
        if (Random.value < adjsRate)
            val = val + range * Random.Range(-1f, 1f);
        if (val < bounds[i].x)
            val = bounds[i].x;
        if (val > bounds[i].y)
            val = bounds[i].y;
        vector[i] = val;
    }
  9. Define the value in case it needs to be randomized:
    else
    {
        vector[i] = Random.Range(bounds[i].x, bounds[i].y);
    }
  10. Retrieve the new vector:
    return vector;
  11. Define the function that will make everything work:
    public float[] Run()
    {
        // next steps
    }
  12. Initialize the values:
    Init();
    int iterations = numIterations;
    float best = Mathf.Infinity;
  13. Call the previous functions and computations to find the best list of pitches:
    while (iterations != 0)
    {
        iterations--;
        float[] harm = CreateHarmony();
        fitness = ObjectiveFunction(harm);
        best = Mathf.Min(fitness, best);
        memory = harm;
    }
  14. Return the best list of pitches:
    return

How it works…

The algorithm initializes all the values, given the public inputs and its inner members. It iterates several times in order to find the best list of pitches among the set of bounds and the different tones created using the previously defined objective function.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.220.22