Sign in to follow this  
Followers 0
litlmike

How to Represent a Circular Relationship Programmatically?

6 posts in this topic

I am not sure this was the best way to describe the issue, but it was the best I could come up with. I am trying to create a 'Circular Relationship Programmatically", in that I have values that are seperated by 12 'degrees' so that each value has a relationship with every other value by a number of 'degrees'. For those that are familiar with musical notes, specifically I am talking about the notes on the 12 Tone Scale (chormatic scale). For those that are not familiar with musical notation, you can think of it like this:

#include <Array.au3>
Local $a12ToneScale[13] = [12, "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"] ;Array that has all notes on the 12 Tone Scale
_ArrayDisplay ($a12ToneScale, "$a12ToneScale")oÝ÷ ØêÛzÛ^¯'­Êjv¥²ay(~Ø^ºÞ«b¢{!¬r*ܺV«jȧêÞjëh×6Local $aArray[7][12] = [["", ""]]

$aArray[3][0] = "A"
$aArray[2][1] = "A#"
$aArray[1][2] = "B"
$aArray[0][3] = "C"
$aArray[1][4] = "C#"
$aArray[2][5] = "D"
$aArray[3][6] = "D#"
$aArray[4][5] = "E"
$aArray[5][4] = "F"
$aArray[6][3] = "F#"
$aArray[5][2] = "G"
$aArray[4][1] = "G#"

_ArrayDisplay ($aArray, "$aArray")

So if you look at $a12ToneScale[1] it is 1 'degree' away from $a12ToneScale[2]. $a12ToneScale[2] is 1 degree away from $a12ToneScale[3], but you don't want to think in 'negative degrees', so $a12ToneScale[2] is not 1 degree away from $a12ToneScale[1], $a12ToneScale[2] would be 11 'degrees' away from $a12ToneScale[1]. Instead, $a12ToneScale[13] is 1 'degree' away from $a12ToneScale[1].

What I am trying to figure out, is how to represent these relationships in the form of lines of code. With that, I could create scripts that could interact with this relationship, based upon paramaters. So, if I wanted to find the 3rd degree from "C" ( $a12ToneScale[4] ), it would return "D#" which is $a12ToneScale[7]. The difficuly I am having is how would I find the 5th degree of "G#" ( $a12ToneScale[13] ), which would be "C#" ( $a12ToneScale[5] ). Of course, simply adding a number beyond the Ubound of the linear array would just give me an error, "Array variable has incorrect number of subscripts or subscript dimension range exceeded."

Or, if I had a set of rules that said a major scale is composed of these degrees of seperation, it could theoretically construct a major scale from the relationship.

Any help is appreciated.

Thanks

Share this post


Link to post
Share on other sites



$Note = DegreesFromNote("C", 0) ;Returns C
ConsoleWrite($Note & @CRLF)

$Note = DegreesFromNote("C", 12) ;Returns C
ConsoleWrite($Note & @CRLF)

$Note = DegreesFromNote("C", 24) ;Returns C
ConsoleWrite($Note & @CRLF)

$Note = DegreesFromNote("C", -12) ;Returns C
ConsoleWrite($Note & @CRLF)

$Note = DegreesFromNote("C", -24) ;Returns C
ConsoleWrite($Note & @CRLF)

$Note = DegreesFromNote("C", 8) ;Returns G#
ConsoleWrite($Note & @CRLF)

$Note = DegreesFromNote("C", -6) ;Returns F#
ConsoleWrite($Note & @CRLF)


;Note = Note name
;Degrees = Retrieve note this many steps away
Func DegreesFromNote($sNote, $iDegrees)
    Local $NumElements = 12
    
    Local $a12ToneScale[$NumElements] = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"] ;Array that has all notes on the 12 Tone Scale

    ;Create dictonary to store relation between note and array element
    Local $Obj = ObjCreate("Scripting.Dictionary")
    For $X = 0 to $NumElements-1
        $Obj($a12ToneScale[$X]) = $X
    Next

    ;Check if note is valid
    If $obj.Exists($sNote) Then
        $Index = $Obj($sNote)
        
        $NewIndex = $Index + $iDegrees
        
        ;If the desired position is beyond last element of the array, wrap it around
        If $NewIndex > ($NumElements-1) Then
            $NewIndex = Mod($NewIndex,$NumElements)
        
        ;If the desired position is before the first element, wrap around
        ElseIf $NewIndex < 0 Then
            $NewIndex = $NumElements + Mod($NewIndex,$NumElements)
        EndIf
        
        Return $a12ToneScale[$NewIndex]
    Else
        Return SetError(1,0,"")
    EndIf
EndFunc

Share this post


Link to post
Share on other sites

...

Now that... is cool. I have not seen the use of ObjCreate("Scripting.Dictionary") before. Here is what I gather from reading the MSDN on "Scripting.Dictionary". It is an associative array, which it seems like associative arrays are just an array, except where you don't have to assign a value to an 'index', but rather you can associate any element value with any other value. So a name with a phone number, or in this case a Letter with a number. So I guess you could use this to assign A-Z with the values 1-26. Is that about right? Also, I included some comments into your code to 'think out loud' and try and explain what I think you are doing here. It would be great to get some feedback to see if I understand what you are doing here. I see how this can be helpful in other projects.

Thanks.

Func _DegreesFromNote($sNote, $iDegrees)
    ;Note = Note name
    ;Degrees = Retrieve note this many steps away
    Local $iNumElements = 12
    Local $iIndex, $iNewIndex
    Local $a12ToneScale[$iNumElements] = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"] ;Array that has all notes on the 12 Tone Scale

    ;Create dictonary to store relation between note and array element
    Local $Obj = ObjCreate("Scripting.Dictionary")
    For $iCC = 0 To $iNumElements - 1
        $Obj($a12ToneScale[$iCC]) = $iCC ;Assigns an Integer Value ('Item') to each 'Key'
    Next
    
    ;Check if note is valid (Exists in the Dictionary)
    If $Obj.Exists($sNote) Then
        $iIndex = $Obj($sNote) ;Assign an Index Value to the associated 'Item' Location of the 'Key' ($sNote in this case)
        $iNewIndex = $iIndex + $iDegrees ;Assigns $iNewIndex the associated 'Item' Location for the 'Key' (Note that is $iDegrees away)

        ;If the desired position is beyond last element of the array, wrap it around
        If $iNewIndex > ($iNumElements - 1) Then
            $iNewIndex = Mod($iNewIndex, $iNumElements) ;$iNewIndex becomes the remainder between $iNewIndex (the Root Note + $iDegrees) and $iNumElements (12)
            ;This represents the relation in degrees from the Root Note to the Note $iDegrees away.
            
            ;If the desired position is before the first element, wrap around (Works backwards, or in Negative Degrees)
        ElseIf $iNewIndex < 0 Then
            $iNewIndex = $iNumElements + Mod($iNewIndex, $iNumElements)
        EndIf

        Return $a12ToneScale[$iNewIndex]
    Else
        Return SetError(1, 0, "")
    EndIf
EndFunc   ;==>_DegreesFromNote

Share this post


Link to post
Share on other sites

My head hurts now... and I remember why I dropped band class in Jr. High. Being a geek, I surely would have tried mixed my world of music with my world of computers, and ended up in an institution at some point.

More power to ya!


My UDFs: ExitCodes

Share this post


Link to post
Share on other sites

My head hurts now... and I remember why I dropped band class in Jr. High. Being a geek, I surely would have tried mixed my world of music with my world of computers, and ended up in an institution at some point.

More power to ya!

I am almost at the point. Btw, in your signature, it would be more effective if you used the actual characters from the movie, unless Riddler makes a guest appearance, I am pretty sure it was the Joker.

Share this post


Link to post
Share on other sites

Here is what my code does.

Since the order of the elements is critical, we have to keep the values in an array. The Scripting Dictionary wasn't necessary but it avoids us having to loop through the scale array to find the desired note. I guess its not a big deal with such a small array.

Next we take the degrees passed to the function and convert them from relative to absolute. We do that by finding the note key name in the associative array and saving its position.

Lets say we want to find 10 degrees from "C". "C" is at element 3. Element 3 plus 10 degrees would give us 13 which higher than than the largest element (11). The Mod() function will perform division and return the remainder. The size of the array is our constant - 12.

So we do Mod(13,12) which returns 1, which happens to be the element 10 degrees from "C".

Clear as mud?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0