# Dynamic Loop - Script



## jorgefernando86 (Aug 16, 2020)

Hello friends
I am a beginner in Kontakt script programming, and I have used loops in my performances. However, I cannot develop anything that recognizes chords.
Example: I have two samples of loops from below, one in A major, one in A minor. If I run A major on my keyboard, let the kontakt play the loop sample for A major. If I run A minor, let the kontakt play the loop sample for A minor.
Did you understand?
I'm not very good with English and I'm using the translator.
I thank you all!!


----------



## jbuhler (Aug 18, 2020)

I don’t think I understand what you want to do. But Kontakt will not change major to minor. It can only pitch shift the full sample. (So A minor to G minor, for instance). I mean you could develop a Kontakt instrument that did what you seem to want but you’d have to do quite a bit of programming to pull it off. But I might not be understanding what you are trying to do.


----------



## berto (Aug 18, 2020)

I think the OP wants to trigger major and minor loops by playing major and minor chords, so he wants to be able to do a chord detection script... so funny because i'm kind of looking for the same thing with my division script problem...


----------



## Suganthan (Aug 20, 2020)

Well, there should be a similar script done by someone already. But let me share my take on it.

This is a simple chord detection script, within 50 ms, it detects the root note and chord type(only major and minor). Inversions work too. It is based on KEY_DOWN_OCT, so the user can play the chords anywhere on the keyboard, the result will be the same.

Also, the group start options are not manipulated.

If a major chord is detected, the play_note triggers the lowest first octave in the corresponding key.
If a major chord is detected, the play_note triggers the lowest second octave in the corresponding key.

So, it is required to map the loop samples accordingly.



```
on init
  message("")
  make_perfview
  set_ui_height(4)
  declare ui_value_edit $Chrd_Wait(1, 100, 1)
  declare $i
  declare $note_counter := 0
  declare %note_array[3]
  declare $new_ncb
  declare %intervals[2]
  declare !note_name[12]
  !note_name[0] := "C "
  !note_name[1] := "Db"
  !note_name[2] := "D "
  !note_name[3] := "Eb"
  !note_name[4] := "E "
  !note_name[5] := "F "
  !note_name[6] := "Gb"
  !note_name[7] := "G "
  !note_name[8] := "Ab"
  !note_name[9] := "A "
  !note_name[10] := "Bb"
  !note_name[11] := "B "
  $Chrd_Wait := 50
end on

on note
  ignore_event($EVENT_ID)
  message("")
  $new_ncb := $NI_CALLBACK_ID
  $i := 0
  $note_counter := 0
  while ($i<12 and ($note_counter<3))
    if (%KEY_DOWN_OCT[$i]=1)
      %note_array[$note_counter] := $i
      inc($note_counter)
    end if
    inc($i)
  end while
  wait($Chrd_Wait)
  if ($new_ncb=$NI_CALLBACK_ID and ($note_counter=3))
    sort(%note_array,0)
    $i := 0
    while ($i<2)
      %intervals[$i] := %note_array[$i+1]-%note_array[$i]
      inc($i)
    end while
    select (%intervals[0])
      case 3
        select (%intervals[1])
          case 5
            play_note(%note_array[2],$EVENT_VELOCITY,0,-1)
            message(!note_name[%note_array[2]] & " | major chord")
          case 4
            play_note(12+%note_array[0],$EVENT_VELOCITY,0,-1)
            message(!note_name[%note_array[0]] & " | minor chord")
        end select
      case 4
        select (%intervals[1])
          case 3
            play_note(%note_array[0],$EVENT_VELOCITY,0,-1)
            message(!note_name[%note_array[0]] & " | major chord")
          case 5
            play_note(12+%note_array[2],$EVENT_VELOCITY,0,-1)
            message(!note_name[%note_array[2]] & " | minor chord")
        end select
      case 5
        select (%intervals[1])
          case 4
            play_note(%note_array[1],$EVENT_VELOCITY,0,-1)
            message(!note_name[%note_array[1]] & " | major chord")
          case 3
            play_note(12+%note_array[1],$EVENT_VELOCITY,0,-1)
            message(!note_name[%note_array[1]] & " | minor chord")
        end select
    end select
  end if
end on
```

Here is the uncompiled sublime ksp version.


```
define MAX_CHORD_NOTES := 3      // Three note chord detection
define OCTAVE := 12     // According to this script, the minor loop samples are placed on the second lowest octave

on init
    message("")
    make_perfview
    set_ui_height(4)

        declare ui_value_edit Chrd_Wait (1, 100, 1)

        declare i
        declare note_counter := 0
        declare note_array [MAX_CHORD_NOTES]
        declare new_ncb
        declare intervals [MAX_CHORD_NOTES-1]

        declare !note_name[] := ("C ","Db","D ","Eb","E ","F ","Gb","G ","Ab","A ","Bb","B ")

        Chrd_Wait := 50

end on


on note
    ignore_event($EVENT_ID)
    message ("")

    new_ncb := $NI_CALLBACK_ID     // new_ncb always has the latest $NI_CALLBACK_ID that is just processed

    i := 0
    note_counter := 0

    while ( i < 12 and note_counter < MAX_CHORD_NOTES )

        if (KEY_DOWN_OCT [i] = 1 )

            note_array [note_counter] := i
            inc(note_counter)
        end if

        inc (i)
    end while

    wait(Chrd_Wait)

    if (new_ncb = $NI_CALLBACK_ID and note_counter = MAX_CHORD_NOTES)     // if this is the latest key note pressed and sufficient amount of keys are pressed
       
        sort (note_array, 0)    // whatever order user presses the three notes, it gets sorted in ascending order

        i := 0    //
        while (i < MAX_CHORD_NOTES-1)
            intervals [i] := note_array [i+1] - note_array [i]
            inc(i)
        end while

        select (intervals[0])     // interval between note_array[0] and note_array[1]
           
            case 3

                select (intervals[1])     // interval between note_array[1] and note_array[2]
                    case 5     // Root note 2 = major chord
                        play_note (note_array [2], $EVENT_VELOCITY, 0, -1)
                        message (note_name [note_array [2]] &  " | major chord")
                    case 4     // Root note 0 = minor chord
                        play_note (OCTAVE + note_array [0], $EVENT_VELOCITY, 0, -1)
                        message (note_name [note_array [0]] &  " | minor chord")
                end select

            case 4

                select (intervals[1])
                    case 3     // Root note 0 = major chord
                        play_note (note_array [0], $EVENT_VELOCITY, 0, -1)
                        message (note_name [note_array [0]] &  " | major chord")
                    case 5     // Root note 2 = minor chord
                        play_note (OCTAVE + note_array [2], $EVENT_VELOCITY, 0, -1)
                        message (note_name [note_array [2]] &  " | minor chord")
                end select

            case 5

                select (intervals[1])
                    case 4     // Root note 1 = major chord
                        play_note (note_array [1], $EVENT_VELOCITY, 0, -1)
                        message (note_name [note_array [1]] &  " | major chord")
                    case 3     // Root note 1 = minor chord
                        play_note (OCTAVE + note_array [1], $EVENT_VELOCITY, 0, -1)
                        message (note_name [note_array [1]] &  " | minor chord")
                end select
        end select
    end if

end on
```


----------



## berto (Aug 20, 2020)

I did a similar script using ENGINE_UPTIME instead of wait, but the problem i have, i can't detect more than a specified set of notes. Like yours, 3, or more, but they need to be defined. If the user plays a different number of notes each time, it does not work...


----------



## jorgefernando86 (Aug 20, 2020)

Hello friends Thank you very much for your help. It is rewarding to be part of this group. I managed to get the result from the following script:


> on init
> declare ui_label $chord_name(2, 1) {{{{{Note + mode{{{}
> declare ui_button $start
> declare !note_names[12]
> ...


----------



## Suganthan (Aug 20, 2020)

> I need to make it play until another note is released or the stop button is pressed



Maybe use a sustain pedal trigger?



> If the user plays a different number of notes each time


@berto What’s happening in your on note callback? If any note is played, the first note can wait for a specific time (to give user time to input others) . According to how many notes user presses, you distribute the voices. If user presses just 2 notes, the total voices could be equally distributed to two maybe?


----------



## berto (Aug 21, 2020)

```
on note

            if($ENGINE_UPTIME>=$last_note_time+ $TIME_GAP) {$TIME_GAP is a knob}
                $counter:=0
            else
                    inc($counter)     
            end if
    
            %chord[$counter]:=$EVENT_NOTE

            if($counter=$CHORDS_NOTES-1)  {if the chord with set notes is completed - $CHORDS_NOTES is a knob}
                    
                                sort(%chord,0)   {sorting in order}

                                        {blablabla - chord detection}
                $counter:=0
            end if
        
            $last_note_time:=$ENGINE_UPTIME
end on
```

That's basically what happens, but I'm not sure how to avoid if($counter=$CHORDS_NOTES-1) and leave it open to any number of notes...


----------



## Suganthan (Aug 21, 2020)

berto said:


> if($counter=$CHORDS_NOTES-1) and leave it open to any number of notes...



If I understand correctly, and the problem is distributing the voices among variable user input note numbers ( $count ) , how about this?

```
Select ($count)

     case 1 
        {user pressed one note, so distribute all voices to this note, in octave}

     case 2
        {Distribute voices for root and fifth}

     case 3
        {chord detect and distribute voices}

     Case 4 {or more }
        {complex chord detection and distribute voices}

end select
```

Instead of if($counter=$CHORDS_NOTES-1) ?


----------



## jorgefernando86 (Aug 21, 2020)

Hello friends.
does anyone know how to solve this problem?
The events are embolando, when played respectively.

"if ($ played_chord mod 12> = 0 and ($ played_chord / 12 = 0))
$ do: = play_note (0, $ EVENT_VELOCITY, 0, -1) {{{{CHORD MAJOR}
change_tune ($ do, $ played_chord mod 12 * 100000,0)
else
if ($ played_chord / 12 = 1)
$ do: = play_note (1, $ EVENT_VELOCITY, 0, -1) {{{CHORD MINOR}
change_tune ($ do, $ played_chord mod 12 * 100000,0)
end if "

How do I get the event to end when another one is released?


----------



## Suganthan (Aug 21, 2020)

jorgefernando86 said:


> How do I get the event to end when another one is released?


So when the new chord is pressed, the already running voices (chor) should stop. Right? Adding a note_off($do) in on note should do the trick.


```
on note

note_off ($do) {Previous note turn off}

ignore_event($EVENT_ID)
...
...
...
```


----------



## jorgefernando86 (Aug 26, 2020)

Hello Friend I believe it didn't work ... because the chord sound stopped immediately. Or I didn't know how to add this text to the script ...


----------



## Suganthan (Aug 26, 2020)

jorgefernando86 said:


> because the chord sound stopped immediately. Or I didn't know how to add this text to the script ...



Did you add `note_off ($do)` in the top or at the bottom? It is supposed to be at the top, inside the on note callback.


----------



## jorgefernando86 (Jun 23, 2022)

hello companions

Sorry to dig up this topic, however, this topic brought a new challenge to my script development.
Since the KEY_DOWN_OCT causes the event to be expanded to the entire keyboard, is there a way to determine that the chord reading occurs in only a specific region of the keyboard, and not the entire keyboard?
Thanks in advance to all


----------



## berto (Jun 23, 2022)

jorgefernando86 said:


> hello companions
> 
> Sorry to dig up this topic, however, this topic brought a new challenge to my script development.
> Since the KEY_DOWN_OCT causes the event to be expanded to the entire keyboard, is there a way to determine that the chord reading occurs in only a specific region of the keyboard, and not the entire keyboard?
> Thanks in advance to all


add 
if(EVENT_NOTE> 'value' and EVENT_NOTE< 'value') 
< your chord recognition script here>
end if 

should work, on top of my head


----------



## jorgefernando86 (Jun 24, 2022)

berto said:


> add
> if(EVENT_NOTE> 'value' and EVENT_NOTE< 'value')
> < your chord recognition script here>
> end if
> ...


I already tried this alternative. however, somehow, when the chord notes are typed in succession, the script somehow recognizes the chord. And in my case, I need to do the harmony with my left hand and the melody with my right hand. However, when I make the melody I mess up the whole harmony... Is there any other way to limit the scope of this script?


----------



## berto (Jun 24, 2022)

Then you might want to use KEY_DOWN instead


----------



## polypx (Jun 25, 2022)

You probably want to define a split point, and only process notes that occur below that. ie. for middle C split point, you would run your script only if EVENT_NOTE < 60


----------



## Venturieri (Jul 23, 2022)

jorgefernando86 said:


> I already tried this alternative. however, somehow, when the chord notes are typed in succession, the script somehow recognizes the chord. And in my case, I need to do the harmony with my left hand and the melody with my right hand. However, when I make the melody I mess up the whole harmony... Is there any other way to limit the scope of this script?


Resolveu?


----------



## semiono (Sep 9, 2022)

Suganthan said:


> ```
> on init
> message("")
> make_perfview
> ...


There is checks maj/min third and + one = 3
There is no way to add another chord here. How to add 7th or 6th?


jorgefernando86 said:


> ```
> on init
> declare ui_label $chord_name(2, 1) {{{{{Note + mode{{{}
> declare ui_button $start
> ...


This is used change_tune it's distorts the sound a lot in high numbers.
Please, have anyone more script to more chords carry on to chords 7th.
Please, I'm newbe and stupid))
Some axample to carry on like 7th or sus4?
How to mix this two beautiful sripts together?
------->8-----------------
LOL I found this!

```
$do := play_note($played_chord+12,$EVENT_VELOCITY,0,-1){Loop Major}
```
There $played_chord mean index note! Very happy!


----------

