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.

<Very> basic Mozaic question

Hi, everyone. I’m getting my feet wet with Mozaic, and I have a question with this simple command.

When I run this, it works fine. Whatever note I press, Mozaic sends out a perfect 5th higher. Then the note stops.

@OnMidiNote 
  SendMIDIOut MIDIByte1, MIDIByte2 + 7, MIDIByte3
@End 

However, instead of adding 7, I want to add a random value between 0 and 12:

@OnMidiNote 
  offset=Random 0, 12
  SendMIDIOut MIDIByte1, MIDIByte2 + offset, MIDIByte3
@End 

The problem is that the notes aren’t turning off.

Why does adding this variable value prevent a MIDI off message, and how do I fix it?

Thanks to any help you can offer. :)

Comments

  • There are 2 MIDI events for every note: On and Off.

    Your start a the ON with a random Note value.
    Then follow up with random OFF Note value that actually in most cases is NOT ON. There’s still one out there playing however.

    A really simple alternative is to fix the note length by launching “Note On” and “Note Off + delay” together in your code.
    The delay is just another value added to the SendMIDIOut parameters. I would use a pair similar to this:

    SendMIDINoteOn MIDIChannel, Midibyte2 + offset, 100
    SendMIDINoteOff MIDIChannel, MidiByte2 + offset, 0, 300

    Another useful trick: a MIDI Note On command with the volume set to 0 is interpreted as a Note Off by almost all apps.
    So, you can get away with this minimal code change:

    Delay = 200
    SendMIDIOut MIDIByte1, MIDIByte2 + offset, MIDIByte3
    SendMIDIOut MIDIByte1, MIDIByte2 + offset, 0, Delay

    Delay’s are in milliseconds with 1,000 = 1 second.

  • edited January 2023

    I've never used @OnMidiNote.

    I would use @OnMidiNoteOn and @OnMidiNoteOff.

    But the reason why it's not working, is that a new random number is being generated when it receives a NoteOff message.

    So let's say you change that function to be @OnMidiNoteOn, and then you duplicate that function for @OnMidiNoteOff, but remove the "offset=Random 0, 12" statement from the @OnMidiNoteOff version. That's an improvement.

    But now, if it receives two NoteOn messages before receiving a NoteOff, then it will still generate a new value for the "offset" variable, which means that only the most recent NoteOn will be paired with a NoteOff message.

    So the solution would be to store each "offset" number in one array, and store the associated MIDIByte2 in another array, and put them both at the same location in the array.

    The location variable could be called "Location" or "Index". After storing the offset and MidiByte2 in the two arrays, at the same "index", you'll want to change the index variable to a different number, so that the next NoteOn doesn't overwrite that data.

    So you could use a third array to track which indexes are currently being used to store NoteOn messages, or when a NoteOff is received, you could change the value located in your MidiByte2 array to be -1, to indicate that no byte is being stored there.

    (Side note: There are other ways to do this.
    The most newbie-ish way might be to just write "inc index" or "index = index + 1" and then
    if index = 100
    index = 0
    endif
    But then, if 100 NoteOns and NoteOffs are played before a certain key is released, there will be a hanging note.)

    Then, when a NoteOff is received, you want to use a "for loop" to cycle through the Byte2 array, and search for the Byte2 value of the NoteOff message. In the offset array, at the same location, that's where the associated "offset" message will be stored.

    So that would look something like this.

    @OnMidiNoteOff
    OffByte2 = MidiByte2
    for i = 0 to 127
    if OnByte2Array[i] = OffByte2
    SendMidiNoteOff MidiByte1, MidiByte2 + OffsetArray[i], MidiByte3
    OnByte2Array[i] = -1
    Exit
    endif
    endfor
    @End

  • McD and Skyblazer, thanks very much for your fast replies and help! I appreciate it.

    Everyone…mark your calendars…I hope to release a Mozaic script around August 2037. :/

  • edited January 2023

    @dcollett I'd say that this is a perfect use case for the NoteState matrix:

    @OnLoad
      ResetNoteStates
    @End
    
    @OnMidiNoteOn
      offset = Random 0, 12
      SendMIDINoteOn MIDIChannel, MIDINote + offset, MIDIVelocity 
      SetNoteState MIDIChannel, MIDINote, offset
    @End 
    
    @OnMidiNoteOff
      offset = GetNoteState MIDIChannel, MIDINote
      SendMIDINoteOff MIDIChannel, MIDINote + offset
    @End 
    

    See section "6. Remembering note states" in the manual.

  • Grandbear, thanks very much for your input also. I really appreciate all of you helping. I may be able to speed up the release to 2036.

Sign In or Register to comment.