1. IMPORTANT:
    We launched a new online community and this space is now closed. This community will be available as a read-only resources until further notice.
    JOIN US HERE

Professional-Quality Pitch Shifters with Core?

Discussion in 'Building With Reaktor' started by NIhilated, Jan 8, 2011.

Thread Status:
Not open for further replies.
  1. NIhilated

    NIhilated New Member

    Messages:
    18
    Has anyone built a professional-quality pitch shifting module with Core for the User Library -- better quality than the "grain" pitch shifters in Reaktor?

    If not is there some public domain algorithm (maybe from Max?) that could be ported?

    The Reaktor grain pitch shifters (both regular and Core) certainly have "personality"... um, in the bad sense.
     
  2. Jedinhopy

    Jedinhopy NI Product Owner

    Messages:
    821
  3. BertAnt

    BertAnt NI Product Owner

    Messages:
    414
  4. colB

    colB NI Product Owner

    Messages:
    3,969
    I had a go a while back and had some promising results, but I gave up due to the lack of iteration in core.

    The problem was that searching for the best jump back point in the sample stream is difficult if you can't iterate over the data. That eaves you with just guessing at which zero crossing might give minimum glitches.

    What I ended up doing was making a pitch tracker and using that to guide the shifter. Unfortunately, the tracking wasn't robust enough to deal with the more interesting/rich audio that I wanted to pitch shift.

    (Unfortunately, since then, I Iost some stuff in a hard drive crash, so I don't even have the half finished stuff to upload - before you say it, it crashed while I was making a backup)

    cheers

    Col
     
  5. NIhilated

    NIhilated New Member

    Messages:
    18
    Unless I'm doing something wrong with it that's definitely not artifact-free pitch shifting. :)
    ---
    Perfect if it can be implemented in Core -- and entirely over my head.

    That's the Prosoniq/Orange Vocoder guy BTW so he certainly knows what he's doing. Looks like he's answering questions currently on that page -- wonder if he owns Reaktor...
    ---
    I'm not certain what you're talking about and if it's relevant to the DSP Dimension algorithm BertAnt has mentioned. But could you write the audio stream through an Audio Table module. Then on the way out of the Audio Table you could test for zero crossings, and write their location (by X index of the Audio Table) to another table or array.
     
  6. CList

    CList Moderator

    Messages:
    3,299
    Disclaimer: I don't know all that much about FFT transforms or EzFFT, but I think I know enough to help you see what the difficulties are with this...
    /Disclaimer

    When they talk about "windowing" in those FFT articles, they're talking about doing calculations with groups of samples for *each sample processed*. So, when you process each new sample at time [n] you might need to do processing against the samples [n-32] ... [n] (e.g.) ...or maybe just [n-5] ... [n]. The bigger the "window" (the further back in time you need to go), the harder it is to do in core because core doesn't allow you to do something like;
    for i = 0 to 31
    {
    y = y + array
    }

    ...looping - aka "iteration".

    You must do all the math explicitly in core because it does not allow looping structures that can be processed in one tick of the sample clock. This means you have to do things like so;
    y = y + array[0] + array[1] + array[2] ... + array[31]

    ...now that might seems simple, but imagine what happens when you want to do something like this;

    This is what makes it difficult to reconcile the code in EzFFT with the code samples you'll find out on the web that do FFT algorithms - because most algorithms out there written in code utilize iterative loops and to do them in core you need to "unroll" the loop into straight, explicit math.

    Based ont he example I gave, this may not seem like too much work, but imagine if your original loop were something like this:
    for i = 0 to 8191
    {
    b = 0.5 ( 1 - array[i -1] )
    a = array[i-2] + b
    c = (a - (b * 0.25)) / array
    array = (c + b + a) / 3
    }

    ...and think about doing that without a loop, and you see that you could have one hell of a big-ass formula!

    ....of course none of this answers your original question, to which I have to assume the answers is; 'it would be very difficult to do in reaktor'. It would probably be a lot easier to if you were willing to having it run non-realtime; like load a sample, click a button, wait a few seconds, then you have a new sample that's pitch-shifted, but... well... what fun is that?

    Cheers,
    CList
     
  7. salamanderanagram

    salamanderanagram NI Product Owner

    Messages:
    3,454
    "Unless I'm doing something wrong with it that's definitely not artifact-free pitch shifting"

    i'm not so sure there is such a thing - any pitch shifter is going to have *some* artifacts. i hope i'm wrong on that account, but i don't think i am...

    @clist, i've had success just hitting a core cell with an iterator module.
     
  8. BertAnt

    BertAnt NI Product Owner

    Messages:
    414
    i'm curious about the iterator module...let's say i connected the module output to the input of another iterator module (in attempt to simulate nested loops).. will this work as expected (the second iterator sends all event before the next event is sent from the first ) ?
     
  9. colB

    colB NI Product Owner

    Messages:
    3,969
    Just to clarify, I wasn't talking about an FTT based frequency domain approach.
    I was trying a time domain algorithm.

    The same problem applies though.

    For my approach, in order to shift notes from 80Hz (a reasonable lower range) at 44100Hz sample rate, I would need to process a loop of up to about 600 iterations.

    Now way I'm going to build and debug a module with 600 sections in it :).
    If NI would release the technical specs for the file format, I suppose one could write some C or java code to generate a Reactor module, but again, I'm not about to attempt to reverse engineer the format just to see if my algorithm works - what a waste of effort if it doesn't :)

    EDIT : the problem with the iteration module is that its not in core:
    600 iterations per sample would probably be impossible in core - it certainly would in primary. There are ways to optimise the algorithm I was implementing considerably, but not enough to make it viable in primary.
     
  10. CList

    CList Moderator

    Messages:
    3,299
    @salamander: the iterator sending events into the core cell does work, and can get a lot done - I've used it myself to do instantaneous copies of very large core arrays. The problem is that it's off-line and not synced to the incoming audio stream.


    Yes, this works quite well for *events*. I use it all the time to do some very code-like stuff (the event table bubble-sort algorithm in my arpeggiator, e.g.) - but using it for something that's synced to the audio clock - and that works on *samples* in an audio stream, on a sample-by-sample basis is a bit of a chore. Remember that an entire event chain - including all iterators - will process as soon as the first event triggers the chain, and will process all in one tick of the sample clock. I threw some pics in below of "nested loops", and the structure of my "for-loop" macro - which I pretty much always use instead of using the iterator, I very rarely want an iterator without it having the structure of an "increment by 1" for-loop.

    If you want to load your audio into a table and process it offline - you could do it this way, but something more real-time (with, perhaps a slight delay) that's working on a sample-by sample basis would be more difficult. I'm not sure what the goal of the O.P. was/is , but I just assumed near real time FFT pitch shifting of incoming live audio was the goal.

    A few of us did a bunch of playing around a while back trying to go back and forth between the core audio domain and the primary event domain to try and trick core into processing iterated events as if they were audio, but the synchronization between the two was;
    a. very tricky
    b. slightly unreliable as reaktor makes no promises about the timing of one relative to the other
    c. very bad for CPU usage as the cross over from core to primary and back takes a heavy toll on CPU usage (see the thread: "Primary and Core a CPU Analysis" here http://www.native-instruments.com/forum_us/showthread.php?t=104265)

    Here's another thread with some examples of the experiments we did in these murky waters (as well some examples of my ignorance when it comes to the math involved in DSP!)... the thread gets into some rather heady theory on interpolation methods for over sampling, but it starts off with some interesting, simple examples of
    primary event <-> core audio
    synchronization techniques to cause core to process audio samples at a higher clock rate than the audio clock
    http://www.native-instruments.com/forum_us/showthread.php?t=104720


    Cheers,
    CList
     

    Attached Files:

  11. machinehermit

    machinehermit Forum Member

    Messages:
    403
    I think you would be hard pressed to hear artifacts in Eventides algos, but that is also why they cost so much.

    Even if you could do FFT based shifter in reaktor, surely it would have artifacts of resynthesis.
     
  12. Jedinhopy

    Jedinhopy NI Product Owner

    Messages:
    821

    Attached Files:

  13. NIhilated

    NIhilated New Member

    Messages:
    18
    Eh. Can't you just simulate loops with multiple Arrays cycling through each other, with the sample rate bumped up inside the Core module to a few thousand times the real sample rate?

    Yes I meant real-time, and no nothing is actually artifact "free", but most pitchshifters unlike the Reaktor grain delays can shift by a semitone without sounding like the audio is driving down a gravel road.
     
  14. CList

    CList Moderator

    Messages:
    3,299
    To be honest, I'm not too up on the new features in R5.5, so someone correct me if I'm wrong, but...

    No. Core cells cannot have a sample rate that's any different from the sample rate of the rest of the instrument. Over-sampling in core is done by replicating the same structure for each number of times you want to over-sample and then combining the results at the end via "down-sampling".

    We all hope that at some point in the future NI will come up with a scheme for core that will let us do loops and/or allow for different sample rates within cells.

    Cheers,
    CList
     
  15. NIhilated

    NIhilated New Member

    Messages:
    18
    R6 then. Thanks for your help.
     
  16. sowari

    sowari Moderator Moderator

    Messages:
    27,759
    whatever, it would be nice to have decent Pitch Shift in Reaktor, because the one that comes with the R5 Library is dreadful.

    sowari
     
  17. Tr97

    Tr97 NI Product Owner

    Messages:
    118
    Hi. Here is the result of an attempt to build an EzFFT-based shifter based on the dspdimension-tutorial, but it is far from decent for tonal input yet (except for octave shifts). It sounds more than a ringmodulator than like a shifter and it cannot handle bass. One of the main problems is the correct reassignment of the shifted bins. And the transient-handle of course.

    The latency is 4.5 blocks (~105 ms, 4 fft,ifft + 0.5 processing).
     

    Attached Files:

  18. stingray2

    stingray2 NI Product Owner

    Messages:
    12
    Hi CList, Is that for-loop publicly available for download on you Reaktor FAQ website? I would like to test that in a structure here, if I may. Cheers.
     
  19. CList

    CList Moderator

    Messages:
    3,299
    I don't think that file is specifically on the website, but you can find in almost every instrument I've made in the user lib.


    e.g., this one uses it somewhere I'm sure;
    http://www.semaforte.com/reaktor/files/EventWatcherv04.zip


    Cheers,
    CList
     
  20. stingray2

    stingray2 NI Product Owner

    Messages:
    12
    Thank you
    :)
     
Thread Status:
Not open for further replies.