Kyma Forum
  Kyma Support
  accumulating / counting code

Post New Topic  Post A Reply
profile | register | preferences | faq | search

next newest topic | next oldest topic
Author Topic:   accumulating / counting code
Phi Curtis
Member
posted 06 December 2008 18:48         Edit/Delete Message   Reply w/Quote
Hi,

I'm trying to get code that takes input numbers and adds the new numbers to the sum of all the previous numbers. The reason I'm doing this is because I would like to determine the intervals of melodies that are coming in via !KeyPitch and change the intervallic structure. So, for example, if a major 3rd is played I can substitute a minor 3rd instead. So a heard melody might start on the same note that the performer started on, but deviate systematically from the performed notes.

In order to do this, I need to determine the intervals that are being played (I've got that working), and then I need to add the new intervals that are coming in to a running total, which will be the new melody.

So I have been looking at doing a variation of code that is on page 263 of Kyma X Revealed. This is what I have:

| count |
count := EventVariable new initialValue: 0.

(!NumberToAccumulate hasChangedInLast: 0.001 s)
true: (count <~ (!NumberToAccumulate + count))
false: (count)

To test I use !NumberToAccumulate set to play smallish integers only, in both positive and negative directions. It works great as long as I move the NumberToAccumulate fader via the mouse in the VCS, but if I try to write a use a midi controller, or substitute an expression using !KeyPitch, it doesn't work (as mentioned in Kyma X Revealed: the problem is that the expression is being evaluated continuously and the midi controllers are being updated continously).

There must be a completely different way to approach this problem, but I can't think of any.

Looking for suggestions...Thanks! I can post an example when I have something working.

Phil



IP: Logged

Luddy
Member
posted 06 December 2008 19:41         Edit/Delete Message   Reply w/Quote
What happens when it doesn't work? Does the count soar to very high values, or does it get stuck?

One thing that strikes me as dicey about your example is that you want to measure whether an event value has changed in the last 1 ms (0.001s) But this is the resolution of the event timing. It would be impossible in principle for the system to know whether an event value had changed in the last 0.9 ms, for example. At 1ms you are at the exact minimum value for which the question can be answered. It will probably be fine, just strikes me as odd.

I suspect that the problem is not that the expression is being evaluated 'continuously' but rather that it's being evaluated lazily and too infrequently. You might try adding the statement

count readEveryMillisecond.

after the declaration of count. It is clear that for this expression to work properly (given the 1ms change window), the expression as a whole must be visited and evaluated once per ms anyway.

-Luddy

IP: Logged

Phi Curtis
Member
posted 06 December 2008 20:31         Edit/Delete Message   Reply w/Quote
quote:
Originally posted by Luddy:
What happens when it doesn't work? Does the count soar to very high values, or does it get stuck?

The numbers get added inaccurately - the numbers go higher than they should (lower when adding negative values).

Thanks - I wasn't aware of the readEveryMillisecond expression. I just set the hasChangedInLast: to 1 millisecond, because any lower would not register a change, and any higher would make the number more inaccurate. Using readEveryMillisecond improves the accuracy somewhat, but not enough.

I think I need to take a completely different approach, though. I just brought this example up to show what I had tried so far.

[This message has been edited by Phi Curtis (edited 06 December 2008).]

IP: Logged

Luddy
Member
posted 07 December 2008 10:07         Edit/Delete Message   Reply w/Quote
Phil,

| lastvalue sum |

lastvalue := EventVariable new initialValue: ?InitialValue.
lastvalue readEveryMillisecond.

sum := EventVariable new initialValue: 0.
sum readEveryMillisecond. "not sure this is necessary"

((sum <~ (sum + ((?Value ne: lastvalue) * ValueToBeAdded))),
(lastvalue <+ ValueToBeAdded))


Something like this might do the trick. It is modified from code I use to watch for changes to continuous controllers and do stuff when they change. It returns the value of sum.

If a note is played twice (successively), this won't notice; you'd need more than KeyPitch to notice the change, no?

-Luddy

IP: Logged

SSC
Administrator
posted 07 December 2008 16:41         Edit/Delete Message   Reply w/Quote
If you are measuring an interval as the size of the change between the current !KeyNumber and the last one played, then you could use !KeyDown as the trigger for updating the value of the interval. For example:

code:

| prev interval |
prev := EventVariable new initialValue: 60.
interval := EventVariable new initialValue: 0.

(!KeyDown
true: ((interval <+ (!KeyNumber - prev)),
(prev <+ !KeyNumber),
interval)
false: (interval))


[This message has been edited by SSC (edited 07 December 2008).]

IP: Logged

Luddy
Member
posted 07 December 2008 20:27         Edit/Delete Message   Reply w/Quote
(!KeyDown
true: ((interval <+ (!KeyNumber - prev)),
(prev <+ !KeyNumber),
interval)
false: (interval))

This code depends on the fact that the expression evaluation will happen only when something changes, yes? That is, if the true: false: expression were to be evaluated twice while !KeyDown is true -- not when it triggers, but in the steady state -- then the interval will be reset to zero mid-note.

-Luddy

[This message has been edited by Luddy (edited 07 December 2008).]

IP: Logged

Phi Curtis
Member
posted 07 December 2008 21:23         Edit/Delete Message   Reply w/Quote
Hi Luddy and SSC,

Thanks for your help. Here's the code that I had to determine the interval of the present note compared to the previous note:

| nn1 nn2 |
nn1 := ((!KeyDown countTriggersMod: 2) eq: 0) sampleAndHold: !KeyNumber.
nn2 := ((!KeyDown countTriggersMod: 2) eq: 1) sampleAndHold: !KeyNumber.

((!KeyDown countTriggersMod: 2) eq: 1) of:
(Array with: (nn1 - nn2) with: (nn2 - nn1))

I'm still playing with how to go to the next step, which is constructing a melody from the interval information, and then switching out the performed intervals with predefined substitutions (ascending perfect 4ths might be replaced with ascending perfect 5ths, any descending interval replaced with a descending perfect 2nd, etc).

I think I might have an idea. Stayed tuned...

[This message has been edited by Phi Curtis (edited 07 December 2008).]

IP: Logged

Phi Curtis
Member
posted 08 December 2008 00:24         Edit/Delete Message   Reply w/Quote
This code is doing what I was looking for:

| nn1 nn2 interval intervalDetected intervalDetectedCount intervalDifference |
nn1 := ((!KeyDown countTriggersMod: 2) eq: 0) sampleAndHold: !KeyNumber.
nn2 := ((!KeyDown countTriggersMod: 2) eq: 1) sampleAndHold: !KeyNumber.
interval := ((!KeyDown countTriggersMod: 2) eq: 1) of: (Array with: (nn1 - nn2) with: (nn2 - nn1)).
intervalDetected := interval eq: (!IntervalToReplace * !KeyDown clipTo01).
intervalDetectedCount := intervalDetected countTriggers.
intervalDifference := !SubstitutedInterval - !IntervalToReplace.

!KeyNumber + (intervalDetectedCount * intervalDifference)

The user supplies an incoming interval to be replaced (!IntervalToReplace), and a new interval to be heard in its stead (!SubstitutedInterval). The code then just keeps track of how many times the !IntervalToReplace has been performed, and then calculates the pitch offset required from the actual pitch being performed (!KeyNumber).

The only thing that isn't quite what I want is that if the !IntervalToReplace is changed during the performance, a new note is calculated based on the new !IntervalToReplace. I would rather that that change wasn't heard, but the current offset just continued on (I don't know if I'm saying that clearly).

I'm also still curious about what code that would add a number to a running total would look like (which has how I was originally thinking I would have to do this with).

Thanks!

PC

[fixed bug 12/8: "!KeyDown clipTo01" in intervalDetected definition insures that repeated notes will be detected.]

[This message has been edited by Phi Curtis (edited 08 December 2008).]

IP: Logged

All times are CT (US)

next newest topic | next oldest topic

Administrative Options: Close Topic | Archive/Move | Delete Topic
Post New Topic  Post A Reply

Contact Us | Symbolic Sound Home

This forum is provided solely for the support and edification of the customers of Symbolic Sound Corporation.


Ultimate Bulletin Board 5.45c