Loopy Pro: Create music, your way.

What is Loopy Pro?Loopy Pro is a powerful, flexible, and intuitive live looper, sampler, clip launcher and DAW for iPhone and iPad. At its core, it allows you to record and layer sounds in real-time to create complex musical arrangements. But it doesn’t stop there—Loopy Pro offers advanced tools to customize your workflow, build dynamic performance setups, and create a seamless connection between instruments, effects, and external gear.

Use it for live looping, sequencing, arranging, mixing, and much more. Whether you're a live performer, a producer, or just experimenting with sound, Loopy Pro helps you take control of your creative process.

Download on the App Store

Loopy Pro is your all-in-one musical toolkit. Try it for free today.

MOZAIC - Create your own AU MIDI plugins - OUT NOW!

19899101103104

Comments

  • Hi .
    Why are there sending extra values ​​in Square type lfo in mozaic ?

  • @pejman said:
    Hi .
    Why are there sending extra values ​​in Square type lfo in mozaic ?

    Can you post some code? In particular it would be helpful to see your SetLFOType, SetupLFO, and GetLFOValue commands in context. If this is a part of a large program, then it might be worth the time to write a simple program that does nothing else but log the values.

    All that said ... I think I remember running into this in a program earlier. I don't remember what was up, but I concluded that reading from a square LFO wasn't going to work for what I was doing.

  • @pejman - I did a quick test and the square LFO is working as expected. I did manage to get a wrong reading or two on the first cycle or two, but nothing that would explain your results.

    LFO's are rarely perfectly square. If you have a slow LFO and high sampling rate you will be likely to get a few off values on the edges if you sample right in the middle of the down or up cycle.

    Here's some test code I used to play with various values for SetTimerInterval and LFO speed.

    @OnLoad
      hz = 1
      interval = 60
    
      SetTimerInterval interval
      SetLFOType 0,{Square}
      SetupLFO 0,0,127,NO,hz
      running = NO
    @End
    
    @OnTimer
      Log GetLFOValue 0
    @End
    
    @OnPadDown
      running = not running
      if running
        StartTimer
      else
        StopTimer
      endif
    @End
    
  • @wim

    @wim said:

    @pejman said:
    Hi .
    Why are there sending extra values ​​in Square type lfo in mozaic ?

    Can you post some code? In particular it would be helpful to see your SetLFOType, SetupLFO, and GetLFOValue commands in context. If this is a part of a large program, then it might be worth the time to write a simple program that does nothing else but log the values.

    All that said ... I think I remember running into this in a program earlier. I don't remember what was up, but I concluded that reading from a square LFO wasn't going to work for what I was doing.

    The image you see in the screenshot is related to the performance of LFOs patch by orchid.

    I have this problem in the codes that I wrote myself, but unfortunately, because the codes that I wrote are not readable for you, I refuse to send them.

  • @pejman said:
    I have this problem in the codes that I wrote myself, but unfortunately, because the codes that I wrote are not readable for you, I refuse to send them.

    I don’t understand what you mean by that, but OK. 🤷🏻‍♂️
    Hopefully someone else can help you.

  • @wim

    @wim said:
    @pejman - I did a quick test and the square LFO is working as expected. I did manage to get a wrong reading or two on the first cycle or two, but nothing that would explain your results.

    LFO's are rarely perfectly square. If you have a slow LFO and high sampling rate you will be likely to get a few off values on the edges if you sample right in the middle of the down or up cycle.

    Here's some test code I used to play with various values for SetTimerInterval and LFO speed.

    @OnLoad
      hz = 1
      interval = 60
    
      SetTimerInterval interval
      SetLFOType 0,{Square}
      SetupLFO 0,0,127,NO,hz
      running = NO
    @End
    
    @OnTimer
      Log GetLFOValue 0
    @End
    
    @OnPadDown
      running = not running
      if running
        StartTimer
      else
        StopTimer
      endif
    @End
    

    🔺I changed your code to 1.5 hertz , And I added setknobvalue and send CC to it so that we can see the changes more easily through knob

    Please see this video . It seems complicated to me why this happens sometimes.

    https://www.dropbox.com/scl/fi/8k9dyxfcbi2b5nb4hn3g3/out_2024-01-27-10-54-50.mp4?rlkey=ior2ypyrx5uqsjivcbvwjwakw&dl=0

    Please note that in some cases I will enable or disable cubasis playhead and enable .

    @OnLoad
    hz = 1.5
    interval = 60

    SetTimerInterval interval
    SetLFOType 0,{Square}
    SetupLFO 0,0,127,NO,hz
    running = NO
    @End

    @OnTimer
    SetKnobValue 0, GetLFOValue 0
    SendMIDICC 0, 1, GetLFOValue 0
    Log GetLFOValue 0
    @End

    @OnPadDown
    running = not running
    if running
    StartTimer
    else
    StopTimer
    endif
    @End

  • @pejman said:

    Please see this video . It seems complicated to me why this happens sometimes.

    https://www.dropbox.com/scl/fi/8k9dyxfcbi2b5nb4hn3g3/out_2024-01-27-10-54-50.mp4?rlkey=ior2ypyrx5uqsjivcbvwjwakw&dl=0

    Please note that in some cases I will enable or disable cubasis playhead and enable .

    I’m sorry, but I have no idea what that video is supposed to demonstrate.

  • @wim

    @wim said:

    @pejman said:
    I have this problem in the codes that I wrote myself, but unfortunately, because the codes that I wrote are not readable for you, I refuse to send them.

    I don’t understand what you mean by that, but OK. 🤷🏻‍♂️
    Hopefully someone else can help you.

    I wrote in response to your question : “ ___The image you see in the screenshot is related to the performance of LFOs patch by orchid.

    I have this problem in the codes that I wrote myself, but unfortunately, because the codes that I wrote are not readable for you, I refuse to send them.”___

    Unfortunately, as I have not yet written my code in a way that is publicly understandable or comprehensible, I will refrain from posting it at this time until I have modified it to be readable by all at the appropriate time.

    But in fact, I wanted to say that this problem exists in LFOs patch Too .

  • wimwim
    edited January 27

    I see.
    I may be able to find some time to look at the LFO patch by orchid tomorrow.

    Have you tried in another host such as AUM to isolate whether this may be caused by Cubasis?

  • @pejman - I’m not seeing any incorrect behavior of the LFOs script in AUM.
    Are you sure you don’t have a modulator set accidentally on th square LFO you’re recording?

  • @pejman - I didn’t see the problem in AUM during one quick test, but I do see it in Cubasis and Loopy Pro. I can’t say if it’s a problem of that LFOs script or something else.

  • @wim

    @wim said:
    @pejman - I’m not seeing any incorrect behavior of the LFOs script in AUM.
    Are you sure you don’t have a modulator set accidentally on th square LFO you’re recording?

    You wrote : Have you tried in another host such as AUM to isolate whether this may be caused by Cubasis?

    🔺I also tested it in aum, strangely, sometimes this happens during the entire LFO execution, and other times when I enable and disable the LFO, there is no problem at all.

    You wrote ; Are you sure you don’t have a modulator set accidentally on th square LFO you’re recording?

    🔺No I haven’t any modulator .

    This video is test in AUM .

    https://www.dropbox.com/scl/fi/xic1lcj5765orjs23l0s6/out_2024-01-27-12-42-45.mp4?rlkey=pn2sjmzcsj7czoayf7x5dflts&dl=0

  • @wim said:
    @pejman - I didn’t see the problem in AUM during one quick test, but I do see it in Cubasis and Loopy Pro. I can’t say if it’s a problem of that LFOs script or something else.

    If there is a case where it is not working in Loopy Pro, could you post a project on the slack?

  • _ki_ki
    edited January 30

    I can confirm the occurrence of intermediate values (during transients) of Moazaic square LFOs.

    @brambos Here a modified version of @wim ‘s script showcasing the behavior.

    @Description
     Showcase occurrence of intermediate values on Mozaic's square lfo
    
     Change LFO freq and measure rate via knobs and check LOG for non 0 or 127 values. 
     These happen regularly for rates <= 8ms, but can also occur for slower rates >8ms (ie
     like every 5th second for 13.8hz with 40ms rate)
    
     Remark: When outputputting the LFO to CC messages, rates less than 3ms would 
     spam the receiver.
    @End 
    
    @OnLoad
      ShowLayout  4
      hz = 25
      rate = 6
      last = 0
    
      SetTimerInterval rate
      SetLFOType 0,{Square}
      SetupLFO 0,0,127,NO,hz
    
      SetKnobValue 0, TranslateScale hz, 0.5, 40, 0,127
      SetKnobValue 1, TranslateScale rate, 1, 50, 0,127
      SetKnobValue 2,0
      SetKnobValue 3,0
      Call @RedrawKnobs
    
      lastTime = SystemTime
      StartTimer
    @End
    
    @OnTimer
      v = GetLFOValue 0
      if v >0 and v<127
         Log {❗️LFO },last, { -> }, v
      endif
      last = v
    
      delta = SystemTime - lastTime
      if delta >= 1000
        Log {==============  second tick =====  LFO },hz,{hz   rate },rate,{ms}
        lastTime = SystemTime
      endif
    @End
    
    @RedrawKnobs
      n = RoundDown hz
      f = RoundDown (hz - n)*10
      LabelKnob 0, {hz },n,{.},f
      LabelKnob 1, {rate },rate,{ms}
      LabelKnob 2,{ }
      LabelKnob 3,{ }          
    @End
    
    @OnKnobChange
      val = GetKnobValue LastKnob
      if LastKnob = 0
        hz = 0.1 * Round TranslateScale val, 0,127, 5, 400
        SetupLFO 0,0,127,NO,hz
      elseif LastKnob = 1
         rate = Round TranslateScale val, 0,127, 1,50
         SetTimerInterval rate
      endif    
      Call @RedrawKnobs  
    @End 
    

    I myself can live with that Mozaic quirk and simply would add extra code if i were sending out square lfo CCs to ‚recitfy‘ the values before sending.

  • Hi
    I want to mix delay with HostTempo , But with the condition that if the tempo increases or decreases, the delay will increase and decrease properly compared to the given tempo.

    Imagine that inside Aum as host app, I have a sequencer that plays bass drum and snare notes alternately and regularly. It sends notes to my mozaic patch .

    I created a 500 ms delay through knob number one of mozaic , While the host tempo is 100 , but when I increase tempo in Aum , The amount that should be reduced delay is not reduced by the code I wrote and the ratio is incorrect.

    In this patch I wrote “ delay - HostTempo * 2 “ that I know it works wrong.

    My goal is to create something similar to swing, that by increasing or decreasing the tempo, the swing ratio should be observed correctly.

    >! 
    
    @OnMidiNoteOn
    
    delay = Round TranslateScale (GetKnobValue 0) , 0, 127, 0, 1000  
    if MIDINote = 36
    SendMIDINoteOn 0, MIDIByte2 , MIDIByte3 
    elseif MIDINote = 38
    SendMIDINoteOn 0, MIDIByte2 , MIDIByte3 , delay - HostTempo * 2 
    endif
    
    @End 
    
  • wimwim
    edited February 20

    @pejman -
    HostBPM is in beats per minute. But the delay parameter is in milliseconds. So, to use HostBPM to calculate a delay in ms, you have to do some math:

    milliseconds per beat = 60,000 / HostBPM
    

    Explanation:

    • There are 60,000 milliseconds per minute
    • Dividing the 60,000 by the HostBPM gives you the number of milliseconds per beat

    Now that you know how many milliseconds are in a beat, it's easiest to target your delay to some fraction of a beat. Lets say we want a 32nd note worth of delay. We just need to divide the milliseconds for a beat by the right amount. A 32nd note is 1/32nd of a whole note (4 beats) so we have to be aware of that in the formula.

    So we end up with:

    ms per whole note =  (60,000 / HostBPM * 4)
    ms per 32nd note  =  (ms per whole note   ) / 32
                      =  (60,000 / HostBPM * 4) / 32
    

    I hope I explained that in a way that makes sense.

  • _ki_ki
    edited February 20

    Delay calculations could also be based on the QuarterNote Mozaic variable, which returns the millisecs per Quarternote..

    So adding a delay of 1/16 could be specified as QuarterNote/2, while a delay of 1/2 is QuarterNote*2.

    To offer a knob specifying the fraction, i would setup an array of fractions like tempo_fractions = [ 0.25, 0.5, 1, 2] for 1/16, 1/8, 1/4, 1/2 note delays and a knob that defines the integer index to be used to index into that array (lets name it delay_idx). Whenever the code needs to specify a delay value, use tempo_fractions[ delay_idx ] * QuarterNote to specify the note-length dependent delay time.
    One can also add fixed fractions for dotted and tripplets to the array (and thereby to the knob dialing through these)

  • _ki_ki
    edited February 20

    As i re-read your problem description, you want to add tempo dependent swing, which means staying off grid and not to use the fixed note length steps my above post offered.

    BTW as i learned for implementing my ‚Apply Swing’ Mozaic script, it is common in pop music to apply swing delay only to notes issued in certain times during a bar/beat, ie the ones arriving on the odd 1/16th or odd 1/8th.

    A first step to archive bpm dependent delay would be to use the knob as a ‚ratio‘ between 0 and 0.5 for QuarterNote
    frac = TranslateScale (GetKnobValue 0), 0, 127, 0, 0.5 and the use frac * QuarterNote as delay time. So its somewhere (but still fix for all bpm tempi) between no-delay and 1/16 note. In center position it‘s exactly 1/32 delay
    (one can also use QuarterNote * (GetKnobValue 0) / 255 without the need for the frac variable as GetKnobValue returns 0 .. 127)

  • @wim
    Sorry for late . I was testing and reading the material you sent me .
    Thanks for reply and help .

    I understand the theory of what you said, but I don't understand its relation to delay .

    I don't know how I can use this formula in my patch.

    Should I be using 0 to 32 translated instead of the 1000 milliseconds I put in my patch?

  • @_ki said:
    Delay calculations could also be based on the QuarterNote Mozaic variable, which returns the millisecs per Quarternote..

    That's a much more elegant way of doing it. Thanks.

  • @pejman, I would make the dial go from 0 to 0.5 as @_ki says, then use @_ki 's simplified calculation rather than mine.

    Something like:

    @OnMidiNoteOn
    
    frac = TranslateScale (GetKnobValue 0),0,127,0,0.5 
    delay = frac * QuarterNote 
    
    if MIDINote = 36
      SendMIDINoteOn 0, MIDIByte2 , MIDIByte3 
    elseif MIDINote = 38
      SendMIDINoteOn 0, MIDIByte2 , MIDIByte3 , delay
    endif
    
    @End 
    
  • @_ki
    @wim

    I didn't realize @_ki had sent two posts after @wim. I don't know why I didn't see them, maybe I hadn't refreshed forum.

    Thanks @_ki and @wim ❤️.

    I will try this method.

  • @_ki

    @_ki said:
    As i re-read your problem description, you want to add tempo dependent swing, which means staying off grid and not to use the fixed note length steps my above post offered.

    BTW as i learned for implementing my ‚Apply Swing’ Mozaic script, it is common in pop music to apply swing delay only to notes issued in certain times during a bar/beat, ie the ones arriving on the odd 1/16th or odd 1/8th.

    A first step to archive bpm dependent delay would be to use the knob as a ‚ratio‘ between 0 and 0.5 for QuarterNote
    frac = TranslateScale (GetKnobValue 0), 0, 127, 0, 0.5 and the use frac * QuarterNote as delay time. So its somewhere (but still fix for all bpm tempi) between no-delay and 1/16 note. In center position it‘s exactly 1/32 delay
    (one can also use QuarterNote * (GetKnobValue 0) / 255 without the need for the frac variable as GetKnobValue returns 0 .. 127)

    Thanks for reading my post again. Yes, that is exactly what I meant .
    You’re formula work properly, thanks 🙏.
    Only I used 1 instead of 0.5 for more delay.
    frac = TranslateScale (GetKnobValue 0), 0, 127, 0, 1

  • @wim

    @wim said:
    @pejman, I would make the dial go from 0 to 0.5 as @_ki says, then use @_ki 's simplified calculation rather than mine.

    Something like:

    @OnMidiNoteOn
    
    frac = TranslateScale (GetKnobValue 0),0,127,0,0.5 
    delay = frac * QuarterNote 
    
    if MIDINote = 36
      SendMIDINoteOn 0, MIDIByte2 , MIDIByte3 
    elseif MIDINote = 38
      SendMIDINoteOn 0, MIDIByte2 , MIDIByte3 , delay
    endif
    
    @End 
    

    Thanks wim for writing suggested @_ki code , 🙏.

  • edited March 2

    Hi ,
    How to calculate note length in mozaic ?
    It means the number ( milliseconds ) from the time interval of the note being pressed until the time the note is released ?

  • @pejman said:
    Hi ,
    How to calculate note length in mozaic ?
    It means the number ( milliseconds ) from the time interval of the note being pressed until the time the note is released ?

    Use the systemtime function to record the time when the note arrives and when it ends subtract that from the current system time.

  • @espiegel123

    @espiegel123 said:

    @pejman said:
    Hi ,
    How to calculate note length in mozaic ?
    It means the number ( milliseconds ) from the time interval of the note being pressed until the time the note is released ?

    Use the systemtime function to record the time when the note arrives and when it ends subtract that from the current system time.

    Thanks espiegel for help , i will try . 🙏

  • Hi again,

    I use lfos in some of the patches that I am making. I use labels and set knobs to show the performance of lfos, for example, I use the values ​​that are being exported from each Lfos for setknobposition and label knob.

    Therefore, I have to use them in @ontimer along with loops, and this issue causes the cpu consumption to increase drastically.

    As far as mozaic warns about using too many loops in @ontimer, but the patch works properly

    I remember that @espiegel warned me about this before, but I don't have a solution to avoid many loops and many lines of code that I used in ontimer.

    Please guide how and where should I use the codes related to labelknobs, setknoblael and setuplfo that I want to use except @ontimer . ??

  • @pejman - The timer interval is important. If you're doing a lot in each timer interval then you should set as long a timer interval as you can and still get smooth enough results.

    Other than that, there may be ways to optimize the code in your timer loop. Sometimes lengthy if - then statements can be reduced using arrays and in other ways. Maybe if you post an example of an @OnTimer section that's giving you trouble, we can spot some ways to reduce its overhead.

  • @pejman - here's a simple example meant to show two things:

    1. Timer interval doesn't have to be super low to still get smooth animation. Even a 40ms timer interval results in better than 24 fps frame rate.
    2. Checking LFO's and doing things with them in a single for loop. The text on the labels is kept simple to work without if ... elseif statements, but wouldn't create a lot more overhead if you to use one for more customized labels.

    Maybe this will give you some ideas for streamlining your @OnTimer section.

    @OnLoad
      // Some quick code to set up example LFOs
      for lfo = 0 to 15
        SetupLFO lfo,0,127,NO, ((Random 0,100) / 1000)
      endfor
      ShowLayout 1
      SetTimerInterval 40   //This gives us about 24 FPS!
      StartTimer
    @End
    
    @OnTimer
      for lfo = 0 to 15
        lfoValue = GetLFOValue lfo
        SetKnobValue lfo, lfoValue
        LabelKnob lfo,{LFO },lfo, {:}, Round(lfoValue)
      endfor
    @End
    
Sign In or Register to comment.