Sound2Light (S2L)

   Print  Previous  Next

Functionality

As described above, sound data refers to frequency-based data. First of all, the function GetSoundLevel retrieves the volume of the two audio channels (stereo sound). The value returned ranges  from 0 to 255, the lowest and highest level possible, respectively.

Moreover, other available data is frequency values. They are stored in the fields SOUND_DATA_LEFT and SOUND_DATA_RIGHT, which are both of the data type int. There are up to 511 values and each describes the volume of a well-defined frequency.

The length-operator of the fields tells how much valid data they contain. A check may be necessary and then just take the values that are actually available/provided to have a proper effect. But  it is secure to always assume 511 present values.

In contrast to other dynamic fields, in MADRIX Script those fields will not grow because their size is fixed. Trying to get an invalid element, always results in 0.

 

The First S2L Example

The following example first of all selects a color depending on the volume of the music, which is then used as background color. Lines will be drawn onto the matrix that indicate the average volume of each single frequency.

const color LEFT_CHANNEL = {255, 0, 0, 128};

const color RIGHT_CHANNEL= {0, 255, 0, 128};

 

void InitEffect()

{

}

 

int avgFrequ(int field[])

{

    int result;

 

    //to avoid division by zero later on

    if(field.length > 0)

    {

        for(int i = 0; i < field.length; i++)

            result += field[i];

 

        result /= field.length;

    }

 

    return(result);

}

 

void RenderEffect()

{

    int valL = GetSoundLevel(0); //left channel

    int valR = GetSoundLevel(1); //right channel

    color c = {valL, valR, (valL * valR) % 255, (valR + valL) / 2, 0};

 

    float iHL = (float)avgFrequ(SOUND_DATA_LEFT) / (float)MAX_FREQUENCY_VOLUME;

    float iHR = (float)avgFrequ(SOUND_DATA_RIGHT) / (float)MAX_FREQUENCY_VOLUME;

 

    Clear(c);

    DrawVectorLine(LEFT_CHANNEL, 0.0, iHL, 1.0, iHL);

    DrawVectorLine(LEFT_CHANNEL, iHL, 0.0, iHL, 1.0);

 

    DrawVectorLine(LEFT_CHANNEL, 0.0, 1.0-iHL, 1.0, 1.0-iHL);

    DrawVectorLine(LEFT_CHANNEL, 1.0-iHL, 0.0, 1.0-iHL, 1.0);

 

    DrawVectorLine(RIGHT_CHANNEL, 0.0, iHR, 1.0, iHR);

    DrawVectorLine(RIGHT_CHANNEL, iHR, 0.0, iHR, 1.0);

 

    DrawVectorLine(RIGHT_CHANNEL, 0.0, 1.0-iHR, 1.0, 1.0-iHR);

    DrawVectorLine(RIGHT_CHANNEL, 1.0-iHR, 0.0, 1.0-iHR, 1.0);

}

 

 

Explanation:

First, several constants are declared. They are used as colors to draw lines for the right and the left channel.

The function avgFrequ is an assistant function. It iterates through a given field of integer values and returns the average of all given values. If the field is empty, 0 is returned.

The function RenderEffect stores the volume of the left and the right sound channel. This is done for performance reasons. Calling a function needs more time than using a variable which is done in the third line. Here, a color is build up defined by the volume levels. This color is used as background color later on.

Afterwards, for both the left and the right sound channel the average volume is calculated. In the same step, the results are divided by the maximal possible value in order to break them down to a value between 0.0 and 1.0. Then, the matrix is cleared with the color calculated before and at last, horizontal and vertical lines are drawn onto the matrix. Hereby, the vector version of the draw function is used to draw lines across the whole matrix using the level described by the average volume level.

 

The Second S2L Example

Another nice effect based on the same data is done by the following RenderEffect function. It uses a black background and draws the lines with the calculated color.

const color LEFT_CHANNEL = {255, 0, 0, 128};

const color RIGHT_CHANNEL= {0, 255, 0, 128};

 

void InitEffect()

{

}

 

int avgFrequ(int field[])

{

    int result;

 

    //to avoid division by zero later on

    if(field.length > 0)

    {

        for(int i = 0; i < field.length; i++)

            result += field[i];

 

        result /= field.length;

    }

 

    return(result);

}

 

void RenderEffect()

{

    int valL = GetSoundLevel(0);

    int valR = GetSoundLevel(1);

    color c = {valL, valR, (valL * valR) % 255, (valR + valL) / 2, 0};

 

    float iHL = (float)avgFrequ(SOUND_DATA_LEFT) / (float)MAX_FREQUENCY_VOLUME;

    float iHR = (float)avgFrequ(SOUND_DATA_RIGHT) / (float)MAX_FREQUENCY_VOLUME;

 

    Clear();

 

    DrawVectorLine(c, 0.0, iHL, 1.0, iHL);

    DrawVectorLine(c, iHL, 0.0, iHL, 1.0);

 

    DrawVectorLine(c, 0.0, 1.0-iHL, 1.0, 1.0-iHL);

    DrawVectorLine(c, 1.0-iHL, 0.0, 1.0-iHL, 1.0);

 

    DrawVectorLine(c, 0.0, iHR, 1.0, iHR);

    DrawVectorLine(c, iHR, 0.0, iHR, 1.0);

 

    DrawVectorLine(c, 0.0, 1.0-iHR, 1.0, 1.0-iHR);

    DrawVectorLine(c, 1.0-iHR, 0.0, 1.0-iHR, 1.0);

}