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
Just to be clear, done needs to be set to NO in the
@OnLoad
event or the script will generate an error.Apologies, @wim and @McD . I was massively over-thinking it. Your explanation was spot on and I’m all set. Thanks!
I try to detect an audio buffer change, actually all midi I received within that buffer to send it to another instance of Mozaic
I noticed that SystemTime is what I need as normally it's updated once a cycle
To test I coded this:
Using a 2048 buffer (AUM) @ 48 kHz that's 42.66.. msec, expecting values between 42 and 43
But I'm getting some strange results
display is :
Count when last systemtime = systemtime -- sytemtime - last systemtime
Note that I don't intend to use the timer, just query systemtime on midiInput, but I need to make sure I received all midi for that buffer call
@mbncp Mozaic‘s SystemTime isn‘t continous, also the OnTimer event doesn’t seem to fire on buffer changes. It‘s a bit more complex, but some time ago i did several investigations:
TL;DR: The 1ms log occurences result from the interpreter filling up the 1000 call‘s you requested with a timer interval of 1msec. See the script at the bottom on how to detect ‚all midi input of the current input queue processed‘
.
First we‘ll dive into the topic of OnTImer calls, show that timers faster than 1msec are possible and that the number of actual calls depends on buffersize and samplerate for these ultrafast timers:
A timer interval of 0.04 ideally means 1000msec/0.03msec per interval = 33333 calls per second.
But if you‘ll run it, you notice its in fact around 44300 ticks/sec if the samplerate is 41Khz and 512buffers are used. With 128/41Khz i get 44105 ticks/sec - and with 128/48Khz it is 48000 ticks/sec.
Let‘s stay at 128/48Khz. For a timerintervall of 0.04ms you‘ll get the same values. For values around 0.05ms you’ll get 24000 (48000/2), if the timerintervall is >0.07ms the number of ticks jumps to around 16000 (48000/3), >0.09ms is about 12000 (48000/4) and so on.
For timerintervalls >0.25ms the effective ticks/sec still follow this internal subdivision - that why you don‘t get the exact number of ticks - only if there is kind of divisor between samplerate and the ticks/sec requested. For timerintervalls >= 1ms the differens between requested and effective ticks is small.
The script above also didn‘t take into account that the SystemTime itself isn‘t continous (see below). That’s why i used a different measurement method in my own tests: The OnTImer only increments, and the whole measurement was done in OnNewBeat with 60bpm host tempo. That‘s also 1sec/beat - but the results and observed effects are same as with the simpler to setup script above.
.
Now we take a look at SystemTimer:
For a 1msec timer, one would expect around 1000 different SystemTimes - but Mozaic seems to update the timer only before certain functions (ie the Midi Input events) and therefore you‘ll only get around 200 destinct SystemTimer values for 512buffer / 48Khz. If you lower the buffer size to 128, you‘ll get around 400 destinct times. If one uses a 0.1ms timer you still get 400 values. For a buffersize of 64 the script reports around 800 destinct values. The SystemTime update depends on the buffersize and samplerate, but even with extreme Settings there are not 1000 different SystemTImes in a second, usually only around 200 for ‚normal‘ buffersettings.
=> Therefore it‘s not advisable to wait for a specific SystemTime value in an OnTImer - the value might just never be reported. When using >= as a test, one might be 5msec to late (200changes/sec for 512/48Khz).
.
All this internal stuff i presented isn‘t a Mozaic bug. It‘s just how it works and in my opinion it works great and very stable.
.
.
As a result of these and other tests, i came up with a method to detect when the processing a batch of midi input events is completed: Mozaic will never fire the OnTimer while there are still events in the input queue. If a fast timer interval is used (ie 1msec or below), Mozaic will schedule that Timer event right after the last midi input event is processed.
Feed AUMs keyboard into the script, use several fingers and then do a fast slide left and right. This will result in many notes being triggered per batch. You can also feed sequencers with chords etc.
If the ‚end of batch‘ detection is implemented in this way, it works very reliable und usually within the same SystemTime as the last of the input events. If a midi input buffer consists of many, many notes and/or CCs, the SystemTime will increment between the OnMidiInput (etc) calls, but the OnTimer is still fired right afterwards.
Just reposting this here from another thread incase Mozaic people are interested:
Thanks @_ki will try this. Although my implementation seems to work, just checking the system time diff, my other instance received each time the full midi batch, no missing events but still I wasn't convinced.
IMO it would have been cool to get all the AUV calls as is from the the Host.
It would be fantastic that @blueveek implements the full AUV calls and functions in JS + being able to query atom's buffer and even replace them. Knowing in advance note lengths, reliable chord or scale detection ...![B) B)](https://forum.loopypro.com/resources/emoji/sunglasses.png)
At the begin of last year i implemented a Mozaic script to script midi transmission, including communication error detection and interferences from other scripts using the global vas. I was able to transmit around 43K of data/second send by 7 sequences and around 40 MidiLFO with 3 CCs each. But i didn‘t publish these scripts, as i didn‘t find a real usecase.
This year i changed that concept to support auto-connecting bidirectional duplex communication for several groups of Moazic scripts - designed as Include snippet. Since the including scripts need to run a fast enough timer and due to the lack of general use cases, i didn‘t finish that work.
I was inspired by the Quantum script suite and wanted to add distribution of physical knob movement to the current active sub script. There are also other messages going on between these script for scene management etc - if the sub script would use the Intercom snippet, no AUM midi routing would be needed between the scripts, making their setup easier.
Main drawback of the script to script communication is that one doesn‘t get rid of the tiny delay![:) :)](https://forum.loopypro.com/resources/emoji/smile.png)
@mbncp I also though about scripting something in Atom - but i thought the current callbacks are just for the communication with external controllers, from the dicumentation it seems they only react to external midi input from midi ports specified by their device name - but not the input stream from the AUv3 host.
Not sure that Atom will take this route, but it wouldn’t be to difficult for him. I did some basic tests and the JS interpreter seems about 50 times faster, and it has Strings![:) :)](https://forum.loopypro.com/resources/emoji/smile.png)
A midi script plug with port connections, file i/o, midi files i/o, global data, includes, .. would be really nice. Atom has it all, just needs to fill the gap.
For now I find it very useful as an incoming midi processor from different sources before it hits the host, with "zero" latency, whatever the buffer size. Just missing specific midi outs.
I haven’t looked at Atom. Does it have UI options?
Scratch that. Piano roll. Nothing yet does what Mozaic only hints at...
Not sure if this has been requested, but something akin to what divisimate does for the swam solo libraries. Play a chord, and the lowest note is routed to the double bass (appropriate octave), the next lowest routed to cellos, then violas, then violins, etc.
The demos of such are incredible.
There's nothing to compare, it's just that the scripting engine could make a great scripting plug. Currently it's focused at communicating directly with Atom from/to external gear like a launchpad or any midi controller with some scripting.
@ion677 Have a look at my MultiDivisi Mozaic script, its inital redistribution is by pitch - you can turn of the unison feature with the lower right pad.
My Smart Chord Bass script just picks out the lowest note of a chord (even does chord inversion detection) so you can route it to a specific instrument.
.
The Multi-Disivi really sounds great with a SWAM Brass ensemble setup.
But for the SWAM strings you need to supply individual Expression (CC-11) and Vibrato (CC-1) following the individual melody lines - otherwise they sound quite stiff and not natural. Maybe using an MOe controller together with the amulti-Divisi script could work.
I've been daydreaming about a script for "humanizing" these streams of CC messages. The only question is, "Can I make it sound good enough?" It doesn't have to sound real, it just needs to match that rare, cozy spot in the uncanny valley that SWAM occupies.
I enjoyed reading your post about the auto-connecting bidirectional duplex communication, so I wondered if you might have any ideas on this subject.
Here are some ideas I have. Although it would be most realistic to generate the automation data in post, I'm envisioning a script for live performance. Something that goes slightly beyond adding a curve, delay, and offset to the CC values and adding a delay to the NoteOn/Off messages.
Imagine if one voice acts as a sort of "bungee cord" pulling the other voices, and when the CC values being sent to two voices intersect, the voice designated as the "leading" voice changes. Maybe the expression value being sent to the "following" voices is curved and offset by random values that change gradually, and is re-rolled when the expression value hits 0. And finally, I could make it so that the "following" voices can receive their NoteOns when the leading voice's expression value passes a threshold.
First time Mozaic help poster, long time coding dunce here.
I'm probably gonna "derp" when answer but I have a really dumb question about this:
The code does not send the sysex after it logs the "YAAAAS!"
It Just skips it. It also logs the "Na"
I know the string is correct because if I run this by itself, it works:
Curious why its doesn't run all 3 commands under the "if found"
I apologize for my brainlet-ness
@AlmostAnonymous If i understood your script, it should send out the pgmodeOn Sysex after receiving the sysex defined in header.
Since found is NO during your test, at least one of the 9 comparisons is failing. Add the line
as first line to the for loop to log the received sysex for comparison. You also can add a
to the if inside the loop to make it more obvious where there is a difference.
Are you saying that the code runs lines in both parts of this 'IF' structure in a single pass through?
If so, that should of course not be happening. Which makes me think something about your explanation is off or perhaps missing.
@hes Oh, I must have misunderstood that part of @AlmostAnonymous message - the script shouldn't output both log string...
So maybe there are two Sysex arriving: I suggest adding a
log {OnSysex }
to the top of the event function. And add another log right behind theSendSysex
command to be sure that the if part was fully executed.Could you also add a MidiMonitor capable of showing Sysex after Mozaic to check, if it was send or not ? Maybe it is send, but your receiver doesn't pick it up. Is it the same device that send in the Sysex ? Perhaps it doesn't like such an immediate answer ?
Please could someone make a little Mozaic widget that allows you to send AUM's midi clock with stop/start to multiple midi destinations, I guess either by selecting the destinations within Mozaic or perhaps by it broadcasting out the clock and appearing on the AUM midi matrix so I can choose where to route it there.
I'm trying to make a Mozaic script for controlling all the MIDI of StepPolyArp. I want to limit certain sliders to certain steps. For example, SPA only needs 0-3 to control the Octaves, but obviously Mozaic sends 0-127. Is there an easy way to limit this? I tried looking in the manual but can't see anything that helps me.
Here is my code:
@OnLoad
ShowLayout 3
LabelKnob 0, {Gate}
LabelKnob 1, {Speed}
LabelKnob 2, {Groove}
LabelKnob 3, {Octaves}
LabelKnob 4, {Order}
LabelKnob 5, {Pattern}
LabelKnob 6, {Latch}
LabelKnob 7, { }
LabelKnob 8, { }
LabelKnob 9, { }
LabelXY { }
SetShortName {StpPlyRp}
@End
@OnLoad
default_Knob_channel = 16
default_Knob_value = 100
default_pad_channel = 16
default_long_press_time = 250
Call @Init
@End
@OnKnobChange
if LastKnob = 0
setting = GetKnobValue 0
SendMIDICC 16, 16, setting
Endif
if LastKnob = 1
setting = GetKnobValue 1
SendMIDICC 16, 17, setting
Endif
if LastKnob = 2
setting = GetKnobValue 2
SendMIDICC 16, 18, setting
Endif
if LastKnob = 3
setting = GetKnobValue 3
SendMIDICC 16, 19, setting
Endif
if LastKnob = 4
setting = GetKnobValue 4
SendMIDICC 16, 20, setting
Endif
if LastKnob = 5
setting = GetKnobValue 5
SendMIDICC 16, 21, setting
Endif
if LastKnob = 6
setting = GetKnobValue 6
SendMIDICC 16, 22, setting
Endif
@End
@OnXYChange
x = GetXValue
y = GetYValue endif
@end
@end
@slicetwo Use
TranslateScale
to convert ranges, andRound
to the nearest value.The example converts knob 3 to the range 0..3 :
Also:
So would it look like this:
if LastKnob = 0
setting = GetKnobValue 0
SendMIDICC 16, 16, setting
val = GetKnobValue 0
settings = Round TranslateScale val, 0,127, 0,3
Endif
If he max values for each of the knob differs, add the following line to the OnLoad
and change the TranslateScale line of @hes optimization to
The range array is initialized with the max value for each knob - in my example the first two knobs would use 0..127, the next two knobs use 0..3 and the last three knobs use 0..7, 0..9 and 0..11 as their range.
@slicetwo No, you got the order wrong. Its like @hes pointed out. First do the calculation, then send.
Dope! Thanks!
@hes @_ki It works. Thanks!!!
I misworded. It does not run both if conditions. I was stating the "Na" part does function correctly.
If the string is found, I get the "Yaaas!" and thats is. If it is not detected, I get the "Na" part and thats it. I dont get the YAAAS and the sysex send together. I get "Yaaasss" then @end
I do have midispy on it. It does not log the sysex, even in the standalone midi version. I know the receiver is working because the little one that just sends the sysex is just a copy paste into another mozaic.
(Yes, I double checked they are all routed the same way in AUM.)
I shoudlnt need to add the end, correct?:
I think that 'end' will actually throw an error. One thing you might try is including some extra log statements to confirm which lines are actually getting executed:
If all three log statements are executed, then you know the lines in between are being executed also.
You might also try this:
I think this might work for you: https://patchstorage.com/midi-clock-tool/
Set it to use Host Clock.