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
Sure. For the sake of simplicity, let's set up the pads to be consecutive midi notes staring with note number 60.
Here is the pseudo-code. (By the way, I am almost always write in pseudo-code first and then just translate that into the actual programming language).
I can see that we need to know what note to send and what velocity to use. So, I add to my pseudo-code to capture that info:
Now, I'll write the pseudo-code for setting up the note assignments for the pads:
Here is the pseudo-code for triggering the pads:
Most of that pseudo-code translates straightforwardly into Mozaic script statements that you can probably figure out from looking at the list of Mozaic commands.
Hopefully that was helpful.
In my opinion, being able to describe things in pseudo-code -- first as general vague directions and then refined into more specific directions is really helpful. The hardest part of programming is making the transition from thinking in general terms to thinking in terms of little steps.
Yes, all the descriptions about how Mozaic handles Events, Commands, and Functions are very helpful.
It allows me to better understand the rules Mozaic uses to parse the code, rather than "guess" how any particular event or command will be interpreted by the Mozaic "engine".
I'll give it try.
Thanks, that is helpful.
I'll try writing out the note recording / pad tap playback script in pseudo-code and see if I can fill out all the necessary elements.
I'll have to put some deep thought into how Arrays function, and how to get Midi notes in and out of an Array.
Let's consider the case where you want to store incoming notes and additional details into somearray(s).
Set up 3 arrays and an index variable:
Channels[0] // you may just be dealing with a single channel and can skip building this array
Notes[0] = 0
Velocities[0] = 0
TimeStamp = ?? // you would have to add commands to read the Mozaic clock and insert it here
index = 0
advance = 0
I MIDI Note ON comes in:
Do this for every Note in and you will have a list of Note event data of length index.
When you want to play back those notes in order use:
Channels[advance]
Notes[advance]
Velocities[advance]
and increment advance to be ready to recall the next note data triplet
This way of making and using lists of things with a pointer to the Head where data is written
and the tail where data is read in called a FIFO (First In - First Out) Data Structure.
What I've added is the idea of a multidimensional Array which Mozaic does not explicitly
provide. But 3 aligned arrays would have 3 Dimensions. But a real Multi-dimensional array
would allow for Nested Loops to advance across dimension pulling out the values related to some
index.
I hope this gives you some insight into how to read and write from arrays and apply this to
typical kinds of Midi problems.
Aligned arrays can also hold values related to Knobs, Pads, Chord Structures, Rhythms, etc.
A basic C_Major_Chord could be stored as follows:
C_Major_Chord = [60, 64, 67]
and sent out in 3 MidiOut events which will be sent sequentially space out by 0.0000001 seconds
or effectively at the same time to out ears.
Thanks @McD , this is exactly the stuff that I have the toughest time with.
But,
When I put this into Mozaic. I only get single C4, and not chord.
I don't understand how.... C_Major_Chord = [60, 64, 67] .... works?
Are you saying 3 values can be assigned to a single variable, and the somehow recalled as individual variables?
@horsetrainer : ARRAYS! (apologies for some bad formatting below)
Ok. I see a frequent comment from potential scripters without programming backgrounds about arrays. Arrays (and other data structures) can seem daunting -- but let me see if I can help them seem less confusing and abstract.
An array is just a virtual shelf with a number (called an index) that let's you specify where on the shelf you want to put something or take something. You can put anything on the shelf for later retrieval. The major "trick" is that you need decide how you want to organize the shelf.
Let's look at the pads to notes script, we were talking about up-thread. Let's have a shelf (array) where we store the note numbers for the pads to play. We will store the note a pad plays (the MIDI note number) on the shelf at a location that has the same number as the pad. Here is the pseudo-code for putting things on the array shelf (initializing the array). We will start by putting consecutive note numbers starting at 60 on the shelf. We'll look later at how to put arbitrary notes you play on the shelf.
PSEUDO-CODE
when the program loads do these things:
set firstNote to 60
for padNumber from 0 to 7, put (firstNote + padNumber) onto shelf padNote at location padnumber
when a pad is touched:
send out the midi note whose number is stored at location padNumber from the padNote shelf
So, an array name is just the shelf name. And we tell Mozaic where on the shelf to store something or look for something by putting the location in brackets. So, our padNote shelf is the padNote array. Programmers start counting at 0. So, the first location on the padNote shelf is padNote[0]. We stick something on the padNote shelf like this:
padNote[theLocationNumber] = someNumber
we retrieve something from the shelf like this:
someNumber = padNote[theLocationNumber]
Here is the Mozaic code for the pseudo-code above:
That's it. The note numbers are now safely stored. Now, if you don't want to limit the pads to consecutive notes starting at firstNote. You can do something like this.
PSEUDOCODE
if a pad is held down and the shift key is down and a midi note comes in, store that note on the padNote shelf.
Now, I need to refine the pseudo-code to be structured a little differently since I know that Mozaic listens for events to happen and runs code (event handlers) when those events happen.
REFINED PSEUDOCODE:
when a midi note comes in, if a pad is being held down, store the midi note on the padNote shelf at the pad's number
MOZAIC
This is very bare bones. It assumes, for instance, that only when pad will be pressed at a time. But, hopefully that helps demystify things a bit.
C_Major_Chord is a variable that holds multiple values, yep! An array is a variable that can hold multiple values. Think of it like a chest of drawers..."C_Major_Chord" is the entire chest of drawers, and each drawer can hold one value. You open each drawer in the chest with a number. So C_Major_Chord[0] is 60, C_Major_Chord[1] is 64, etc.
You'll need to sequentially step through every element of the C_Major_Chord array (i.e. open each drawer of the chest) in order to hear the entire chord, otherwise Mozaic thinks you just want the first element of the array, which in your case is 60/C4.
I've been doing this with for loops like so:
This might seem counterintuitive but it's not Mozaic's fault - MIDI is a serial protocol so a chord is always a quick succession of single note events.
Oops sorry! I guess @espiegel123 already answered while I was typing!
@horsetrainer Imagine each variable name beeing a cupbard wih 1024 drawer each. The index number given in square brackets points out which of the drawer of the cupboard to open to retrieve a number or in which drawer to put a number if user left of the assignment’s equal sign.
If you omit the index, Mozaic will use the draw with index 0. So
my_var = 100
is the same as `my_var[0] = 100, both store the value 100 in the drawer 0 of the cupboard named ‚my_var‘.The same applies to value retrieval.
The line
C_Major_Chord = [60, 64, 67]
uses another Moazic language feature: Array Assignment. It allows to specify values for successive indexes.Mozaic also allows to offset the desination, the line
test[3]=[10,15,20]
would set test[3] to 10, test[4] to 15 and test[5] to 20.This concepts of storing multiple values inside the same varibale is called Array. They are very helpful, because you can also use another variable or even calculation as index. Quite often the variable used for indexing into an array is also named something with ‚index‘ to help understanding its purpose.
.
In your example, you didn‘t use the array brackets, so you indexed the value at index 0.
But beware, your code now sends out 3 fixed notes for any incomming midi message - for each keyboard press and also for the release of the keyboard, tons of notes for pitchbend or modwheel etc
@espiegel123 , @unicity , @_ki
Thanks guys,
Now it’s finally starting to make sense.
Now I understand that all Mozaic variables have the potential to become arrays.
I can enter multiple values into an array by putting the values between brackets.
To play a chord with code, I have to send out each note individually using a method such as a loop, that can use a variable to index each value out of an array, one step at a time.
This below was a major help...
Btw, it isn't just that Mozaic variables CAN become arrays -- all Mozaic variables ARE arrays. Mozaic simply lets you access the first slot of an array without providing its index. So, you don't need to know that it is an array.
Real programmers will be upset from I would start by exposing 1 new concept at this time.
Show how you must send/play a chord:
@OnMidiInput
C_Major_Chord = [60, 64, 67]
SendMIDINoteOn 0, C_Major_Chord[0], 100
SendMIDINoteOn 0, C_Major_Chord[1], 100
SendMIDINoteOn 0, C_Major_Chord[2], 100
@End
// even more basic
SendMIDINoteOn 0, 60, 100
SendMIDINoteOn 0, 64, 100
SendMIDINoteOn 0, 67, 100
Now a real programmer like @_Ki sees an opportunity to wrap the 3 send in a Loop that runs
three times and advances the C_Major_Chord index:
For i = 0 to 2
SendMIDINoteOn 0, C_Major_Chord[i], 100
End-for
Now all three Notes will be dispatched with a 0.0000001 second delay between notes. On our scale of hearing they are simultaneous making a "chord". Midi only transmits 1 event at a time on the MIDI Highway.
Real programmer's like to save extra typing but when you're learning don't be afraid to just create
with the Commands you understand at your stage of development.
My first StreamByter script was over 100 lines and @_Ki understood the idea and re-coded it in about 12 lines. They sounded exactly the same but my 2nd version started with his elegant solution and what he
did taught me more StreamByter Commands that I hadn't discovered yet. That started a series of updates that @_Ki made that basically coded a lot of my music theory ideas about MIDI FX.
When I took those ideas to Mozaic I used a similar approach and later looked at some of @Wim's code related to Chords and saw whole different approach using the Mozaic Scales Functions.
I was thinking of bringing up the way I found to "calculate" standard chords from a single root note, but this discussion is about Mozaic programming concepts more than those specifics. There's a post many pages back about it that I can dig up if needed, but it seems like it would be a distraction from the main flow of thought at this point.
If this play a C Chord on middle C...
C_Major_Chord = [60, 64, 67]
SendMIDINoteOn 0, C_Major_Chord[0], 100
SendMIDINoteOn 0, C_Major_Chord[1], 100
SendMIDINoteOn 0, C_Major_Chord[2], 100
What do you think this does?
Strum_Rate = 100
C_Major_Chord = [60, 64, 67]
SendMIDINoteOn 0, C_Major_Chord[0], 100
SendMIDINoteOn 0, C_Major_Chord[1], 100, Strum_Rate
SendMIDINoteOn 0, C_Major_Chord[2], 100, Strum_Rate * 2
It all goes out in 0.000001 milliseconds so what will Mozaic's execution engine do with these 3 commands in "real time"?
HINT: The manual state a simple explanation:
SendMIDINoteOn and SendMIDINoteOff take 3 mandatory parameters, and an optional 4th one:
That's one way to ask for something to happen in the future.
There are more of course but one idea at a time.
I'd definitely read it if you care to write it up. When I saw what you did I thought "Wow. I wish I had just used this to make my One Finger app." The One Finger app sounds good but the code is beyond confusing in a lot of ways. Still, I code for own use as a rule to solve puzzles and problems. Usually to save money or drudgery. I never really save much time since it takes a lot to get something useful done.
It's useful to invent your own solutions but also good to see how it could be more elegant, extensible, and re-editable. The Bram Father gave us scales... we should use them. One chord routine will work across all those scales... a lot smarter than (60, 64, 67).
I already did write it up, and I'm pretty sure you read and commented on it. I'll see if I can track it down and PM you the link.
I couldn’t find it, but have now added it as a brief tip on the wiki page: https://wiki.audiob.us/mozaic_tips_and_tricks#calculate_standard_chords_from_a_root_note.
Now, if I can only remember that I did that for the next time it comes up...
@McD , @espiegel123 , @unicity , @_ki , @wim
Thanks to your help, I FINALLY made a script that actually works!
Nice work @horsetrainer!
Just one tiny suggestion. You might want to fill the array with -1 rather than 0 since 0 is a valid midi note and will be played back when you hit the play pad if you haven’t recorded a note in each position. Then you can further enhance the script by checking that the chordnote array variable isn’t equal to -1 before playing a note on the off chance that a synth would be buggered up if an invalid note is sent to it.
You can also avoid the three if statements in the
@OnMIDINoteOn
event by replacing them with with a singlechordnote[counter] = MIDIByte2
. Of course, the main thing is to keep the code understandable to you, not to anyone else, so feel free to ignore these thoughts.No, those are really good thoughts.
Now that I have a base to work off of, I can understand the code you wrote above.
I also now get what that -1 is all about.
Thanks Wim.
It feels great when it does what you wanted, doesn't it. I suspect you have greatness in you for
turning ideas into working scripts. Mastering code does take a lot of effort and study but
hacking out ideas is really just a matter of persistence.
If you're brave you can ask the pro's to provide advice where optimizations might be possible.
Sometimes they will generate a quick sample that shows how they might approach the same
effective solution. I do think tackling these problems alone help the learning stick and become a part of your neural pathways.
You can watch someone ride and pick up some tips but you really must get on the horse to get better.
Another teaching example of a Mozaic script segment:
If this plays a C Chord on middle C...
C_Major_Chord = [60, 64, 67]
SendMIDINoteOn 0, C_Major_Chord[0], 100
SendMIDINoteOn 0, C_Major_Chord[1], 100
SendMIDINoteOn 0, C_Major_Chord[2], 100
What do you think this does?
transpose = 2
Strum_Rate = 100
C_Major_Chord = [60, 64, 67]
SendMIDINoteOn 0, C_Major_Chord[0] + transpose, 100
SendMIDINoteOn 0, C_Major_Chord[1] + transpose , 100, Strum_Rate
SendMIDINoteOn 0, C_Major_Chord[2] + transpose, 100, Strum_Rate * 2
Imagine set a value of transpose and Strum_Rate with a Knob control.
They can be set anywhere in the script and when the Knob is turned the chords will
be transposed and strummed at the new settings.
The Knob changes will be in an OnKnob event block while the SendMidiNoteOn is somewhere else.
I hope that help explain how you can adjust knobs linked to a variable and the script produces
altered output as you roll the knobs.
There are also some Global Variables that share their values across Mozaic runtime instances.
Change a Knob in one script and outputs change across 2 or more different Mozaic scripts.
You can tie Knobs to all kinds of typical App parameters like Transpose, Scale, PPQN, etc.
Mozaic app is freezing in standalone and AUv3 mode, when I try to 'Select all' text on the code page.
I was wanting to export the Chordial code into Sublime Text 3 to review the code with @ki 's syntax, but the app freezes and I need to exit via home button.
Any advice? cheers
Tried with different scripts and even the Chordial. Not reproducible. Works as expected.
Try the windows solution. reboot
Hmm. Yes, I've just reset iPad with long press of home and off buttons. Same issue. Once I have selected all the text, app freezes.
I'm on iOS 12.4.1
iPad Pro 12.9 (2nd gen)
Any easy ways of getting code exported from the app?
What hardware and OS version?
As MrB suggests, try rebooting.
Yeah, no joy.
We posted at same time btw.
Would be great to have dedicated 'copy all' and 'export' buttons in the code section. @brambos
You can't see it, but once all text is selected I'm trying to copy. App freezes, no response.
Is this happening with all scripts or only Chordial?
Even though, you rebooted, see if powering down (I.e. saying "yes" to a power off prompt) and powering back up works. I have occasionally had that solve issues that the other types of reset didn't.