Troubles re-writing an Audio Table with an Iterator

Options
hobwell
hobwell Member Posts: 3 Newcomer

Hello, first time poster, new to Reaktor.

I have an oscillator driving an audio table that has been drawn into.

I have a button that triggers an iterator. This is set up to switch the audio table to get it's RX from the iterator (instead of the oscillator), as long as the iterator is running.

The intention is to invert the sign of all values in an audio table using the iterator running at audio rate (48kHz in this case).

I've taken great pains to order the outputs from my macro to the audio event table such that outputs are ordered:

  1. RX
  2. WX
  3. Val (to be written to the audio event table)
  4. W

It almost works, but the items in the event table are getting pushed up by one or more steps each time the button is pressed and the first few steps of the table are mangled.

I'm really struggling to understand what is going on here.

The first problem I notice is that when the iterator starts, it's outputting the max value on the first step for some reason. I assume this value is left over from the previous run, but I don't quite get how to clear it.

The second thing I can't figure out is when the iterator is actually writing within the bounds of the audio table, why the first value written is always "-0".

The third issue I can't wrap my head around is why the "Invert" is triggered whenever the ensemble is loaded.

I have made the assumption (since there isn't a dedicated R input) that pushing a value into RX on the audio table will cause the value at that position to pop through the Out port.

I've likely done something wrong, but I've no clue what it might be. The documentation on the Audio Table is a bit too sparse to help me.

I've attached the ensemble in question, would be much obliged if anyone took a look.

Many thanks!

Best Answer

  • colB
    colB Member Posts: 820 Guru
    edited May 2023 Answer ✓
    Options

    Here's a version in Primary that works.

    The main trick here is to use a table trick where you can have multiple instances of the same table. To use this you need to select backup with structure in the table properties, and then you must save the table to a file (even thought this is then unimportant because the instances will use the backup in the structure (I think?)... now when you make copies of that table, they will all link to the same data for reading and writing. That simplifies the code because we don't need loops, and we can separate the different processes. So for example, the playback section can be polyphonic, but the invert code can be monophonic to save cpu.

    Its all a bit clunky, but seems to work.

    It's nasty because speed limited iteration is nasty, but necessary because output of audio table is always one value per audio tick. The problem here is that you then need to change the iteration speed manually for a different sample rate. So for me its set to 44100, but you'll need to change it to 48000

    A way round this might be to ditch iteration and use an audio rate counter that functions like the iterator, but is sensitive to sample rate changes. That's the type of thing that's trivial to implement in core, but 'challenging' in Primary

    (Note that the inverted wave has the same spectrum as the non inverted, so the sound is identical ;))


Answers

  • colB
    colB Member Posts: 820 Guru
    Options

    Why not invert it at the output of the table?, just mult with -1, and you are done... so the button just toggles between 1 and -1, and you multiply that with the output?

    In general, it's easier to manage this type of thing using core. This is a fairly simple concept you are implementing, and you are already getting to the limits of Primary (in)sanity. In core, you could take the same concept way further with less pain!

    I would likely go with a mouse area multi display combo for the waveform drawing, storing that in a snap value array, and simultaneously sending it through to a core cell with an internal core array, Any changes made manually, or in the core cell core would then be fed back to the snap value array, and the display.

    Inside the core array, you can easily separate the table updates from the audio rate reading for output, so it becomes much easier to maintain and develop.

    The only downside is that you would have to manage the interpolation for the output yourself. But there are some core interpolators in parts of the factory library to plunder!

    It seems like more work, but there is way less time spent head scratching and fighting against limitations and invisible gotchas, and you end up with more flexibility and power to tailor your design.

  • hobwell
    hobwell Member Posts: 3 Newcomer
    Options

    Thank you kindly for taking the time to respond :)

    I'm just starting out with Reaktor, been at it a few weeks now. While I know Core exists, and have spent some time examining some of the existing Core modules, I think it's a bit out of my depth at the moment. I fully intend to get there, but I thought it would be a good idea to get a firm grasp on Primary before I start building in Core.

    This is more of an exercise to help me understand how to use Audio Tables and iterators. I chose inversion as the simplest possible operation to perform on an existing value in the table. I had eventually planned to modify the values in other ways (i.e. adding or subtracting, re-ordering etc.). But if I can't even manage a simple inversion, I'm not likely to succeed with other operations.

    I'm not sure how I'm supposed to read arbitrary values out of the audio table and I'm starting to get the impression that we're not really meant to read/write data to the audio table in this way. The documentation just says that an Audio Table is "similar" to an Event Table without really indicating what the differences might be. Since the Audio Table doesn't have an R input like the Event Table, I assumed that pushing a value into RX would produce the related value at the Out port. This assumption doesn't seem to be correct.

    You mentioned snap arrays, and I've seen a couple of references to snap value arrays, is that how this type of thing (I/O manipulation of the values in an Audio Table) should be managed?

  • colB
    colB Member Posts: 820 Guru
    Options

    While I know Core exists, and have spent some time examining some of the existing Core modules, I think it's a bit out of my depth at the moment.

    Advanced users and folk wanting to make more complex DSP will mostly use core. So when you look at core much of it looks complicated. But you can use it for simple stuff too!.

    The reason those guys use core because it is easier than Primary! The stuff they want to do would be impossible in Primary, or at least difficult enough to make it impractical.

    The problem with Primary in general is that it's easy to use the modules the way they were intended to be used, but as soon as you want to do something else that wasn't designed in, you are fighting the system!.

    Audio tables will constantly output an audio stream, even with no input.

    So one trick will be to completely control the order of events. The problem can be that audio and events are processed separately, so the are asynchronous which makes it tricky to have guarantees. ie can you prove that the audio clock wont tick just at the wrong moment and give you an audio output after you started with your invert procedure, but before the table index is updated?

    I don't think that is what's happening in your example though, but the many possible problems make this sort of thing tricky to debug in Primary.

  • colB
    colB Member Posts: 820 Guru
    edited May 2023 Answer ✓
    Options

    Here's a version in Primary that works.

    The main trick here is to use a table trick where you can have multiple instances of the same table. To use this you need to select backup with structure in the table properties, and then you must save the table to a file (even thought this is then unimportant because the instances will use the backup in the structure (I think?)... now when you make copies of that table, they will all link to the same data for reading and writing. That simplifies the code because we don't need loops, and we can separate the different processes. So for example, the playback section can be polyphonic, but the invert code can be monophonic to save cpu.

    Its all a bit clunky, but seems to work.

    It's nasty because speed limited iteration is nasty, but necessary because output of audio table is always one value per audio tick. The problem here is that you then need to change the iteration speed manually for a different sample rate. So for me its set to 44100, but you'll need to change it to 48000

    A way round this might be to ditch iteration and use an audio rate counter that functions like the iterator, but is sensitive to sample rate changes. That's the type of thing that's trivial to implement in core, but 'challenging' in Primary

    (Note that the inverted wave has the same spectrum as the non inverted, so the sound is identical ;))


  • hobwell
    hobwell Member Posts: 3 Newcomer
    Options

    Wow! Thanks so much for taking the time to help me work through this. I'm quite enthused that it's possible to separate concerns with the table like that. I was really struggling with making it work in place with the one table. This alone makes it worlds easier to understand.

    I will also take a look at using the counter, I was actually wondering how to get the audio rate to sync to the iterator, but using a counter tied to the control rate makes way more sense.

    And I did not know that the inverted wave has the same spectrum as the non inverted, so thanks for that too!

    Again, really appreciate your time, thanks for the assistance :)

Back To Top