First time here? Check out the FAQ!
x

Can I trigger parameters of a MIDIOutput Event from nested STGCs?

0 votes
43 views

I'm making a sequencer in Kyma that outputs midi using the MIDIOutput Event.

Initially I'm starting with a 4 step sequence but I'm about to make it much more complex with nested loops.

If I put the expression that calculates the current note value in the MIDIOuput Event it works fine:

MIDIOutput Event:
    Frequency:

    (((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq1Value suffix: i]}) + 60) nn hz

But as I add more levels of nesting this expression is going to become unweildy and hard to debug because I can't see (in the VCS) any intermediate values. But if I create a STGC to create a !Gate signal and another STGC to calculate the current note value (!SeqVal) then weird notes start coming out over midi (half way between values).

Mixer:
    Inputs:

        SoundToGlobalController:
            GeneratedEvent:
                !Gate

            Value:
       
       1 bpm: !BPM

       SoundToGlobalController:
   
       GeneratedEvent:
       
       !SeqVal
           Value:
       
       ((((!Gate nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq1Value suffix: i]}) + 60) nn hz

       MIDIOutput Event:
   
       Frequency:
       
       !SeqVal
           Value:
  
             !Gate

 

I've tried delaying the !Gate signal in the MIDIOutput Event using turnOnAfter: for: and while that had some odd effect it didn't fix the problem. How do I create a sound that can work out the note value for the MIDIOutput Event without having to write the entire expression in its frequency parameter?

 

I've attached two example sounds - the first one that works where the entire expression is in the MIDIOutput Event and the other where I've tried to refactor that expression into STGCs unsuccessfully.

http://kyma.symbolicsound.com/qa/?qa=blob&qa_blobid=394791909300513371

asked Jan 25 in Sound Design by alan-jackson (Adept) (2,210 points)
edited Jan 25 by alan-jackson
Alan, have you tried doing both?  Couldn't you put the full expression for frequency and gate directly into the MIDIOutputEvent to ensure sample-accurate synchronization and also put intermediate expressions into STGCs so you can monitor each of the intermediate results visually?
I have tried putting the full expression in the frequency and gate fields. As I change the tempo the loops seem to get out of sync and the notes start going weird.

Here's the frequency expression:

(
    (
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Level1Effect suffix: i]})
        *
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq1Value suffix: i]})
    )
    +
    (   
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Level2Effect suffix: i]})
        *
        ((((1 bpm: (!BPM/4)) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq2Value suffix: i]})
    )
    +
    (
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Level3Effect suffix: i]})
        *
        ((((1 bpm: (!BPM/16)) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq3Value suffix: i]})
    )        
    +
    (
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Level4Effect suffix: i]})
        *
        ((((1 bpm: (!BPM/64)) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq4Value suffix: i]})
    )
    +
    60
) nn hz



and the gate expression:


1 bpm: !BPM dutyCycle: (
    (
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Level1DutyEffect suffix: i]})
        *
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq1Duty suffix: i]})
    )
    +
    (   
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Level2DutyEffect suffix: i]})
        *
        ((((1 bpm: (!BPM/4)) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq2Duty suffix: i]})
    )
    +
    (
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Level3DutyEffect suffix: i]})
        *
        ((((1 bpm: (!BPM/16)) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq3Duty suffix: i]})
    )        
    +
    (
        ((((1 bpm: !BPM) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Level4DutyEffect suffix: i]})
        *
        ((((1 bpm: (!BPM/64)) nextIndex) mod: 4) of: {(1 to: 4) collect: [:i | !Seq4Duty suffix: i]})
    )
)



As you can see "1 bpm: !BPM" is repeated all over the place. I imagine it's all of those bpm: expressions that are going out of sync when I move the !BPM fader. How would I factor out the "1 bpm: !BPM" so it only occurs once?

1 Answer

0 votes

Hi Alan,

You'll get a more accurate clock using the form:

1 bpm: !BPM triggerEvery: 64

in places where you have an expression of the form:

1 bpm: (!BPM/64)

Hope that helps!

answered Jan 26 by ssc (Savant) (44,910 points)
why is this happening?
In one case (triggerEvery), you are sharing the same clock and triggering every 64th tick. In the other, you are creating a new clock by dividing a number by 64. Because all arithmetic you do on a computer has finite precision, this new clock rate may not be *exactly* 1/64th the rate of the original clock.
...