How do you recursively call a macro?

Harry LeBlanc
Harry LeBlanc Member Posts: 14 Member
edited October 22 in Reaktor

I'm a newbie at reaktor (though I'm an experienced programmer). I'm trying to build a samchillian, and I'm most of the way there, but I'm stuck on what I hope is something simple.

In case you don't know what a samchillian is, it's a remapping of the keyboard, so that each key doesn't represent an absolute midi value, but instead an amount of change. So, e.g., C4 might move the note down a scale degree, B3 down by 2 scale degrees, E4 up a scale degree, F4 up 2 degrees, etc. Very fun, and an innovative way to improvise melodies in a particular key. If you want to see it in action, there are youtube videos.

But there's the rub. The amount of absolute midi notes to change varies on the scale you're using and your current position in that scale. So, if I'm going to move up 3 scale degrees, I need to figure out where I'm starting, and for each step figure out how many semitones that scale degree change is. Going from the third to the fourth in a major scale is one semitone, while fourth to fifth is two.

So I've built up scale maps using snap value arrays, and I wrote a macro to process one degree change at a time. I pass in the amount of change already accumulated (initializing it to 0 on the first call), then the macro returns the new amount, which I stick into a value object, which then feeds back into the next round of macro processing.

My problem is, how do I iterate calling the macro recursively, and then stop calling it when I'm out of steps to process? I can't quite figure out how to use the iterator object to skin this cat. The processing itself is quite complex, to accommodate multiple scales, and encapsulating it inside a macro is the only way to keep things manageable.

Can anyone help me?

Thanks!

Answers

  • colB
    colB Member Posts: 988 Guru
    edited April 22

    Not sure why you need recursion (thankfully, because that is not easy in Reaktorland, achievable, but very challenging)

    Just keep track of the current note (I would be using core), and have a map like you suggested for what all the keys do. Then each time you get a keyboard input, reference the table, apply the arithmetic to the current note value, store that and send it to the output.

    The main trick is storing the current value, you can do this in Primary, maybe with a snap array, or an event table, or whatever. Core is maybe better because you can use OBC, but there is a steeper learning curve to that because you need other stuff to make best use of it...

    Seems like a nice easy project though, the only hassle is inputting all the 'instruction' data for what all the keys do.

    I'm gonna go look up samchillian now to see if there are any subtleties that might require recursion :)

    EDIT: yes, it seems technically simple enough to implement (assuming I'm not forgetting any MIDI issues with Reaktor). You just need all the scales tabulated, and the samchillian 'instructions' encoded.

    You need some logic for octaves so you only need one octave per scale type (assuming you've not using super esoteric scales that don't repeat on octaves), you should be able to have pentatonics, diatonics, stuff like be-bop scales etc. Just need to do all the annoying work of encoding them

  • Harry LeBlanc
    Harry LeBlanc Member Posts: 14 Member

    The scales I'm using aren't very exotic -- all the modes, plus pentatonic, hexatonic, octatonic and chromatic. Nothing fancy. Maybe down the road I can add extra scales, but I just want to produce something usable for now.

    I'm not yet ready to tackle core. I think I need to achieve proficiency at the primary level before I take that on. I don't know diddly about dsp. I intend to get there eventually, but for now it's not a solution for today's problem.

    You say that in primary it's "simple to implement," but don't tell me how. How do I loop x number of times, then stop and kick out the result? It may seem obvious to someone who's more experienced, but I'm still baffled as to how.

    I can brute-force it, and lay out 8 separate copies of the macro in sequence (I'm not supporting more than 8 steps of change), but I'd like a more elegant solution.

    Can you tell me how to do it? Maybe even with a screen shot with an illustrative ensemble?

    Thanks!

  • colB
    colB Member Posts: 988 Guru

    How do I loop x number of times, then stop and kick out the result?

    Why do you need to loop any times?

    Maybe I'm misunderstanding, but what I see is that there is some starting pitch (not sure how that is arrived at?), then when you hit a key on your samchillian engine, depending on the key you hit, that starting pitch is altered in scale steps depending on the scale...

    The way I imagine it (simple approach, maybe not most elegant) is that you have a table of 'operations', so just values that are positive and or negative integers... so 1 means go up one scale step, -4 means go down 4 scale steps.

    For each scale you have a table of references to midi notes... or to semitones, or similar... you start off at some offset within the scale table, then if you hit a key you use the value for the key to look in the operations table, which gives you a value to add or subtract... lets say it's 4, so you add 4 to your scale index, then read from the scale table and it will give you back a new midi note, which you output as midi, or directly play on some Reaktor synth... next time you hit a key, similar process.... use the played key to read from the operations table, add the value you get back to the scale offset, read from the new index, and you get a midi note value to play (or output)... seems simple?

    EDIT: I see that it's slightly more complex, but that just means more work rather than more difficulty :)

    So the example on wikipedia is of a major diatonic C scale, and the key to go up in diatonic 2nds, this goes up 2 semitones, except for the steps from E to F and B to C where it jumps by 1 semitone. Probably the easiest way to do that would be just to have a table per scale per operation (really just a big table with offsets for scales, and operations within scales). Still just a case of using the current note and the key you just hit to calculate a new table index which gives you a new note value.

    The table will be large num_scales * num_operations * scale_size (different key centres should be achievable just by transposing, so more arithmetic... Pretty easy to do this in core (maybe in Primary too?) You could built the table elsewhere in import it as (I think?) a comma separated list of values.

    Still no need for iteration or recursion that I can see. Just work out a mechanism to reset/restart at some offset within the scale table.

    If you want to have a neater setup with only an octave stored, then you would have to use some sort of modulo process, and wrap the table index, you would need to then keep track of what octave you are in as well as the table index. still no need for iteration though.

    Not sure how chords work. Maybe some method to keep track of pressed keys and associated notes... this is much more difficult in Reaktor, because you need some sort of data structure. a much more advanced project! I have used a mutant linked-list/stack thing for midi handling before, but it's not easy to process, and definitely something to do in core IMO. So maybe get the sequential monophonic basics working first?

    Of course, this is just be imagining how it might work, I've hadn't even heard of a samchillian before, so thanks for that :-)

  • Harry LeBlanc
    Harry LeBlanc Member Posts: 14 Member

    Yes, that could work. From any scale of n length, there are n possible starting points, with n results in each table. So 8 tables (corresopnding to the various modes -- ionian starts on d, dorian starts on e, etc), with pre-summed results (jumping a third will be four semitones from a c, three from a d, etc). Certainly simpler than my idea. Thanks!

    And one thing I figured out the other day, is that the seven modal scales are all you need for both going up and down. So E phrygian going up is identical to C ionian going down. They're symmetrical around D. D's the same up and down. E up/down = C down/up, F up/down = B down/up, etc.

    And for whole tone and chromatic, every step is identical. And octatonic and hexatonic are super simple patterns.

    Yes, this should do it. Thanks for your insight.

    I'd still like to figure out how to use the iterator; I'm sure I'm going to need it someday. But not today.

    🙂

This discussion has been closed.
Back To Top