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 StoreLoopy Pro is your all-in-one musical toolkit. Try it for free today.
Comments
@pejman, I noticed right away that you have a syntax error in
@OnKnobChange
.value = GetKnobValue
requires a 2nd argument to tell it which knob to get the value from. So, value isn't getting set properly. You need to change it to either:value = GetKnobValue LastKnob
orvalue = GetKnobValue knob
(since you already setknob = LastKnob
in the previous line)You should have seen a syntax error in the log. Always check the logs, especially when things don't work as you expect. But really, you should check the log even when you don't notice any errors.
Next you have a critical error in the
for
loop. p is supposed to be a counter that goes from 0 to 3. But each time the loop executes, you override p withp = LastPad
. This throws the loop off. When the loop returns to the top, it's expecting p to have the same value that it started with. It then adds 1 and re-executes the loop.You're messing that up by changing
p
. Let's say you last touched pad 14. The loop starts with p = 0. You changep
to 14. The next time the loop starts, p was supposed to be 0 and increment to 1. But that won't happen because p is already greater than 3. Your loop won't repeat.Or, let's say you last touched pad 0. I didn't try, but as far as I can tell that should put you in an infinite loop. The loop will start with
p = 0
. You set p = 0, so no problem on the first loop. On the second loop, p is incremented to 1. But you set p back to 0. So the next time the loop executes it increments it to 1 - but you set it back to 0. Infinite loop.Try fixing those things first and see how things go.
[edit] you make the same mistake in the
for
loop in@SetKnobLabel
and@SetKnobPosition
. Those need to be fixed too.I was able to find something like this, which still has a problem and p is unknown in the syntax. That is, I had to solve the problem after removing the loop with [p]. But the issue here is that this patch only works for one knob and if I add another knob or knobs it won't work. Because I couldn't link or connect ( p ) to some knobs ones
Unfortunately, no, because I don't know exactly where and for what purpose I should use the log in order to find out the errors in the code. I only use an external CC monitor.
The log command prints information to the log section of Mozaic’s display. See the manual for more information. It is a valuable part of Mozaic debugging.
@pejman - now you're working on a different script rather than debugging the one you have? Honestly, this troubleshooting effort is just too haphazard. You need to find some way to be more methodical.
I described a methodical next step in my previous post, but instead you jumped to a different script and introduced new issues. You should pick one and tackle the problems one at a time, not moving on to anything else until that issue is solved, and not pasting snippets from other scripts until you fully understand what they're doing.
Yes, you are right, I should have gone to the main path of our script. I will definitely continue my efforts.
I apologize.
Yes, I am fully familiar with Log and I know its function, but I don't know exactly when and for what purpose I should use it. Because in many cases, I don't know exactly where my problem is so I want to create a log for it.
Put log statements liberally in your code to print out variable values to see if they are what you expect. Use it in conjunction with going through your script line by line as I suggested earlier to simulate what happens. You use log statements to print out the variable values to see if they are what you think they should be.
No apologies needed. This is all part of the learning process.
Which script is closer to what you’re trying to accomplish? We should focus on whichever is closer.
Hi everybody!
Long-time-Mozaic-er, first time poster.
I've just finished my most ambitious Mozaic patch and I'm running into some really nasty CPU spikes with it in AUM and Drambo and I was wondering whether someone could take a look to see whether it's my ipad Mini 5 getting a bit long in the tooth or whether I can optimise the code better.
The patch is a "Custom Scaler" - it conforms the notes on Channel 1 to the notes on Channel 16. I built it as I do a lot of generative music and I wanted a way of locking loads of different sequencers to my own set of notes and scales. Because the CustomScale object isn't assignable programmatically (as far as I could tell) I had to code my own ScaleQuantise function from the ground up which was quite a long road!
I've uploaded 2 versions to patch storage:
CustomQuantiser - the OG with all my comments and debugging tools
CustomScaler STREAMLINED - functioning the same but not as pretty
Bram - if you're reading this, after trying MANY languages, Mozaic is the one that's made me enjoy coding! (But if you could add CustomScale as an array, I'd love you even more)
Thanks everyone
C
@pejman During the development of more complex scripts i add Log statements at the start of every event function stating the name of the func and outputting mayor (global) variables used i that function. And a log inside every if /else block that handles the scripts logic.
This allows to detect early if the things happen in the sequence I expected - or if other states occur when using the UI, or if functions are called more often than expected (e.g. on button movements) etc.
.
Quite often i wrap that logging code into a
if debug … log {xxx} … endif
block to allow disabling of the whole log output for the scripts release.For example at the top of AUM Transport Control s OnPadDown i have the code
and this event function contains several more log-line inside the if blocks that happen for the different modes or pad presses.
Likewise the OnPadUp starts with
These log lines were added quite a the start of the development and updated with the relevant variables over the time. One never knows beforehand where things will go wrong - but errors are to be expected and the logs will help to understand whats going on.
If there are too many logs running through the console, i start adding icons/colors as first letter (depending on topic) or add indentation to visualize the flow without the need to really read each line. Sometime i used log levels or bitmaks to allow selection of which logs are shown and which are hidden, but that‘s advanced stuff.
.
TLDR: Logging helps a lot in script development. Add Logs where-ever the scripts receives input, computes logic, changes state or produces output. When wrapped in if/endif blocks you can switch on/off logging whenever needed. I usually don‘t regret investing time in coding logs, and they can even look fancy
@pejman : another logging tip. When you use arrays (especially when you are relatively new to using them), it can be worthwhile to have for loops that print out the array's contents when you enter and leave a function ... you will sometimes see that the array didn't have the values you thought (either entering the function or leaving it). This will help you to know where to focus your attention.
@Bartholomusic From my first short look through the code, i see that each MidiNoteOn and also MidiNoteOff do a lot of computation, there are several for loops running, array shifts etc. That‘s where the CPU glitches come from.
You should refactor this code to do a precomputation for the current quantization for just the 12 possible notes (ie a quant_result[] array with only 12 entries) and then simply do a lookup instead all of your computations:
BTW: You need to implement protection against double-notes by using the NoteStateArray functions, otherwise you likely produce hanging or early terminated notes since several notes map onto a single note and therefore prodice overlapping output midi note events.
@_ki Thank you - I'm not sure pre-computation works in my case because I want to be able to change the quantarray in response to incoming midi... or have I missed something?
In any case - just seeing this momentarily through your eyes has made me see a much simpler solution to my quantiser function which will require much less computation!
Thanks! C
@espiegel123 said:
I often unroll that loop into a single very long Log line as only a limited number of log lines are shown in the console and then the console gets cleared.
Here an example to output 16 values in one line:
Log {arr= [},arr[0],{,} ,arr[1],{,} ,arr[2],{,} ,arr[3],{ ,} ,arr[4],{,} ,arr[5],{,} ,arr[6],{,} ,arr[7],{ ,} ,arr[8],{,} ,arr[9],{,} ,arr[10],{,} ,arr[11],{ ,} ,arr[12],{,} ,arr[13],{,} ,arr[14],{,} ,arr[15],{]}
The output of that code looks like:
arr= [0,0,2,3 ,3,5,5,7 ,7,8,10,10 ,0,0,0,0]
IIRC every log line can be up to 255 chars, resulting in multi-lines in the Mozaic editor. Also notice the extra blanks for indentation every 4th value.
.
.
If the name of the array is to long to write such a log line (max line length exeeded), i copy the values over into a one-letter array and output that:
.
.
When in need to output 128 values, i output like above, but in a backwards running loop generating 8 lines instead of 128. Backwards since the console log is appended above - so when seen the entries are in the correct order:
That last code outputs the following (with random vales in the array):
@Bartholomusic said
Oh - sorry i didn‘t get that part from glancing through the code. But it‘s cool that you found a simpler solution with less computation.
The pre-computation for the quant_array[] could also be triggered by incomming notes - but these then would result in cpu spikes - but no longer for the to-be-quantized notes that use the lookup
@_ki , Oh my Goood,😳 😳, I never thought that Log could be so specialized and widely used, it's really interesting😍. Very good and useful explanation . Very thanks for perfect examples @_ki.🙏🙏🙏🙏.
And very thanks of @espiegel to suggest using log,🙏🙏🙏🙏. I hope I can use it properly.
@wim, The patch I'm developing has a lot of knobs, but I had to delete them and only talk about one knob in order to make it very, very simple and send it to you.
If you believe that the presence of one more knob can make a lot of changes and have a lot of effects, then I propose the script with two knobs, not just one knob.
Adding multiple knobs will add no more complexity than adding one more knob. It's better to add them all.
I'm no longer sure which code we're talking about, so please post it and describe as well as you can what needs to be fixed or changed. Let's see if we can walk through one problem at a time until the script does what you need.
Not actually true. A while back I built configurable custom scales based on MIDI input and used CustomScale and ScaleQuantise to correct notes coming in on another MIDI channel. A variety of scale build schemes including user defineable ones. It was called SMARTARSE. No CPU spikes in sight.
@TheOriginalPaulB ohhhh! So in trying to find SmartArse on patchstorage, I found someone else's patch that does exactly what I was trying to do - thanks for inspiring me to go hunting!
Wow! Is this script available somewhere??
Hi @wim. This is the script we are debugging. In the previous post, there was only one knob, but now I added another knob to it.
If you remember, I wanted to add a double tap knob in this script to reset the knob to value 57, but I had a problem.
And this script used to work properly ( updating knobs via pads ) with sgate[selection], but you said that these words are extra and I removed them.
You said that the for,s ( loops ) that I have used in this script has a problem and is either misplaced or incorrect.
In the continuation of my path to remove the extra for and solve the puzzle, I entered another detour that you did not approve. ( [p] = Round gate ) . I sent you the last script on page 93 on May 9.
The problem now is that I can't update the position of the knobs through the four pads despite removing sgate[selection]. And then adding a double tab on the knobs to reset them to a specific value.
Unfortunately, I have not been able to solve the problem until now, even using the log option suggested by @spiegel. Please help.
Of course, I have other problems, but we are supposed to solve them one by one and step by step.
@pejman : let’s try to help you debug your code.
Step 1. Identify one bug that needs solving. Tell us the step-by-step recipe to reproduce the bug.
There is a different gate or swing for each pad. In this sense, each gate sends a different cc from another gate via pads. So we have four gate and four swing.
In the @SetKnobPosition section, if I remove the [p] that is in front of the gate or swing, the knob, gate or swing will move easily and they will send the different CCs that are defined for them, but their knobposition will not be saved due to the pads.
If i put [p] front of gate and swin , when i touch pad num 0 , knobs gate or swing will move easily and send cc , but if touch pads num 1,2,3 , The knobs are locked and remain fixed at one point and do not send CCs.
Please give us a step-by-step recipe for 1 problem. Being able to give a clear, focused set of steps for one problem is important for your reader and for you.
Something along the lines of (this is totally made up but gives you an idea of the detail needed)
-upload the script
- tap pad 2
- Turn knob 2 to 30
- Tap pad 1
- turn knob 2 to 80
- Tap pad 2 again
- PROBLEM: knob 2 is at 80, but I expected it to be set to 30
Something along those lines.
Once you have done that I’ll ask some more questions that will help you find possible reasons for the behavior you see.
Excuse me, what exactly should I do now?
I am asking you to give a step by step explanation of how to reproduce one bug that you wan to solve. What I provided was a made up example.
I need you to write up a similar set of steps for an actual bug.
Ok.👍
1, upload the script
2, tap pad 0
3, Turn knob 5 and 6 to 30
4, Tap pad 1
4, turn knob 5 and 6 to 80
5, Tap pad 0 again
6, PROBLEM: knob 5 and 6 are at 80, but I expected it to be set to 30
Note : i have edited my script now to explain the problem more easily.
@pejman : so, your first step in debugging this is to see if tapping pad 0 and turning knob 5 to 30 actually stores the value 30 so it can be recalled later.
A question for you to answer before you do anything else: after you tap pad 0 and turn knob 5 to 30, which specific variable or variables in your program store the information that you will use later to restore the knob position when you tap pad 0 after having tapped pad 1?
A task:
Find all lines of code in your program that refer to those variables.
Add log lines before each of those variable mentions and after.
Find the lines in your code where knob values are fetched. Add a log line after any such line to record the fetched value.
Once you have done that tap pad 0 and turn knob 5 to 30. Carefully read the log entries.
Post the code after you’ve added those lines.