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!

16364666869106

Comments

  • I like this idea.
    My only concern is that it may promote 'bad programming practices', like queing a ton of events for the future. That's not what the delay parameter was meant for. Other than that, I can certainly see the use for this.

    I've put it on the list.

  • _ki_ki
    edited February 2020

    And while we‘re in wishing mode:

    To simplify UI development with nice changing labels with user defined strings on knobs and pads and so on, i would like to update my previous proposal for string constants.

    .

    From the real-time aspects and the design of the Mozaic language its clear that string and string operations won‘t fit into the architecture.

    Instead Mozaic could offer a fixed number (128, 256?) of user defined string constants, managed by just two functions:

               StoreStringConstant <idx>, {string for idx},{string idx+1},{string for idx+2}, ....
    <string> = GetString idx   // Only allowed where strings are allows as parameter
    

    Unset idx are empty by default
    .

    This allows to setup groups of strings that later can be access via an integer index in all functions that take string parameters.

    .

    So, instead of having to script

    @SetModePad // param: pad, mode
      if mode = 0
        LabelPad pad, {Config Mode}
      elseif mode = 1
        LabelPad pad, {Name Mode}
      elseif mode = 2
        LabelPad pad, {Copy Mode}
      elseif mode = 3
        LabelPad pad, {Swap Mode}
      Endif
    @End
    

    One could then just write:

    @OnLoad
      StoreStringConstant 0, {Config},{Name},{Copy},{Swap}
    @End
    
    @SetModePad // param: pad, mode
      LabelPad pad, GetString mode,{ Mode}
    @End
    

    Which is so short that i probably wont even put it into a user event. A second group of constants for a different UI element could start at index 5 and so on.

    .

    This concept of a fixed number of string constants should fit well into the real-time architecture, no memory leaks and a single parameter easy to check for its range.

    .

    In ToggleChannels i needed 380 lines of codes for the ‚pad names‘ feature and the knobs to set these up. With the new function, it could be done in about 7 lines of code. In other scripts its about 100 if-cascade ui lines

    .

    I must admit that originally this wish cam up due to laziness in typing, but meanwhile I have a several ideas for what it can be used, which are not realizable with if-cascading due to the number of possible combinations.

    For instance if one would like to display 8 states at once on a pad, one would need 512 lines of code for the if-cascade, which in turn would take very long to interpret and produces crackles if called for all 16 pads.

  • +1 for the ability to have at least some number of indexed strings.

    I managed to find a relatively user-friendly way for non-coders to name controls in my last script, but even then it's problematic because they have to upload the script to see the changes, but if they don't save it before they upload, all their other settings made through the interface are lost.

    I share the concern about canceling scheduled events - but the likelihood of complex on-timer events, and the gymnastics needed to avoid stuck notes have firmly changed my mind on that one. For example: this script was a real bear to figure out and optimize a mechanism for playback using OnTimer. I'm betting your event scheduler is way more efficient than what I came up with using OnTimer.

  • @wim said:
    Hi @brambos ... or anyone who knows.

    The documentation for SendMIDIBankSelect says the syntax is SendMIDIBankSelect <chan>,<value>,[<delay>]. The in-app syntax says it’s SendMIDIBankSelect <chan>,<MSB>,<LSB> which is correct?

    If it’s SendMIDIBankSelect <chan>,<MSB>,<LSB> (which appears to be the case) then I assume I should send 000 for the MSB and the bank number for the LSB?

    BTW ... just a reminder.
    The manual entry for SendMIDIBankSelect appears to be incorrect.

  • wimwim
    edited February 2020

    I would love to have the ability to assign short names (long names too, preferably) to AU parameters. I don't know if that's feasible or not, but it would be much more friendly than Knob0, etc.

    Ability to disable and hide selected parameters would be super nice as well.

    Aren't you glad you stopped by @brambos? :D

  • +1 for text constants...and I hope that at some point some string concatenation. That would make for improved ui's in our Mozaic apps.

  • wimwim
    edited February 2020

    I’m not so sure what string concatenation does for us? We already have it in all labeling and logging commands.

    If I remember correctly, the added complexity of a whole string variable handling mechanism was what Bram was trying to avoid bringing into Mozaic. That is why a single indexable set of string constants was proposed as a middle-ground.

    Ref:

  • _ki_ki
    edited February 2020

    @espiegel123 String concatenations or other string operations imply memory allocation or at least memory management - which is totally not feasible in such a demanding real time environment.

    In addition, i don‘t even see a need for this as all labeling commands already take multiple strings as argument (and therefore does the concatenation when they assign the combined string to the UI element).

    .

    If you wish to conditionally add a another string to an existing one, you could apply the following structure:

    Warning: The following code is for proposed commands StoreStringConstant and GetString

    Lets say want to name a knob to output its channel in addition to one of the four strings „Soft“, „Warm“,“Regular“,“Strong“ depending on mode (0..3) and sometimes add „Penta“ depending on the variable penta (NO,YES):

    @OnLoad
      StoreStringConstant 10, {Soft},{Warm},{Normal},{Strong}
      StoreStringConstant 20,{ },{ Penta}
    @End
    
    @MyKnobLabel // param knob,channel, mode, penta
      LabelKnob knob, {CH }, channel+1, GetString 10+mode, GetString 20+penta
    @End
    

    LabelKnob first outputs the channel, adds the string for one of the four modes (notice that i applied an offset of 10 to index the correct string) and lastly either adds a single „space“ or „ Penta“ (again offsetting the index)

    .

    Or you could combine the string constants to all eight possibilities and address the correct one using simple math:

    @OnLoad
      StoreStringConstant 50, {Soft},{Warm},{Normal},{Strong}
      StoreStringConstant 54, {Soft Penta}, {Warm Penta},{Normal Penta},{Strong Penta}
    @End
    
    @MyKnobLabel // param knob,channel, mode, penta
      LabelKnob knob, {CH }, channel+1, GetString 50 + mode + penta*4
    @End
    

    The two StoreStringConstant lines could have been combined into a single one. But splitting them in two
    is more readable.

    Without the proposed commands, one needs an if cascade of 8 ifs plus 8 label output lines for the above example versus the three lines shown in both cases

    TL;DR Regarding string concatentation: The trick for the first example is that the output line always consisting of all parts, but to uses a single ‚space’ for optional parts that don’t apply. The second example had string constants for all possible output combinations.

  • Why not just have a different kind of variables that can hold strings?
    Based on an ancient tradition, these could be identified by the suffix '$': A$, MyString$ etc.
    You can assign a string to them - but no more than a fixed length, say 16 chars, will be stored:

    A$={a string}

    Since variables are arrays, you should also be able to do array assignments, array indexing etc. String arrays will hold a smaller amount of elements (128 would appear to be perfect for Midi programs), since an individual string element takes more space than a number.

    So I'd get to say:

     Mode$[]={Soft},{Warm},{Normal},{Strong}
     Penta$[]={ },{ Penta}
     mode=3
     penta=0
     LabelKnob knob, {CH }, Mode$[mode], Penta$[penta]
    

    That would appear to be mored direct and flexible to write and to understand.

  • edited February 2020

    My biggest reason for not having strings is that they would require three dozen extra functions and operators - at least - without having much use beyond a label on the UI.

    It’s simply not worth the extra burden on resources, technical complexity, severe bug-risks, etc.

    It’s just one of the limitations I consciously choose to have in Mozaic. :)

  • edited February 2020

    Time for one of us to follow the JavaScript world and make mozaic++ that transpiles to mozaic 🙃

  • @brambos said:
    My biggest reason for not having strings is that they would require three dozen extra functions and operators - at least - without having much use beyond a label on the UI.

    It’s simply not worth the extra burden on resources, technical complexity, severe bug-risks, etc.

    It’s just one of the limitations I consciously choose to have in Mozaic. :)

    Could there be a sequel, ten or twenty years from now?

  • _ki_ki
    edited February 2020

    My biggest reason for not having strings is that they would require three dozen extra functions and operators - at least - without having much use beyond a label on the UI.

    It’s simply not worth the extra burden on resources, technical complexity, severe bug-risks, etc.

    It’s just one of the limitations I consciously choose to have in Mozaic. :)

    I fully understand. And your concerns are the reason for restricting to just two functions with verifiably parameters. (index for both in range 0..x, and then the rest of them need to be strings). There are no new operators or new data types or changes to the existing data types, nor memory allocation needed.

    Yet the proposed concept is powerful enough to facilitate easy dynamic GUI labeling without the need of if-cascades for every possible combination.

    .

    .

    And another rant from the hidden lab of an unnamed the script dev‘ :

    For one my unpublished scripts i implemented a python code generator that outputs the needed Mozaic script code for a nested if-cascade with binary search generating 128 different UI label combinations.

    The original 128 variants elseif cascade took too long and produced crackles when all 16 pads needed redrawing while the audio is playing. A full redraw of all pads needed a maximum of 16*128 = 2048 IF checks in the worst case, the average was about the 1000 IF checks.

    So i needed to change the structure to apply binary search to bring the load down to 7 if-checks per pad and constant 112 for full redraw - but that needed a ‚code generator‘ to write without getting crazy and resulted in about 512 lines of nested if‘s... else ... endif.
    .
    With the proposed concept, it‘s just simply two lines of code.

  • I totally get it about not wanting to mess with string handling. But the usefulness of having a single big-ass array that could store and retrieve strings would be HUGE. It's something I regularly have to work around with often more than half the lines of code in the entire script. I find interface coding takes the most time and number of lines of code. IMO anything you can do to reduce that is probably the best thing that you can do for Mozaic.

  • I’ll ponder the options. No promises :)

  • @brambos : what about just adding two routines: one that stuffs the characters of a string into adjacent array cells (you pass in the start index and string) and one that displays a series of array cells as text (user provides array start index and character count). No string functions required.

    The Mozaic community could probably come up with Mozaic handlers that provide some basic string manipulation ... I vaguely remember having to do that in my intro to pascal class.

  • Intro to Pascal? You must be an old-timer like me. :D

  • @wim said:
    Intro to Pascal? You must be an old-timer like me. :D

    I am ancient.

  • Hey anyone who can help ...

    I need some help. I can’t figure out why TranslateCurve isn’t working as I expect. I have a script that scales cc values passing through it. I send a sawtooth LFO from Rozeta LFO through it and set the minimum and maximum values I want. TranslateScale scales the values as expected. But if I try to apply TranslateCurve, values get “stuck” at the maximum for long periods of time before eventually descending for a bit then getting stuck again.

    I’m stumped. If anyone has time and can see what I’m doing wrong, I’d appreciate it. I’ll just paste the code below to save anyone the bother of downloading it from patchstorage. You just need to remove the comment lines from the TranslateCurve and logging line, then set min above zero and max below 127 to see what I mean. The default value for curve is 1.0. It doesn’t need to be changed to see the issue.

    Thanks!


    @Description MIDI SCALER v1.01 - Squish CC values or note velocity ▫️Set the minimum and maximum values for CC's and/or Notes passing through the plugin. The values will be scaled to fit. If Max. is less than Min. scaling will be reversed. ▫️CURVE IS DISABLED DUE TO A BUG ... Curve adjusts the bias toward lower values when turned left and higher values when turned right. The center position is linear scaling. ▫️The Target knob determines the CC to scale. Fully left turns OFF. Fully right scales note velocity rather than CC values @End @OnLoad //Curve scaling percent. Tweak between 0.00 and 1.00 to moderate the curve values since we're only dealing with values of 0 to 127, too much curve can tend to flatten out peaks too much. curveScale = 0.50 //knob assignments k_min = 0 k_max = 1 k_curve = 2 k_target = 3 if Unassigned init init = TRUE min = 0 SetKnobValue k_min,min max = 127 SetKnobValue k_max,max curve = 1.0 SetKnobValue k_curve, (TranslateScale curve,(curve-curveScale),(curve+curveScale),0,127) target = 20 //default = cc 20 SetKnobValue k_target, (TranslateScale target,-1,128,0,127) for knob = 0 to 21 Call @KnobLabel endfor endif SetShortName {Squish} LabelKnobs { } ShowLayout 4 @End @OnMidiInput byte3 = MIDIByte3 if MIDICommand = 0xB0 //CC if target > 0 and target < 128 and MIDIByte2 = target byte3 = TranslateScale MIDIByte3, 0, 127, min, max // What the heck is going on when TranslateCurve is applied??? // values get "stuck" in the upper end. //byte3 = TranslateCurve byte3, curve, min, max byte3 = Round byte3 // log MIDIByte3, {:}, byte3 endif elseif MIDICommand = 0x90 //Note-ON if target > 127 byte3 = TranslateScale MIDIByte3, 0, 127, min, max //byte3 = TranslateCurve byte3, curve, min, max byte3 = Round byte3 // log MIDIByte3, {:}, byte3 endif endif SendMIDIOut MIDIByte1,MIDIByte2,byte3 @End @OnSysex SendSysexThru @End @OnKnobChange knob = LastKnob value = GetKnobValue knob if knob = k_min min = Round value elseif knob = k_max max = Round value elseif knob = k_curve curve = 1 - (TranslateScale value,0,127,-curveScale,curveScale) elseif knob = k_target target = Round (TranslateScale value,0,127,-1,128) endif Call @KnobLabel @End @KnobLabel if knob = k_min LabelKnob knob, {Min. },min elseif knob = k_max LabelKnob knob, {Max. },max elseif knob = k_curve LabelKnob knob,{Curve} elseif knob = k_target if target = -1 LabelKnob k_target,{OFF} elseif target > 0 and target < 127 LabelKnob k_target, {cc }, target elseif target = 128 LabelKnob k_target, {Note Vel.} endif else LabelKnob knob, { } endif @End
  • edited February 2020

    @wim i set the layout to 3 to get the xy pad for tracking values and changed the following lines.

    ´´´

      // What the heck is going on when TranslateCurve is applied???
      // values get "stuck" in the upper end.
      byte3 = TranslateCurve byte3, curve, 0, 127
    
      byte3 = Round byte3
    
      SetXYValues MIDIByte3, byte3
    

    ´´´

    Not sure what is happening with TranslateCurve but the values go outside the min and max when curve is changed, as you will see on the xy pad.

  • I have a memory of using a script recently that allowed you to strum a series of notes or a chord on the XY pad but I can't for the life of me find it on either my phone or pad. Nor can I remember what it's called or find it on PatchStorage... Is this a real memory or something I imagined? 😬

    It would be great if anyone else can remember this, otherwise funny farm time for me 🤣

  • @Jocphone said:
    @wim i set the layout to 3 to get the xy pad for tracking values and changed the following lines.

    ´´´

      // What the heck is going on when TranslateCurve is applied???
      // values get "stuck" in the upper end.
      byte3 = TranslateCurve byte3, curve, 0, 127
    
      byte3 = Round byte3
      
      SetXYValues MIDIByte3, byte3
    

    ´´´

    Not sure what is happening with TranslateCurve but the values go outside the min and max when curve is changed, as you will see on the xy pad.

    Thanks for looking at it. That makes sense that the values would go between 0 and 127 because the way you’ve written that line would do so. The problem I’m having is if I set min to, say 50 and max to 100, the output values rise to 100 and get stuck there for reasons I can’t figure out, then eventually break back downward for a bit, then get stuck again. I doubt there’s a bug in TranslateCurve, but I can’t find where I’m making an error. I’m hoping someone can see what I’m doing wrong.

  • @wim said:

    @Jocphone said:
    @wim i set the layout to 3 to get the xy pad for tracking values and changed the following lines.

    ´´´

      // What the heck is going on when TranslateCurve is applied???
      // values get "stuck" in the upper end.
      byte3 = TranslateCurve byte3, curve, 0, 127
    
      byte3 = Round byte3
      
      SetXYValues MIDIByte3, byte3
    

    ´´´

    Not sure what is happening with TranslateCurve but the values go outside the min and max when curve is changed, as you will see on the xy pad.

    Thanks for looking at it. That makes sense that the values would go between 0 and 127 because the way you’ve written that line would do so. The problem I’m having is if I set min to, say 50 and max to 100, the output values rise to 100 and get stuck there for reasons I can’t figure out, then eventually break back downward for a bit, then get stuck again. I doubt there’s a bug in TranslateCurve, but I can’t find where I’m making an error. I’m hoping someone can see what I’m doing wrong.

    Im not sure whether it is a bug in TranslateCurve but if you swap the translatescale after translatecurve, using the absolute min and max with curve then i think it gives yiu the desired effect:

      // What the heck is going on when TranslateCurve is applied???
      // values get "stuck" in the upper end.
      byte3 = TranslateCurve byte3, curve, 0, 127
    
      byte3 = TranslateScale byte3, 0, 127, min, max
    
  • edited February 2020

    @wim @Jocphone

    Edit:
    Was wrongly fiddled....i now see the problem at....anyway...deleted

  • Ahh! Thanks @MrBlaschke and @Jocphone!
    It does make more sense to use TranslateCurve first. It seems like it should work either way, but would be more accurate swapped around as you say. Too tired to think it through right now, but at least there’s a way to make it work.
    Thanks again for the help.

  • @Krupa said:
    I have a memory of using a script recently that allowed you to strum a series of notes or a chord on the XY pad but I can't for the life of me find it on either my phone or pad. Nor can I remember what it's called or find it on PatchStorage... Is this a real memory or something I imagined? 😬

    It would be great if anyone else can remember this, otherwise funny farm time for me 🤣

    If that exists, I'd like to use it too. I've thought about making something like that.
    Did you check this list? https://wiki.audiob.us/mozaic_scripts_list
    I checked, and I didn't see it there.

  • That's a handy list thanks @Skyblazer , I'll go through it as it's easier than the weird partial loading that the actual PatchStorage site does - which I've done at least twice since [remembering?] this, doing my own head in 🤣

    I think it's a part of a chord type script, might just have to have challenge myself to make it if I can't find it...

  • @Skyblazer found it! I'm not crazy! 😁

    Harp pad, it's in the presets, thought I'd looked through them, must have just skipped over it... Might have a play with it and see if I can get it any more expressive...

  • edited February 2020

    @Krupa I'm glad you found what you were looking for. Your description sounded more like iShred, but Harp Pad is more like Gestrument. Mine would be like iShred, with the XY pad labeled | | | | | | to indicate where the invisible strings are located. You'd strum the XY across the X axis, and the four pads would be used to switch between chords, with a knob switching between banks of chords. I wouldn't have been surprised if it already existed, because I probably got the idea for it when I tried Harp Pad and it wasn't like iShred.

    iShred:

  • @Skyblazer I've been messing about with it already and got a scale knob to work, but great minds think alike and I've been plotting just that way of strumming as my next move...

Sign In or Register to comment.