# Is there a way to delay CCs on an on controller callback?



## Thonex (Feb 29, 2008)

Is there a way to delay CCs on an on controller callback using the wait() statement?

Basically, I'm delaying notes and I want to also delay their accompanying CC info by the same amount.

It seems as though it is not possible? 

Any tricks around this?

Thanks,

T


----------



## Big Bob (Feb 29, 2008)

Hi Andrew,

Are you trying to delay sending it on to subsequent scripts and/or the synth engine or are you trying to delay its effect within the current script?

For the former, couldn't you do something like this?


```
on controller
  if CC_NUM = ccn
    saveit := CC[ccn]
    ignore_controller
    wait(delay)
    set_controller(ccn,saveit)
  end if
end on
```

For the latter, just put your action routine after the wait(), No?

Or, am I just not understanding the question :oops: 

God Bless,

Bob


----------



## polypx (Mar 1, 2008)

Thanks for this, I had given up trying to do the same thing... I also kept getting errors, and had somehow completely forgotten the "ignore_controller" line.


EDIT: Whoops, nope. It still doesn't work for me. The problem is that "saveit" needs to be a polyphonic variable, otherwise it gets changed before the wait time is finished, and you get jumps in the value. BUT, you can't use a polyphonic variable in a controller callback.

Thonex, did you have successful results?

cheers
Dan


----------



## Nickie Fønshauge (Mar 1, 2008)

You can create your own "polyphonic" *saveit* as a (array) queue with a "read" and a "write" pointer. That should work, when the wait time is the same for each CC message.


----------



## Big Bob (Mar 1, 2008)

> EDIT: Whoops, nope. It still doesn't work for me. The problem is that "saveit" needs to be a polyphonic variable, otherwise it gets changed before the wait time is finished, and you get jumps in the value.



I must admit that I was thinking that the 'delay' would be very short relative to the rate of arrival of new CC values. If that isn't the case and you need to retain the entire CC stream (but just shifted in time), then Nikie's suggestion will do the job nicely (although you may need multiple arrays if more than 512 CC values can occur during the delay interval). 

If you don't need to retain all the CC values that occur during the delay, you could do something like this:

```
on controller 
  if CC_NUM = ccn
    ignore_controller
    if saveit # -1
      exit
    else
       saveit := CC[ccn]
    end if 
    while saveit # -1
       wait(delay) 
       temp := CC[ccn]
       set_controller(ccn,saveit) 
       if saveit = temp
          saveit := -1
       else
          saveit := temp
       end if
    end while
  end if
  exit
end on
```

Assuming that saveit was pre-initilized to -1, the above would output one CC event per delay interval and the value would always be what it was 'delay' seconds ago (I think :lol: ).


----------



## polypx (Mar 1, 2008)

> Just out of curiosity, why are you needing to delay the 'controller curve'?



I wanted to get an effect where if you moved one controller, let's say the mod wheel.. then another controller would do the same thing a certain time later... which could be routed to something else.... so in a very simplistic example: if group 1's filter was adjusted by the mod wheel, a filter on group 2 could mimic it a rhythmic value later using a "delayed controller".

I wasn't sure how useful it would be, as I said earlier I did give up on it at one point. 
This thread just re-kindled the idea.


I hope you have many many more 'good days' Bob... even in the short time I've known you on this forum you've taught me so much, and your generous spirit is very much appreciated.

cheers
Dan


----------



## Thonex (Mar 3, 2008)

polypx @ Sat Mar 01 said:


> Hi Bob
> 
> For my purposes (not sure about Thonex), I was trying to delay the entire "curve" of a controller... so I think Nickie's array method might be the only solution. (Though I'm a bit unsure how it would work, since I can't guess in advance how big the array might need to be... and might need some sort of 'delta time' to keep the curve shape?).
> 
> ...



Hi I'm back... yes... I was trying to keep the same "curve" of cc info and delay it by precisely the same amount as I would delay the notes. Like a Digital delay that captures expression also.

I'm guessing if Nickie and Bob are suggesting a saved cue list... then that probably* is* the way to go. :D 

I think I know how I'm going to do it. I think a 256 (128x2) array should be enough to handle my needs. I'm guessing it could look like this (in plain English) *if *set_controller actually works in a controller CB:


on controller
ignore_cc
if CC1 is touched then inc(counter)
if counter >256 then counter = 1
%Save_cc[counter] = CC1
wait (1 second)
set_controller (1, %save_cc[counter])

no?


----------



## Thonex (Mar 3, 2008)

ok... I think set_controller can't be used in a controller CB.... is this right? Otherwise... why is this not working??:


```
on init
  
   declare $CC_Counter_A
   declare %CC_Save_A [256]
   
   
end on


on controller
   
   ignore_controller
   if (%CC_TOUCHED[11] = 1) {for CC 11}
      inc ($CC_Counter_A)
      if ($CC_Counter_A >256)
         $CC_Counter_A := 1
      end if
      CC_Save_A[$CC_Counter_A] := %CC[11]
      wait ( 1000000)
      set_controller (11, %CC_Save_A[$CC_Counter_A])
   end if
end on
```

This is supposed to delay CC11 by 1 second.... continuous data up to 256 resolution per second. I can't see why it's not working unless set_controller can't be used inside a controller CB. That's my hunch.

Cheers,

T


----------



## Tod (Mar 3, 2008)

Hi Thonex, at this point I'm not sure why it's not working but set_controller is supposed to work in all callbacks. :? 

Tod


----------



## Tod (Mar 3, 2008)

Could it be possible that "ignore_controller" should come after you've saved the variable? :? :?


----------



## Thonex (Mar 3, 2008)

Ok... it's working but not correctly... or logically. 

I put the K2 Midi Monitor script after the code above to monitor what going on. It seems to update only the last CC ... or if I play a CC sweep for more than a second, it latches on... but seems to latch on with real time values. 

So... I tried making the $Count var a polyphonic Var... but I don't think KSP liked it... it gave me errors.... but when I got rid of the "polyphonic" at least it didn't give me errors.

So far as I can see, I see the CC CB reacting like a a note on CB but without the capability to use poly vars.

Could this be the problem? and if so... do any of you geniuses have any ideas for a work around?

Cheers,

T


----------



## Thonex (Mar 3, 2008)

Tod @ Mon Mar 03 said:


> Could it be possible that "ignore_controller" should come after you've saved the variable? :? :?



will try.... hold on

[EDIT] nope... doesn't make a difference.


----------



## Thonex (Mar 3, 2008)

I tried a variation without using CC_TOUCH just to make sure that wasn't interfering and it didn't help either.
on controller


*on controller*
```
```
```*select* ($CC_NUM)
`````````
``````*case* 11
`````````ignore_controller
`````````*if* (%CC_TOUCHED[11] = 1) _{for CC 11}_
````````````inc ($CC_Counter_A)
````````````*if* ($CC_Counter_A >= 500)
```````````````$CC_Counter_A := 1
````````````*end if*
````````````CC_Save_A[$CC_Counter_A] := %CC[11]
````````````wait ( 1000000)
````````````set_controller (11, %CC_Save_A[$CC_Counter_A])
`````````*end if*
```*end select*
```
```
*end on*

Any ideas?


----------



## Tod (Mar 3, 2008)

> it latches on... but seems to latch on with real time values.



If I'm understanding correctly by "real time values", isn't your latest variable the real time value?


----------



## Thonex (Mar 3, 2008)

Tod @ Mon Mar 03 said:


> > it latches on... but seems to latch on with real time values.
> 
> 
> 
> If I'm understanding correctly by "real time values", isn't your latest variable the real time value?



it means that if I sweep my CC 11 back and fourth for less than a second... the curve is not delayed and played back... only the last CC received will be sent through. If I do the same thing for more than a second, the script seems to just play what I'm playing without delaying the CC info.


----------



## Tod (Mar 3, 2008)

Thonex @ Mon Mar 03 said:


> Tod @ Mon Mar 03 said:
> 
> 
> > > it latches on... but seems to latch on with real time values.
> ...



OK, so it's delaying the controller for a second, but when it resumes won't your last variable reflect the current value?

If you want it to reflect what was played during the 1-sec interval don't you maybe need a "while" loop or some kind of loop to play the correct data? The problem with this of course would be that the timeing of the past controller data would be lost. I think??

Hehe, forgive me T, I'm just winging it. :oops: :D


----------



## Thonex (Mar 3, 2008)

ok... this seems to work *without* the wait() statement:

```*select* ($CC_NUM)
`````````
``````*case* 11
`````````ignore_controller
`````````*if* (%CC_TOUCHED[11] = 1) _{for CC 11}_
````````````inc ($CC_Counter_A)
````````````*if* ($CC_Counter_A >= 500)
```````````````$CC_Counter_A := 1
````````````*end if*
````````````%CC_Save_A[$CC_Counter_A] := %CC[11]
`````````````message ($CC_Counter_A & " " & %CC_Save_A[$CC_Counter_A])
```````
````````````set_controller (11, %CC_Save_A[$CC_Counter_A])
```````````
`````````*end if*
```*end select*

when there is a wait() in the controller CB... it would seem that the set_controller would only transmit the lastt CC value it saw... and not sequentially cascade the string of CC variables I have saved.

Any ideas for a work around?

Thanks,

T


----------



## Thonex (Mar 3, 2008)

*DID IT!!!!!!!!!* :D 

I realized that I needed a "delayed" counter too.... DUH!!!!! ~o) 

*on init*
```message ("")
```
```*declare* $CC_Counter_A
```*declare* %CC_Save_A [500]
```*declare* $CC_Delayed_Counter_A
```
```
*end on*


*on controller*
```
```
```*select* ($CC_NUM)
`````````
``````*case* 11
`````````ignore_controller
````````````inc ($CC_Counter_A)
````````````*if* ($CC_Counter_A >= 500)
```````````````$CC_Counter_A := 1
````````````*end if*
````````````%CC_Save_A[$CC_Counter_A] := %CC[11]
````````````wait (1000000)
````````````inc ($CC_Delayed_Counter_A)
````````````*if* ($CC_Delayed_Counter_A >= 500)
```````````````$CC_Delayed_Counter_A := 1
````````````*end if*
````````````message ($CC_Delayed_Counter_A & " " & %CC_Save_A[$CC_Delayed_Counter_A])
````````````set_controller (11, %CC_Save_A[$CC_Delayed_Counter_A])
````````````

```*end select*
```
```
*end on*


----------



## Tod (Mar 3, 2008)

I think your going to need another array to store the timeing info. Also, I'm not sure how you can store the desired array values during a wait statement unless it could also be done in a "while" loop. Still I think the "wait" would be in the way.

Humm, gotta think about this. :?

*OOps!* Okay forget everything I said.


----------



## Thonex (Mar 3, 2008)

Tod @ Mon Mar 03 said:


> I think your going to need another array to store the timeing info. Also, I'm not sure how you can store the desired array values during a wait statement unless it could also be done in a "while" loop. Still I think the "wait" would be in the way.
> 
> Humm, gotta think about this. :?



see the post above your last one


----------



## Tod (Mar 3, 2008)

Wow, this really shows me how confused I am about the "wait" function. According to my understanding the "wait" function totally stops that callback until the time has elapsed. Obviously that's not the case.


----------



## Thonex (Mar 3, 2008)

Tod @ Mon Mar 03 said:


> Wow, this really shows me how confused I am about the "wait" function. According to my understanding the "wait" function totally stops that callback until the time has elapsed. Obviously that's not the case.



No... AFAIK, each time (for example) controller data is sent to a script with a controller call back it invokes the CB. SO it is constantly listening to what's coming in even if there is a wait statement. It was just curious to me why it didn't function like a note on CB.

T


----------



## Tod (Mar 3, 2008)

> No... AFAIK, each time (for example) controller data is sent to a script with a controller call back it invokes the CB. SO it is constantly listening to what's coming in even if there is a wait statement. It was just curious to me why it didn't function like a note on CB.



Thanks T,

I think I uderstand exactlly what your saying, Even with the "wait" function the controller data is still getting through but evidently it's just not being sent out. Still, with this old brain of mine I'm confused about some things. This is what the manual says:

"wait () stops the callback at the position in the script for the specified time. In other words it freezes the callback (although other callbacks can be accessed or processed). After the specified time period the callback continues."

For that reason it's hard to see how your variable (array) is getting loaded during the 1 second period. Obviously it is getting the desired values so there's more to this than what the manual says. Actually if the data is still entering the callback but just simply not being sent (to the physical or virtual controllers) I can see how this might work.

However, I also don't understand how a variable after the "wait" would be different from a variable before the wait if they are incremented the same? :? 

Sorry for being a lame brain but I would really like to understand this. :oops: 

Tod


----------



## Big Bob (Mar 3, 2008)

Hey guys, I've been gone all day and it looks like I've been missing all the fun :lol: .

Between the two of you (Andrew and Tod), it looks like you've almost got it worked out so I'll just add a few cents worth belatedly :? 



> "wait () stops the callback at the position in the script for the specified time. In other words it freezes the callback (although other callbacks can be accessed or processed). After the specified time period the callback continues."



This is true but ONLY for the current 'thread'. The KSP uses non-pre-emptive multi-tasking. If there was only a controller callback and only controller events, the way it would work is something like this:

1st CC message starts executing the controller callback (as thread #1) and when it hits the wait() call, thread #1 goes to 'sleep'. Meanwhile, the next CC event starts another controller callback thread and it executes until it hits the wait() call, then thread #2 goes to sleep. This continues for the parade of CC events until the wait() call of thread #1 times out. Then, thread #1 continues executing the code after the wait until the controller callback exits. A little while later, thread #2 'wakes' up when its wait() call finishes, etc, etc, etc.

BTW Andrew to do a FIFO (first-in, first-out queue) you do need both an input pointer, IP, and an output pointer, OP. Initially, both pointers are set equal. To add new input data to the queue, you simply store it at the current location of the IP, or Q[IP] and then post-increment the IP pointer. When you want to remove data from the queue, you simply read Q[OP] and then increment the OP.

The other thing you have to deal with is that you would like the queue to be circular. For queue lengths that are non-integer powers of 2, you can handle the wrap around in a manner similar to what you have been doing. However, when the queue is an integer power of 2, there is an easier (and faster executing) way. For example, suppose that your queue is to be 256 words in size. Then the pointer arithmetic can be done like this:


```
IP := IP + 1 .and. 0xFF    { Circularly increment the IP }
    OP := OP + 1 .and. 0xFF  { Circularly increment the OP }
```

Initially set IP = OP = 0. The queue is empty whenever OP = IP (provided you don't insert more than 256 events before removing any).

God Bless,

Bob


----------



## Thonex (Mar 3, 2008)

Thanks Bob!!! :D 



Big Bob @ Mon Mar 03 said:


> BTW Andrew to do a FIFO (first-in, first-out queue) you do need both an input pointer, IP, and an output pointer, OP. Initially, both pointers are set equal. To add new input data to the queue, you simply store it at the current location of the IP, or Q[IP] and then post-increment the IP pointer. When you want to remove data from the queue, you simply read Q[OP] and then increment the OP.



Is that not what I am doing in my last example? I have 2 pointer (counters) that increments with each thread.... one before the wait and one after the wait. When the counter reaches 500 it goes back to 1. Am I doing what you are talking about? It sounds like it.




Big Bob @ Mon Mar 03 said:


> The other thing you have to deal with is that you would like the queue to be circular. For queue lengths that are non-integer powers of 2, you can handle the wrap around in a manner similar to what you have been doing. However, when the queue is an integer power of 2, there is an easier (and faster executing) way. For example, suppose that your queue is to be 256 words in size. Then the pointer arithmetic can be done like this:
> 
> 
> ```
> ...



Anything that goes into hexadecimal and ".and." goes in 1 ear and out the other. That stuff is for the real men... I'm just a babe in the woods :lol: 

Thanks so much for your input.

Cheers,

T


----------



## Tod (Mar 3, 2008)

Hi my friend,

Oh Boy, another can of worms, but I think I'm starting to understand.

So in other words each cc# is a thread in itself and has it's own "wait" function right? Or to put it another way, each cc input value has it's own "wait" function. If that's the case then it totally explains everything and boy do I feel dumb. :oops: 

However, hehe, just as I start to feel secure in understanding how Thonex's script is working then you come out with this: :twisted: 


```
IP := IP + 1 .and. 0xFF    { Circularly increment the IP } 
OP := OP + 1 .and. 0xFF  { Circularly increment the OP }
```

Oh well, that's for another day, week, year. :roll: 

God bless you, like always you enlightened me once again. :D 

Tod


----------



## polypx (Mar 4, 2008)

Boy, I'm sorry I've been missing all this and won't have a chance to try this out till tonight or tomorrow. But I like the look of your solution Thonex... and yeah, to me it looks circular too 




> So in other words each cc# is a thread in itself and has it's own "wait" function right? Or to put it another way, each cc input value has it's own "wait" function.



In my understanding Tod, the controller callback is executed EVERY time a single controller value appears. So the wait function gets called seperately for each of them.

Can't wait to get back into this....

cheers
Dan

EDIT - Okay, I'm late for work now, but it works!!!! Nice one Thonex! Cheers!


----------



## Thonex (Mar 4, 2008)

Oh my :shock: :lol: 

Thanks Bob!!! :D o-[][]-o 

Of course.... modulo!!!!.... why didn't I think of that... I use it all the time for Round Robins... I don't know why I didn't think of that in this case. :roll: :D .... that's why you get the big bucks.

The .and. stuff scare me :lol: ... but in looking at you example (thanks so much for that) I can see where you are going with this. I don't fully understand it yet... I'll have to spend some time with it (compile it and paste it into Nils's editor again) so I can really get my head around this.

I really need to learn bit and, bit or, bit shift, and mark.... if I learn all those... I'll be much happier. Right now they are all a little fuzzy to me :lol: 

Thanks again Bob... you really are a great help.

Cheers,

T


----------



## Hans Adamson (Mar 4, 2008)

I haven't been doing any scripting for some time, so excuse my ignorance. I was trying to read Bob's example, but there are several things there I haven't seen before. For example the construction: "a.b" - is this in the scripting manual? for example "queue.Full"

I guess "family" is in the manual, but I never paid attention to it?

Also, the expressions "accept" and "deliver" - are they documented in the scripting manual?

The example Bob gave here seems to be very useful, so I feel I just have to keep up a little... 8) 

Once again, thanks Bob, Thonex, and all of you that share your knowledge here.


----------



## Thonex (Mar 4, 2008)

Hans Adamson @ Tue Mar 04 said:


> I haven't been doing any scripting for some time, so excuse my ignorance. I was trying to read Bob's example, but there are several things there I haven't seen before. For example the construction: "a.b" - is this in the scripting manual? for example "queue.Full"
> 
> I guess "family" is in the manual, but I never paid attention to it?
> 
> ...



Hi Hans... I'll handle the first salvo... I'm sure Bob will explain it better than me any moment now :D 

Bob is using Nils' script editor that allows functions and families. I use functions all the time... his "accept" and "deliver" commands are actually place holders for functions. When you compile the script in Nils' editor, the functions are inserted into the script in the plain ol' KSP language we all love :D 

With regards to families... I haven't used those yet.

With regards to "queue.full"... to be honest... I'm not quite sure how that works.... but I'm almost 100% sure it's related to Nils' editors features.

Bob? :D


----------



## Thonex (Mar 4, 2008)

Just to keep things neat, here is the code to my script using modulo for circular increments as opposed to if-then statements. It's much more compact and efficient. Thanks again Bob.

*on init*
```message ("")```
```*declare* $CC_Counter_A
```*declare* %CC_Save_A [500]
```*declare* $CC_Delayed_Counter_A
*end on*


*on controller*
```
```*select* ($CC_NUM)
`````````
``````*case* 11
`````````ignore_controller
`````````$CC_Counter_A := ($CC_Counter_A + 1) mod 500
`````````%CC_Save_A[$CC_Counter_A] := %CC[11]```````````
`````````wait (1000000)```````````
`````````$CC_Delayed_Counter_A := ($CC_Delayed_Counter_A + 1) mod 500
`````````set_controller (11, %CC_Save_A[$CC_Delayed_Counter_A])
```*end select*
```
*end on*


----------



## Big Bob (Mar 4, 2008)

Hi Hans,



> I haven't been doing any scripting for some time, so excuse my ignorance. I was trying to read Bob's example, but there are several things there I haven't seen before. For example the construction: "a.b" - is this in the scripting manual? for example "queue.Full"



I think Andrew pretty much covered your questions except maybe for the 'family' details. When a variable is declared within a family such as 'Full', you reference it by pre-fixing the family name (such as MyQ1 or MyQ2 followed by a period). This is strictly a KScript Editor syntax, not KSP syntax. However, I am assuming that by now all serious scripters are using Nils' Editor. Note that I also do not show things like '$' prefixes and such because they are not necessary (Nils' Editor will magically add them for the KSP's benefit but you don't need to clutter up the KS source code with them).

So, the construct MyQ1.Full refers to the 'Full' flag defined in the MyQ1 family and MyQ2.Full refers to the 'Full' flag defined in the MyQ2 family. The reason I used families in this illustration was so that a general *Accept* and *Deliver* function can handle all your queues. You call these functions with the queue's 'family name' and then specify the source for the Accept 'data' or the destination for the Deliver 'data'. The 'queue' parameter of these functions is the dummy parameter that you will replace with the actual family name such as MyQ1 or MyQ2 when you call the function (as illustrated in the 'on controller' block).

As to the need for the 'Full' flag: strictly speaking if you can guarantee that your script will never 'overload' the FIFO, you could get by without such a flag. However, in general, we need to provide some form of exception handling. When the IP and OP are equal, the queue is either full or empty and we need to know which. If the queue is full, we don't want to accept anymore data until some is removed. Similarly, if the queue is empty and we want to notify the using script in some way. In my example I return NoData when this happens. I assume that there is some impossible value for the real data so your script can distinguish it. For all CCs (except the pitch wheel, valid data ranges from 0 to 127 so a NoData value of -1 can indicate that you tried to remove data from an empty queue). A better value might be something like -1000000, since -1 can occur normally from CC128.

The way the Accept and Deliver functions are referenced in the 'on controller' block makes it impossible for the script to attempt removing data from an empty FIFO. But in the general case you would follow a call to Deliver with a test of the delivered data. If the data is the NoData token you could then take appropriate action.

Hope this helps and that you all have a beautiful day.

God Bless,

Bob


----------



## Tod (Mar 5, 2008)

Hi Bob,

After looking over your script I have a couple of questions.

Back in my old BASIC programing days you could send what they called "arguments" to separate SubRoutines and SubFunctions. It appears thats what your doing that with the functions. I've been useing functions for quite a while but didn't realise you could do that. I see they're separated with a comma and although I know there's a practical side to this, I'm wondering if there's any limitation to the number of variables you can send?

Also like Thonex, I haven't really gotten into the "family" variables yet because I couldn't see any practical use for them in the scripts I've been writeing. However, I see now how you can send a whole family of variables to a function by just useing the sub-family name. I can also see if you have a couple of different sets of variables that were very similar it might be advantageous for clarity sake. Are there any other good pratical reasons for useing family variables?

Thankyou much,

Tod


----------

