LPX: Recording MIDI From Another Track

In this post, I will show in Logic Pro X how MIDI being output in one track can be recorded in another track for further editing. This requires a small bit of prep outside of LPX to work.

I was recently working on a classic/prog rock-like track, and while messing around with the Drummer presets, I liked what one of the Electronic Drummers was outputting versus the Rock Drummers, but I wanted an acoustic kit for this, and not a drum machine. The Drummer plug-in is effectively a MIDI plug-in that outputs MIDI the same as the MIDI FX. Changing the Drummer changed the style, so recording the Drummer output into a MIDI region allows me to move the Drummer’s output into any MIDI track. Here is how I captured the rhythms and fills.

Before Recording

Before any MIDI recording can happen, the “IAC Driver Bus” needs to be turned on for the OS. This only ever needs to happen once, and can be leveraged over and over again.

Go to the Audio MIDI Setup application found in /Applications/Utilities in the Finder:

Open the MIDI Studio Window:

Double-click the IAC Driver object in the window

Check the box for “Device is online” and then click “Apply” if need be.

That’s it. Set it and forget it. Back to LPX…

Recording

In LPX, assume there is a Drummer track that needs to be captured. In this example, this is using “Maya – Modern 80’s” which uses the Ultrabeat plug-in:

In the Drummer track, change the instrument to External Instrument, found in the following path: Utility > External Instrument:

In the plug-in window, change the “MIDI Destination” setting to “IAC Driver Bus 1”. This establishes the connection that allows MIDI to be recorded across tracks:

Create a new track and apply a drum plug-in to it. Here I just used Drum Kit Designer. The specific patch doesn’t matter since I only need to hear some output during recording to verify this works:

In the new track, press the “R” button so that it is red.

Keeping the new track selected, start recording and the Drummer’s output will start showing up as MIDI data in the new track:

Expanding the resulting output shows all of the subtleties the Drummer plug-in puts in place. I’ve found it takes some work to develop this sort of thing, but totally worth the effort. Now all of this data can be moved to any MIDI track.

This also works well for capturing a MIDI FX plug-in output to develop further than what the plug-in allows, like the Arpeggiator and Repeater MIDI FX.

If this doesn’t work for you, then check the following:

  1. The source track is set to use the External Instrument “IAC Driver Bus 1.”
  2. The correct track is set up for recording, with the “R” button red and the track selected.
  3. The IAC Driver is online in Audio MIDI Setup. (a.k.a. Is the computer plugged in?)

Totally non-obvious but totally easy. It has helped me develop new ideas. I culled all of this information from multiple sites, but I haven’t seen it all in one place.

The Perpetually Okay Jazz Band Does A Cover

In this post, I will take an arbitrary melody of notes and turn that into The Perpetually Okay Jazz Trio. I will be doing the following things in this project:

  • Use the MIDI Environment to do two things:
    • Push MIDI data to multiple tracks at once
    • Use the MIDI Transformation object in the MIDI Environment to help with creating human-like playing
  • Create a passable (albiet barely) drum solo with the Randomizer
  • Work in the key of A Major, which requires using the Transposer MIDI Effect

The aim is largely to show how automation in the MIDI Environment in Logic Pro X can be used to great effect. But this is also about just having some fun exploring a part of LPX I don’t normally see in the gazillion YouTube tutorials.

Fair warning, this is going to get very technical very quickly, but totally worth it in the end.

The Music Theory Section

The source melody for this project comes from a long-time personal favorite: “Iceblink Luck” by Cocteau Twins from their album Heaven or Las Vegas (released 1990, 4AD).

The chord progression is a typical pop “I-IV-V-vi” centered progression, but it resolves a lot on the IV; the overall song structure is a nice variation of typical pop; and it’s just a really great song all around. Easily one of my “desert island discs.”

Here’s the original progression:


…which then gets boiled down to the tonics…

 

In the last project, I took the Westminster Chimes melodies and used them to manually create the chord progressions, that we were then used to make the music. Which is fine except for when I wanted to make an edit to the melody, that edit had to have been made in multiple tracks. This is somewhat mitigated by separating notes into regions, but that still means having to copy-paste regions in multiple tracks, and then making further adjustments to get the notes in the appropriate octave.

The melody was in the C3 octave, but the individual parts were spread out to ensure musically everything sounded right:

  • Piano Right Hand: C4 octave
  • Piano Left Hand: C2 octave
  • Upright Bass: C1 octave

The Note Editor has easy functions for shifting up and down semitones, but it can still be easier when I know I will have several tracks working from the same source material. Knowing LPX, there’s a couple different ways to get the same MIDI data into different tracks at the same time, but I view the MIDI Environment as the way to go to position the project for real power over the long term.

Splitting the MIDI Data in the MIDI Environment

The MIDI Environment is how to view the actual connections between objects in LPX’s UI. I think of it as the difference between looking and playing a piano versus opening the top and seeing how things actually connect and work to make sound, and then being able to fiddle with things inside. It is an immensely powerful tool, and this project only scratches the surface. But that power is balanced by being a fiddly and sometimes unforgiving environment. There is Undo, but sometimes it’s non-obvious or something. So, the caveat to this post is that while it makes automation in the MIDI environment look easy, it takes a bit of work to get the connections to work as desired.

The main idea here is to take the melody and feed that to the individual instrument tracks. Then, those tracks then use MIDI effects to create the actual music played, chords and all. As noted earlier, the the Perpetually Okay Jazz Band has discrete tracks for all of the parts, mirrored in both the Track editor and MIDI Environment.

The object I used to send MIDI data to multiple tracks is the MIDI Monitor object. It’s a simple pass-through object that allows you to see the MIDI data as it is sent to instruments.

This monitor needs to be added to the Track Editor to contain the source melody (MIDI Data). 

Just click and drag the MIDI Monitor object into the Track Editor, and click Create in the dialog that pops up. 

To get the data into the MIDI Monitor Track, the MIDI needs to be copy and pasted into the track (dragging doesn’t seem to work the same way as with instrument tracks? I could have messed that up, but I don’t think so).

 

The MIDI Monitor track cannot have an instrument of its own—it is literally just a monitor; the Inspector is completely empty—so now the connections have to be made to the discrete part tracks. This is where things get fiddly.

In the top right corner of the MIDI Monitor object, there is a little triangle (pixelated) which is effectively a patch cable connection.

Clicking and dragging from there creates a virtual patch cable that can be connected to pretty anything else with the same connection.

By connecting the MIDI monitor to the instrument track, I am overriding the connection to the tracks original MIDI source and replacing it with the MIDI Monitor. So, whatever is in the MIDI Monitor track is pushed through the instrument track.

[0311_iceblinkluck_raw_connections.png]
[0312_iceblinkluck_raw_connections.png]
[0313_iceblinkluck_raw_connections.png]

One of the fiddly things about the MIDI environment is that the UI makes it look like the MIDI Monitor is connected to the track on the left when it’s really not.

Moving the track on the left reveals the actual virtual connection.


I duplicated this connection to this connection to the other tracks. Every time a connection is made with the object, a new empty connection appears. These are small UI targets, so just be mindful of what you have grabbed before making connections.

With all three connections made, and the MIDI data in the MIDI Monitor track, press play and here the music played across all of the discrete parts. In the MIDI Environment, the MIDI data can be seen within the MIDI Monitor object.

Of course, this no longer sounds right because the MIDI Monitor just passes through the raw data, which is the single line of melody. This is where the MIDI Effects come in again.

MIDI Effects

In the previous version of the Perpetually Okay Jazz Band, the chords needed for the music was in the MIDI regions for each of the tracks. Also, they were already transposed to the correct octave. But in this project, the MIDI Data is a single line melody of notes in the C3 octave.

Upright Bass

Here is what the Upright Bass plays using the original channel strip, which is just a simple arpeggio.

To create the music, I added three more MIDI Effects.

  • Chord Trigger
  • Transposer to get the produced chord in key
  • Transposer to push the notes down to the correct octave

I need to spend some moe time with the Chord Trigger to understand the theory driving it, but it appears to default to the key of C, so the notes need to be transposed to the key of A to align with the project. The Chord Trigger MIDI Effect doesn’t appear to respect the Project’s key setting.

Also, I could probably do both the C-to-A transposition and the push down to the C1 octave in the same Transposition instance, but I was thinking I might need more discrete control at some point.

Adding the Chord Trigger, I get the “walk.”

Add the first Transposer to get in key.

Add the second Transposer to get in the correct octave.

Piano Left Hand

The Left Hand Piano doesn’t change much from the last version of this project. The MIDI Effect stack is still largely the same.

  • Note Rep
    • Delay 1/8
    • 3x
  • Scripter
    • 181/256
  • Note Rep
    • Delay 1/8t
    • 1x
  • Scripter
    • 128/256
  • Chord Trigger
    • Jazz Standard Left Hand Single

All that’s needed are the two Transposers as the Upright Bass

  • Transposer set to -12 semitones
  • Transposer set to A Major

Piano Right Hand

The right hand for the piano also requires minimal work. On its own, it’s just repeating the same notes in different octaves.

The Chord Trigger is added to give the material needed for the rest of the effects.

Finally, use the same transpotions as before, except going up an octave, and that creates the right had part.

Put the piano and bass together, and two-thirds of the Perpetually Okay Jazz Band is back to where it was, all stemming from the same melody of single notes in the MIDI Monitor track.

What’s important to note here is in the Track Editor, there are no regions because nothing is recorded. In order to record, then another track needs to be made, and the IAC Driver Bus 1 has to be used. (I have instructions to exactly that on my webpage.)

However, because the tracks are all sharing the same MIDI events, they all share the same velocities, which means everything is too consistent. To add some randomness back into the music, the MIDI Environment has the tools to do that.

Random Events in MIDI Environment

Back to the MIDI Environment with the three melodic tracks sharing what’s coming out of the MIDI Monitor. (The screenshots are a bit different from the earlier part because I experienced technical difficulties with how one of the tracks was playing another track’s MIDI events. I’m still not sure what happened, but I just created a new track and that altered the environment. Like I wrote before, the MIDI Environment makes things fiddly.)

I want to add randomness to the velocities like I did with the previous version. But since this happens live while playing, a Transformer object is placed inline between the MIDI Monitor and the Track.

The Transformer has the same dialog as the MIDI Transform in the main UI.

In the dialog, I changed the settings to the following:

  • Top box: Status = Note
  • Middle box: Velocity Random, and a range of 60 through 40.

The operation graph shows the same distribution as in the main UI. When I play the track, I can go back into the Environment to see how the Note MIDI events are being transformed in real time. I duplicated the same transformation for the other tracks. With the Monitors, the events can be seen as having their own randomness applied.

As before, the effect is subtle, but still valuable in making it less robotic.

The Benefit of MIDI Event Splitting

Now that I have this single source of MIDI data for all of the melodic tracks, if I want to make an edit, I only need to do it one place. So, let’s say I want to do something totally goofy and make an upside down mirror image of the melody. I can apply the Reverse Position and Reverse Pitch MIDI Transforms, apply a couple quick transpositions to get into key, and then voila!

The Perpetually Okay Jazz Band is playing the “new” music just same way as before. In the previous project, I would have to do those transformations and transpositions in every track that had data.

The Drum “Solo”

At the 2:33 mark of the song, there is an instrumental part. Chords change to iv-V-IV-I, and the drums follow along on the toms. For this portion, I updated the drums to hit more toms in a similar cadence as the rest of the song.

In the original Westminster Chimes piece, the drums were separated out into three discrete tracks: Ride, Snare, and Hi-hat+Kick.

In this piece, I separated out the Snare into two discrete tracks, with the simple logic of one drummer has two hands with a single stick in each, which means they can only hit one drum at a time with each hand.

The Snare Swing Track is still the snare drum and remains unchanged from before. It still has the Note Repeater and Randomizer MIDI Effects. The MIDI events are still moving around the different snare sounds, with some phrasing by measure with rimshots.


The Snare Solo Accomp. Track uses the same MIDI Effects, but shifts the Snare pattern up to the Mid and Hi Toms.

To make the switch to the instrumental portion, automation is used to make three things happen. Before the instrumental, the Randomizer is applied to three tracks:

  • Ride: 128/256
  • Snare Swing: 80/256
  • Snare Solo Accomp: 0/256, effectively shutting this off because 2 sticks only.

In the instrumental, automation on the Randomizers changes them to the following:

  • Ride: 0/256, effectively shutting this off because 2 sticks only.
  • Snare Swing: 126/256
  • Snare Solo Accomp: 129/256

I won’t get into the details of how I landed on the settings for the snare and times, except to say that’s what ended up sounding good to my drummer’s ears.

One additional change I made to the drums was to the Ride track, where I added in some cymbal hits. I felt the phrasing between different song parts, like verse and chorus, were hard to distinguish, so I added the cymbal hits as clues that the music was entering into a new part.

The following sample is 8 measures of the main groove, then the 8 measures of the instrumental portion, then the last 8 measures of the piece.

Like so much else, it’s…(say it with me)…okay. There’s clearly some work to be done, but I think it’s a good start.

Putting It All together

At the end of the project, the only tracks with MIDI Data are the Drums (though I think some signal splitting is possible given the patterns), and the MIDI Monitor. Everything else is handled in the MIDI Environment and the MIDI Effects.

Even if the music isn’t great, it’s still a useful setup to understand for future uses. I think the next challenge is to do some synthwave with the Randomizer, automation, and MIDI Environment, and see if I can craft some decent pop(-ish) music with this.

And that’s that. If you have any questions, please feel free to reach out via the email address casually buried in my About page, and you can also find me on LinkedIn. In the meantime, I hope you enjoy reading these as much as I enjoy making them, and never, ever stop making music.

The Perpetually Okay Jazz Band

The Perpetually Okay Jazz Band: A Practical Application of Random Note Suppression in Logic Pro X

In this post, I will use the randomizer function I posted about previously to create a complete jazz trio—piano, bass, drums—from a single chord sequence, specifically a jazz “walking” groove. The way this works is I use LPX’s MIDI effects to create as many notes as possible based on a simple chord progression, and then use random note suppression to shape the sound. This leads to a reasonably-sounding and loop-able jazz piece that technically could never end.

Here’s the musical caveat to all this: I call this “Jazz” but it’s not like some kind of true jazz purists will appreciate. I’m a mostly fan of jazz, a musician by hobby, and I know enough music theory to get me in trouble but not enough to completely justify my musical choices. This just came out really well to my ears considering the simple random function I created in the last post.

The reason why I am writing this is because the last piece of music came out really “spacey,” and I did some more noodling around and landed on the piece I built here. I caught myself by surprise that such a sample random number function can be used to such great effect. The music is almost secondary to that point. But only almost, because this project needed both the music and the random numbers to work. Whatever.

The Music Theory Section

“If you play the wrong note once, it’s a mistake. If you play the wrong note twice, it’s jazz.”

The melody at the heart of this project will be the venerable Westminster Chimes. This will be done in the key of C Major. Nothing fancy, but it will be illustrative here. I’ve tried other chord sequences, and they still work really well provided they aren’t too jumpy.

From this, I create some basic source material by expanding the melody into different kind of chords.

Using the melody as tonics for chords, the melody became I, IV, V, and vi chords. So, I built a set of those. (As I am reading the final draft, I realize one of the chords is incorrect and that mistake is carried through the whole post. But I’m not going to update this entire post over it.)

At the same time, we’re going for jazz, so I need 7ths and inversions, which will become very import later to help keep the bass line tempered.

The chords are the building blocks of the jazz sound other than the drums. The song tempo is set to 80 bpm, which is important in adding nuance later because so many notes are created.

The Rhythm Section

Drums

“If you’re swinging and the drummer isn’t swinging, then you’re not swinging. If you’re not swinging, and the drummer is swinging, then you’re swinging.”

I started off with the most basic of jazz rhythms. Initially, this sounds totally mechanical, like a good computer should. This is where I add the first real randomness.

For the drum patch, I just use the pre-defined Retro Rock kit. LPX doesn’t have any kits that are obviously jazzy. I like the cymbals in this kit and I was too lazy to fiddle with the shells. Besides, it just looks cool.

In the MIDI editor, I randomize the velocity of each note to add some imperfections by going to Functions > MIDI Transform > Random Velocity. Within the selected MIDI regions, it selects the note events and randomly chooses a new velocity for each within a range you specify. The tool defaults to a range of 40–127, which is I consider to be too extreme for almost all of my uses in these projects.

I prefer a range of 80–100 because it sounds good, and gets the velocities within a reasonable range that will make adjusting easier later.


The effect is subtle at this velocity but it’s effective when I lower velocities to give more of that jazz trio feel. To do this, I manually selected all of the notes, and lowered their velocities using the slider in the right. For this piece, I moved everything from ~85 to ~50.

Shaping the Drum Sound

Now that the core rhythm is settled, I made changes to it to allow the MIDI effects to take over. Basically, the way this works is by creating as many notes as possible within the rhythm’s contours, and then randomly dropping notes to mimic a human playing. To do this, certain instruments have to be separated since MIDI effects are all or nothing without some custom coding. By having the individual drum parts in their own tracks, it’s far easier to add nuance.

The first thing I did was get the ride cymbal set up. I took those notes and moved them to their own separate track. I removed the swing note and just placed notes on the eighth beats. I also extended the region out to a full measure to allow for some phrasing, which is at the end with the ride bell.

The swing notes are added in with the Note Repeater. It repeats once at the 8th triplet to get the shuffle.

The randomizer function is added to drop notes, which gives the ride an improvisational feel. I played with the threshold and settled on 128/256 to balance the swing feel without it being a full on shuffle.

Adding that back into the mix makes for something a lot less mechanical, but I’ll get to that later. The kick and hi-hat are left relatively untouched on their track.

Turning to the snare, the same MIDI effects apply as they did on the ride. For the playing itself, I updated the rhythm so that it moved around the snare a bit over the course of the measure. Most of the time is spent on the snare edge, with movement to the center for variation, ultimately hitting a rim shot for some pop at the end of the measure.

With the Note Repeater, it sounds like marching drum.

With the randomizer, it went into more improvisation.

Combine the whole kit together, and it sounds mostly like a person playing this, kind of a “popcorn” feel to it.

I tried lowering the snare’s random threshold a bit to have it be less noisy, but that was kind of splitting hairs for this piece.

Bass

For this project, I didn’t do too much with the bass. I wanted the piece to have that “walking” feel to it, so a simple arpeggiation of the non-inverted chords is all that is needed here.

I treated the velocities the same as the drums, randomizing between 80–100, and then bringing down to within the ~50 range. I also pulled the chords down into the C1 range. For the patch, I used the default Upright Bass.

Easy peasy. When combined with the drums, it starts to really take shape and sounds like a couple of musicians just kind of surfing or walking along with each other.

Piano

“One chord is fine. Two chords you’re pushing it. Three chords you’re into jazz.”—Lou Reed

The piano was hard to get right, and it was really gave this project the moniker of “Okay.”

I knew up front that I wanted the left and right hands to play differently, so there I created a track for each.

Right-Hand Track

On the right hand track, I moved the dynamic sequence I used for the bass up to C4.

I applied the same MIDI effects as in the last article:
* Arpeggiator
* Randomizer
* Note Repeater
* Randomizer

Again, the idea here is to create all the notes possible within a listenable range, and then suppress notes to shape the sound. Here, the Arpeggiator creates the initial bunch of different events based on a given chord to play with, and then I randomly suppress those with the randomizer. If I had the suppression on before the Arpeggiator, the music would be immediately repetitive, mechanical, and in all-or-nothing bursts. In another context that would be desirable, like maybe with the bass piano notes, but not here. The Note Repeater comes next to add some rhythm, and the random suppression plays the same role as with the Arpeggiator.

I randomized the velocities as with everything else, with a range of 80–100. Then, I fiddled with the various effects settings for a good hour to get the feel of a keyboardist kind of surfing on top of the chord progression. In the end, I settled on the following settings:

Arpeggiator: Rate 1/16, Note Order Down-Up, Variation 4, Octave Range 2, Swing 99%

Randomizer: 128

Note Repeater: Delay 1/2 triplet, Repeats 2, Velocity Ramp 110%

Randomizer: 128

On it’s own, the right hand track is good enough, but will sound a lot better when mixed with the rest of the tracks.

Left-Hand Track

For the left-hand portion, I tried all of the different sequences, and ultimately settled on the 7th Inverted chord sequence moved down into the C2. This helped to ensure the melody on the right hand is supported while not being overwhelmed by the bass, and not overwhelming the upright bass.

The MIDI Effects settings are a little different than with the right hand, effectively making the left hand less busy than the right hand.

Arpeggiator: Rate 1/8, Note Order Down-Up, Variation 4, Octave Range 1, Swing 50%

Randomizer: 128

Note Repeater: Delay 1/2 triplet, Repeats 2, Velocity Ramp 70%

Randomizer: 128

The piano bass was tough to get right, and I’m still not happy with it. But like all good projects, this, too, shall be abandoned.

On a more technical note specific to LPX, to help with editing and organization, the piano and drum tracks are grouped into their own Summing Track Stack.

Putting It All Together

“Jazz isn’t dead. It just has a funny smell.”—Frank Zappa

Anyway, now that all pieces were completed, I put it all together with a bit of mixing. This is the all five sections of the Westminster Chimes looped twice.

Next Steps

I can add more of a proper arrangement to the whole thing by removing some of the 7ths, going back to some un-inverted chords, fiddling with the MIDI effects, etc. But for now, put together, it’s perfectly okay. And since this is all loop-able due to using effects and functions to create the music on top of any chord sequence, it can be perpetual, too.

Epilogue: Piano Left-Hand Track

Soon after writing this, I reworked the the piano’s left-hand track to mimic more of what I had in mind. It was really supposed to more of the chords being played improvisational to a swing beat. I had a use a very specific combination of MIDI effects to do this, while also introducing the Chord Trigger MIDI effect.

  • Note Repeater
  • Randomizer
  • Note Repeater
  • Randomizer
  • Chord Trigger

I started with a shortened-note version of the Westminster Chimes.

Then, I added a Note Repeater with simple settings to build more events. setting creates roughly the same rhythm as the unmodified snare and ride cymbal.

Then I added a Randomizer with a setting of 181/256. It’s an oddly specific setting considering the other settings so far, but I really had to fiddle with the settings for both to get the feel I was looking for.

The second note repeater comes into play to add the swing feel. by repeating once at 1/8 triplets.

The second randomizer is added to help shape it one last time with the now-venerable setting of 128/256.

Finally, the Chord Trigger MIDI Effect is added to create chords that pop. I added a custom patch to the Chord Trigger because I (really, really, really) didn’t like the defaults. I’ll confess a lack of jazz theory, but they just didn’t sound good.

Finally, I did only the range of this piece if only because the effect seems too cryptic to do this work easily across the whole keyboard.

Putting It All Together. Again. For The Very First Time.

Put it all together, and now this sounds more like what I had in mind. So, here is the original piece with the new piano left hand track.

 

LPX Scripter: Random MIDI Event Suppression

About

I’ve been playing around with LPX’s Scripter, starting with random numbers a bit since Scripter utilizes Apple’s JavaScriptCore framework. I find music automation to be a fascinating topic, because it combines my enjoyment of random numbers, from years of board games and role playing games, and music theory and composition, even though my skill in the latter is not nearly as strong as in the former.

One of the first scripts I created has been a lot of fun to play with. It randomly suppresses MIDI events at any point in the MIDI FX chain based on a simple percentage chance of the event actually happening. Here is the script as a whole, suitable for copy and pasting into Scripter.

/* Apple API */
var PluginParameters = [];

/* Mute Threshold Slider */
var resolution = 100;
var minValue = 0;
var maxValue = resolution;
var numberOfSteps = resolution;
var defaultValue = resolution / 2;
PluginParameters.push({ name: "Play %", type: "lin", unit: "", minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, defaultValue: defaultValue });

/* Apple API */
function HandleMIDI(event) {
        if (event instanceof NoteOn) {
            if (triggerEvent("Play %")) {
                event.send();
            }
        }
    else {
        event.send();
    }
}

function triggerEvent(name) {
	var p = GetParameter(name);
	return (Math.round(Math.random() * resolution) < = p) ? true : false;
}

N.B.: I updated this code since the original post to better manage the resolution of the control, and change the Math.ceil to Math.round because even the thought of there being bias was bugging me.

Use Cases

This script is an easy way to create variations in your music, particularly when combining it with other MIDI FX. It's best used when in combination with other MIDI effects.

  1. I have found it useful for exploring different synth settings and sounds while letting the computer run around the keyboard playing in a reasonable approximation of human playing. Tinkering with synths becomes a lot easier when someone else is playing for me.
  2. Applying it to a drum track can create variations that run the gamut from jazz to Aphex Twin-like beats.
  3. Applying it to a chord progression can create any number of musical variations. There are a number of Apple loops that are also MIDI data, and this can be used to find variants of those loops. 

It's that last use case where I have had the most fun. I particularly enjoy ambient techno music, harkening back to the Instinct Ambient label through today (Apple Music's curated "Pure Ambient" playlist is now my go-to resource). Combining this script with the other MIDI effects and applying to a good chord progression has led to some interesting music. It's random, so it's not all perfect, but every once in a while I get a good hook worth playing with more.

How It Works

The script is fairly straightforward as far as Scripter goes, and it's easy to add it into LPX and start using it. But here is how it works for readers unfamiliar with Scripter in general. Hopefully someone in the LPX community will learn something new and apply Scripter in new and interesting ways.

First, the user-changeable control is created. I have detailed information about how controls are managed on my documentation page for Scripter Controls.

/* Apple API */
var PluginParameters = [];

/* Mute Threshold Slider */
var resolution = 100;
var minValue = 0;
var maxValue = resolution;
var numberOfSteps = resolution;
var defaultValue = resolution / 2;
PluginParameters.push({ name: "Play %", type: "lin", unit: "", minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, defaultValue: defaultValue });

By default, this is set to a simple percentage. But I have found that when I get into the lower percentages to create more spacious or elegant melodies, 0%–20% isn’t enough, and more nuance is desired. To resolve this, I change the resolution variable to a higher number like 256. I’ve found anything more than that is kind of pointless, and too high a number results in unexpected behavior in the slider.

As a style matter, Apple’s examples place this code at the end of the scripts, but I prefer to have them at the beginning, if only because it’s the first thing I see when I open Scripter, and it makes tweaking the UI really easy since the Editor is tricky to use.

Next comes the actual triggering of a MIDI event. Essentially, if the NoteOn event is detected, then it calls a custom function that determines whether to suppress the event or not. Every other kind of event is passed through harmlessly.

/* Apple API */
function HandleMIDI(event) {
	if (event instanceof NoteOn) {
		if (triggerEvent("Play %")) {
			event.send();
		}
	}
	else {
		event.send();
	}
}

Because we only care about whether a note should play or not, the function looks for the NoteOn MIDI event. This does not look for “parent” Note events because the NoteOff event needs to be handled later, which I’ve learned is kind of a hassle to manage manually with the minimal troubleshooting the editor provides.

This is an important distinction, because if the Note event is handled but not NoteOff, then a real cacophony of sound quickly builds, and processes peak out with too many MIDI events. This outcome is obscured with quickly-releasing notes and percussion, but is quickly obvious with instruments that never release, like the organs, and when recording MIDI output to another track.

The triggerEvent function which does the actual work of determine whether a note is played is simpler than it looks. All it does is take the user setting from a slider with a given name, randomly gets a number between 1–100, then returns true if the user value is less than or equal to the random number.

function triggerEvent(name) {
	var p = GetParameter(name);
	return (Math.ceil(Math.round() * resolution) <= p) ? true : false;
}

I don’t recall where I found the specific code that creates the random number, but it works fine for what’s being done here. Without getting into too many details, here is how it works. Math.random effectively returns a number between 0 and 1. That number is multiplied by 100 to make it a percentage. Math.round makes it a whole number. The resulting integer is compared to the user’s setting, and if it’s less or equal to the random integer, it returns true, else it returns false.

How to use in a channel’s MIDI FX

This script is used in the MIDI FX section of a channel (highlighted in red below). Note, this can only be used with MIDI FX, and other track types like audio and some drum machines will not allow for it.

By itself, the script simply determines whether a note should be played or not. The real action is when chaining with other MIDI FX, which I’ll get into in the next section.Example channel showing how the random suppression script can be chained with other MIDI effects in the MIDI FX chain.

The behavior in Logic we are leveraging here is that MIDI events are passed through the same way as other signal processors in a channel: from the top down. Events are triggered by the input, and then intercepted by the topmost MIDI FX in the chain. Results of that MIDI FX is passed onto the next MIDI FX.

In the above example, there are three effects in the MIDI chain:

  1. “Scripter” is the random note suppression script. (If only there was a way to show a custom script name in the UI.)
    1. The script determines whether a note should be played (the NoteOn event executed). Those events are passed to the next effect.
  2. “Arp” is the built-in “Arpeggiator” effect.
    1. Arpeggiator can create new events based on the passed event. All of those events are passed to the next effect.
  3. The second “Scripter” is another independent instance of the random note suppression script.
    1. This instance determines which events sent to it from Arpeggiator get played.

Of course, further effects can be added, with this random suppression script in between them, to create some fun and surprising variations, which I dive into in the next section.

Step-by-Step Usage

I highly recommend setting up a MIDI channel to record output data to another channel like I have in this example. I have instructions on my site on how to do this in the Logic Pro X section.

Per that setup, here are two tracks, one with a simple chord progression.

The chord progression in the “Source” track will be the source material for everything to come next. MIDI effects will be applied to it, and the results will be recorded in the “Output” track. When everything is setup correctly, I am able to record the looped MIDI region in the source track to the output track as a single region.

Adding the script on its own, and setting it to 50% (the default) results in the following output.

This is the default output of the script, which is largely uninteresting on its own. Typically, I go down to 33% for the chords so I can prevent whole chords being played, and 20% if I want something akin to tonal accents. Once I get settled on the probability, I add in more MIDI effects like the Arpeggiator to make things more interesting.

Adding the Arpeggiator, set to the default patch, and adding another instance of the random suppression script yields the following output.

Now I have something that is more interesting and playful, if repetitive. As before, the random threshold is still the default, and I always makes some adjustment to get the desired effect. But, even with the default, it’s not half bad.

Playing with the settings in Arpeggiator yields more interesting results by increasing the octave range, note order, and other settings. Changing the patch from the default to Chord Groove 1 changes the output in subtle but important ways.

This gets into something more interesting and somewhat realistic. I only changed the Arpeggiator patch, and left the suppression threshold alone.

Next, I’ll add the Note Repeater MIDI effect, set to the “Five Up” patch, which transposes pitches upwards and lowers the velocity on each repeat. Then, I’ll add yet another instance of the random suppression yields the following results.

It’s a bit much, and now it sounds like something from a 60s science fiction movie, which can be cool in its own way. Changing the last random threshold yields more manageable results.

Okay, so it’s still a 60s sci fi movie, just not as noisy. But the point here is between the various MIDI effects, there now exists massive potential for productive experiments with easy ways to shape the sound as desired.

Generally, this is the channel patch I wind up on, with everything in the chain, adjusting and disabling effects as needed. The output becomes really fun with the ES-series synths, but I have also been able to get scarily good human-like output with the judicious use of random suppression and the arpeggiator.

Further Development

Given Scripter’s MIDI API and use of JavascriptCore, there are obviously a lot of directions for development. Reviewing Apple’s sample scripts yields a bunch of ideas, like handling suppression and shaping for specific pitch ranges like on a drum kit patch, making crazy blast beats on the kick drum or build a new kind of sequencer.

So, that’s it. If you have any questions, please feel free to reach out via the email address casually buried in my About page, and you can also find me on LinkedIn. In the meantime, have fun with the script, and never, ever stop making music.

Retrograde Inverted Fragmentation

I’ve been spending my spare time learning more about music composition to go along with my work in Logic Pro X. I came across this fantastic quote in a book I picked up for cheap:

When given a theme or a motive, there are really only two possibilities: repetition [and] change. Repetition is self-explanatory. Change can be as simple as a sequence or can become quite abstract (retrograde inverted fragmentation, for instance). Instead of tying yourself up in knots, try applying basic operations to what you already have. Not only will this likely bust through your block, but it will also enhance organic coherence of your work (constant change is disorienting to the listener–this is undesirable unless its an affect you’re aiming at).

Brandon Nelson, Composition Toolbox: Practical Ideas to Inspire

Two quick thoughts about this quote.

  1. It sounds like good generalized advice along the lines of “when in doubt, go back to the basics.”
  2. I have no idea what “retrograde inverted fragmentation” is, but it sure sounds like fun.

Logic Pro X Scripter Editor and Controls

Update: I have made this a top-level documentation page on my site. Go there for any updates on this content.

I have been noodling around with the Scripter plug-in in Apple’s Logic Pro X. It is very powerful but also very wonky. Apple has good documentation for it, but inconsistent between the ePub versus the website, though the website looks more complete. Much more can be gleaned from the example scripts, but even then there are behaviors that are not documented anywhere, and the code can be challenging to read if you have little to no experience with Javascript. This post aims to clarify how the Scripter Editor works, and what is expected by both the compiler and the user to build controls for a script.

The Editor

I’ll leave to Apple’s documentation an overview of the Scripter Editor and just dive into the undocumented and undesirable behaviors.

The editor itself, as a Javascript editor is barebones and has none of the features a developer would expect. There is no autocomplete, and formatting is wonky where indentation is inconsistently applied between tabs as 2 and 4 character widths.

Also (and probably worst of all), there are times when the editor will stop compiling to the UI. I was able to jumpstart the editor with a major code change, completely shutting off and reloading of the Scripter plug-in and desired script, and even having to escalate restarting Logic Pro X. The escalation seemed to be necessary more often when I doing a lot of Run Script actions to parse the code, but this wasn’t consistent enough to be hard fact.

There are a few keyboard shortcuts that are specific to the editor. The usual Cut, Copy, and Paste are all supported, but you must be careful you have the correct focus or else you will mistakenly make changes in your project. Beyond that, all other keyboard shortcuts are reserved for the Project window, and the Editor has only these left specific to it:

  • Increase text size: Shift+Option+”+”
  • Decrease text size: Control+Option+”-“

To save a script update, you must go back to the Scripter plug-in menu for that script and select “Save” in the main pulldown menu. Pressing Cmd+S will only save the Project, and that save will not include the Script.

I have to rant a little bit here and state that in spite of the power provided by the Scripter plug-in, the editor is by far the single worst editing tool I have ever used, and very surprising to come across something this poor of quality from Apple. I understand Scripter is deep in the recesses of an already niche and complex app (it’s not even listed on their marketing pages as a feature), but I have to imagine if Apple wants more widespread use of Scripter, then they have a lot of work to do with the editor to get more developers to engage with it.

Controls

Controls aren’t necessary to use Scripter, but they make life a whole lot easier than trying to tweak events in code. This section is a detailed examination of their requirements and behaviors. For each control the following information is provided for each property where relevant:

  • Property name.
  • Property Datatype.
  • Is the Property required by Scripter? For the type property, the actual string expected by Scripter is given, as opposed to just a description.
  • Notes detailing expected values, quirks, and limitations.
  • The return value as captured in the ParameterChanged function.

For the purposes of this post, assume in all of the example controls are being pushed to the API’s PluginParameters array upon initialization.

var PluginParameters = [];
PluginParameters.push({name:"Excelsior!", type:"text"});

Also, assume that all controls must have the following properties specified upon initialization:

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String Yes Partially determines the type of control. Values possible are “lin”, “log”, “menu”, “checkbox”, and “text”. This list is not exhaustive to the types of controls possible. If a particular string is expected by the Scripter compiler, it will be noted in the “required” field.

Different types of controls have different requirements, but all must have those two (which will be called out in each of the listings anyway).

Linear Slider

The Linear Slider is the most obvious use case for affecting MIDI events, and is straightforward to use within the typical number ranges of MIDI: 0–12 chromatic notes, 0%–100%, 0–127 pitches, etc. However, some experimentation is required when working with higher ranges like 0–1000 milliseconds or ranges requiring very fine precision.

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “lin”
minValue Integer or Float No The minimum value for the slider. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 0.00 to the property, and an error will be thrown saying a value is missing. The integer or float can be signed.
maxValue Integer or Float No The maximum value for the slider. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 1.00 to the property, and an error will be thrown saying a value is missing. The integer or float can be signed.
defaultValue Integer or Float No The maximum value for the slider. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 0.00 to the property, and an error will be thrown saying a value is missing. The integer or float can be signed.
numberOfSteps Integer No The number of increments between minValue and maxValue. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 100 to the property, and an error will be thrown saying a value is missing.
unit String No A label shown next to the number in the control to give a unit description if desired. The script will not crash if no value is given, no default will be assigned, and no error will be thrown. Nothing in the provided string will affect the slider’s calculations or settings.
Return value Integer or Float

In general, the linear slider is fairly forgiving when it comes to missing values, but the actual values derived can be unexpected. While the UI will show an appropriate level of precision—tenths, hundredths, thousandths at most—the console reveals far finer precision that may not be useful.

Notes on numberOfSteps

No minValue and maxValue

When no values are given for the minValue, maxValue, and defaultValue properties, Scripter will assign values of 0.00, 1.00, and 0.00 respectively, with the slider incrementing between 0.00–1.00 by the hundredths. So, 0.42 can be a setting for the slider.

numberOfSteps exceeds the difference between minValue and maxValue

If the numberOfSteps value exceeds the difference between minValue and maxValue, then Scripter will divide maxValue by numberOfSteps and use the result for the incremental values, rounding up at certain times. How the control divides the steps is not entirely predictable.

For example, if a slider is set to use 0.00 for minValue, 1.00 for maxValue, and 300 for numberOfSteps, then only values divisible by 0.003 are selectable. Starting at 0.00 and incrementing up the selectable values are 0.000, 0.003, 0.006, 0.010, 0.013, 0.016, 0.020, and so on.

Another example, if a slider is set to use 0 for minValue, 100 for maxValue, and 1000 for numberOfSteps, then only values with a tenths precision are selectable. Starting at 0.000 and incrementing up with the up arrow, the selectable values are 0.000, 0.100, 0.200, 0.300, 0.400, 0.500, 0.600, and so on. However, when the actual slider control is moved to the right, then sometimes values jump to 0.399, 0.599, and so on.

In both cases, the console will output values that are typical floating point values:

2
1.899999976158142
1.8200000524520874
1.7400000095367432
1.6600000858306885
1.5800000429153442
1.5199999809265137
1.440000057220459
1.3799999952316284
1.3200000524520874
1.2600001096725464
1.2000000476837158
1.1400001049041748
1.100000023841858
1.040000081062317
1

Notes on minValue and maxValue

maxValue is less than minValue

If the maxValue is less than the minValue, then the control will behave as expected, moving from the left to right decreasing in value. For example, if a slider is set to use 1.00 for minValue, 0.00 for maxValue, then the slider goes down by the expected increment.

Examples

To create a percent slider set to 50%:

{name:"Linear Slider", type:"lin", unit:"%", minValue:0, maxValue:100, numberOfSteps:100, defaultValue:50}

To create a slider that selects between a range of -12–12, set to 0:

{name:"Linear Slider", type:"lin", minValue:-12, maxValue:12, numberOfSteps:24, defaultValue:00}

Logarithmic Slider

The Linear Slider is another use case for affecting MIDI events, but requires special considerations for its uses when working with number ranges involving very fine precision or negative numbers.

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “log”
minValue Unsigned Integer or Float No The minimum value for the slider. This must be a number greater than or equal to 1. If the value is less than 1, then Scripter automatically assigns it to a value of 1.0. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 1.00 to the property, and an error will be thrown saying a value is missing.
maxValue Unsigned Integer or Float No The maximum value for the slider. This must be a number greater than or equal to 1. If the value is less than 1, then Scripter automatically assigns it to a value of 1.0. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 1.00 to the property, and an error will be thrown saying a value is missing. The integer or float can be signed.
defaultValue Unsigned Integer or Float No The maximum value for the slider. The script will not crash if no value is given, but two things will happen. Scripter will assign the value as 1.0, and an error will be thrown saying a value is missing. The integer or float cannot be signed.
numberOfSteps Integer No The number of increments between minValue and maxValue. The script will not crash if no value is given, but two things will happen. Scripter will assign a value of 100 to the property, and an error will be thrown saying a value is missing.
unit String No A label shown next to the number in the control to give a unit description if desired. The script will not crash if no value is given, no default will be assigned, and no error will be thrown.
Return value Integer or Float

In general, the logarithmic slider is less forgiving than the linear slider.

Notes on numberOfSteps

No minValue and maxValue

When no values are given for the minValue, maxValue, and defaultValue properties, Scripter will assign values of 1.00, 1.00, and 1.00 respectively, with a value of 1.0 being given regardless of the slider’s position.

numberOfSteps exceeds the difference between minValue and maxValue

If the numberOfSteps value exceeds the difference between minValue and maxValue, then Scripter will maintain only a precision of hundredths in the UI, but the console will show far more precise values (typical floating point values). How the control divides the steps is not entirely predictable.

In all cases, the console will output values that are typical floating point values:

2
1.899999976158142
1.8200000524520874
1.7400000095367432
1.6600000858306885
1.5800000429153442
1.5199999809265137
1.440000057220459
1.3799999952316284
1.3200000524520874
1.2600001096725464
1.2000000476837158
1.1400001049041748
1.100000023841858
1.040000081062317
1

Pulldown Menu

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “menu”
valueStrings Array of Strings Yes An array of strings for the user to select in the pulldown menu. There does not appear to be an unreasonable limit to the number of strings. (I was able to add 1024 strings without any issue.)
defaultValue Unsigned Integer No A 0-based index value referencing one of the strings in the valueStrings array. If no number is given, or the value is out of the array bounds, then the first menu item (item 0) is selected.
Return value Integer that is the 0-based index of the item selected.

Examples

A pulldown menu with 3 items, and the last item set as the default

{name:"Pulldown Menu", type:"menu", valueStrings:["Item 0", "Item 1", "Item 2"], defaultValue:2}

Radio Buttons

Radio Buttons are a type of menu, with only two strings in the valueStrings array. If more than two items are added to the valueStrings array, then the menu automatically converts into a pulldown menu. Because of the two-item limit, radio buttons are really just a variation of the Checkbox control.

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “menu”
valueStrings Array of Strings Yes An array of two (2) strings for the user to select in the pulldown menu.
defaultValue Unsigned Integer No A 0-based index value referencing one of the strings in the valueStrings array, so 0 or 1. If no number is given, or the value is out of the array bounds, then the first menu item (item 0) is selected.
Return value Integer that is the 0-based index of the item selected.

Examples

A pair of radio button with “On” and “Off” labels.

{name:"Radio Buttons", type:"menu", valueStrings:["On", "Off"]}

Checkbox

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors.
type String “checkbox”
defaultValue Unsigned Integer No Use 0 for unchecked or 1 for checked. If no number is given, or the value is out of the array bounds, then the checkbox is left unchecked.
Return value 0 for unchecked or 1 for checked.

Examples

A checkbox with the box set to be checked.

{name:"Checkbox", type:"checkbox", defaultValue:1}

Text Control

The text control is a simple label that is used to help organize controls in the interface. But the length of the label is very limited, so if you need to include a “Readme” or instructions, best to add those as comments or a separate text file to travel with the script.

Property Datatype Required Notes
name String Yes The String used for a given control must be unique for the entire script. Having two controls with the same name will have unexpected behaviors. The String has a visible limit of approximately 45 characters. This limit not set by the compiler, but instead by the physical layout of the control.
type String “text”
Return value None.

Examples


{name:"My Text Label Control", type:"text"}