Looping User Samples

As much as I thought the DSP side was perfect ... :)
I tried playing around with importing samples last night and thought it would be amazing if the sample function could support single-cycle waveforms. Would it be possible to add looping to user samples?

I think this would be extremely powerful and a major selling point. We could even have samples of a certain length of, say, 2048 samples loop automatically, to keep from cluttering the voice menu/params.

I can work on this if someone gives me some pointers on where to look in the DSP code, I just don't have enough DSP experience to navigate it easily on my own.

Comments

  • Awesome idea! This would be cool even with given percussion oriented synth engine.
  • edited November 2014
    have a look at
    mainboard/LxrStm32/src/DSPAudio/Oscillator.c
    there is the function
    calcUserSampleOscFmBlock(...)

    in the end all you have to do is change the rows
            //one shot
            if(itg < info.size)
            {
                osc->phase = oscPhase + osc->phaseInc;
            }


    to something like
    osc->phase = oscPhase + osc->phaseInc;
            if(itg >= info.size)
            {
                osc->phase -= info.size;
            }

    that should loop the samples
  • Awesome! I'll have a think about how to implement this in the UI.
  • Is the only sample-related UI still just the "load" entry? Maybe it would make sense to expand that to allow setting of a loopable field in the SampleInfo struct, instead of making it a per-oscillator parameter.
    Or just load from a "loops" directory instead of "samples"?

    Do the INTERPOLATE_OSC et al. ever get enabled? They look off-by-one-y ;)
    Is it worth looking into the //todo use ldm instead of ldr to laod multiple values from memory optimizations?

  • in the config.h file they are enabled
    #define INTERPOLATE_OSC 1
    #define INTERPOLATE_FM_OSC 1

    regarding the ldm ldr stuff.
    I never looked into the assembly what gcc is making of the load statement.
    i just added this note when I stumbled over the ASM command to load consecutive memory blocks.
    not really sure if it is worth it
    http://stackoverflow.com/questions/20187093/the-speed-of-arm-assembly-ldm-and-ldr
  • Doh, I looked in the avr config.h...

    The gcc assembly is usually ok, but I did some experiments (with the preenfm2 code) re-implementing functions in assembly and got up to 40% faster -- sometimes even more but with wrong results :x I guess first we'd need a way of measuring the performance (did I email you about that? I forget...)

    @brendanclarke Sorry for the minor derailment, let me know if you need a hand
  • I tried the code above and it loops for a long sample I have (about 7k), but the short single-cycle waveforms I have in there don't. I think they're 1024 samples. 

    I may not be able to play with this much more for the next couple weeks - I have a gig coming up end of next week and I'd like to acid-test the additions I've done so far and make sure they're totally reliable for that!

  • osc->phase = oscPhase + osc->phaseInc;
            if(itg >= info.size)
            {
                osc->phase -= info.size;
            }

    that should loop the samples
    Silly me, I stuck that in the wrong function and ended up looping the built-in cymbal. Yes, that works - kind of. There seems to a pretty long minimum amount of time between a sample triggering, and triggering again after it ends - some hundreds of milliseconds. If the sample is long enough to loop before it runs out (above something like 100k), the retriggering is not at all seamless. How often does this function get called?
  • IIRC it gets called every 44.1kHz/32 samples and calculates the next 32 samples. I can take a look on the weekend, but off the top of my head two things I'd check are when osc->phase gets reset, and how osc->phase, osc->phaseInc, 2*PI and info.size relate.


  • @brendanclarke ;Can you try the looping with a sample of length 32768? From a quick read of the code I think the phase/lookup is calculated for that length, same as for the internal crash sample...
    That might be intentional so I'll check again before I think about "fixing" anything :)

  • http://www.adventurekid.se/akrt/waveforms/

    Just came across this incase this ends up happening.
Sign In or Register to comment.