Extracting pattern's analytic expression from already executed code

Hi everyone!

I am trying to convert a midi file into a regular Pattern expression, so that I can change some of the it values and behaviors, e.g. I would like to load a MIDI file and have a general Pbind code whose pairs represents the MIDI values.

When using SimpleMIDIFile it is possible to create a pattern (a Ppar) that executes the MIDI file appropriately. Is it possible to extract the raw user side code that have originated this pattern?

// download a Bach midi file:
"curl http://www.bachcentral.com/BachCentral/ORGAN/toccata1.mid -o ~/Desktop/toccata1.mid".unixCmd;

// read it
m = SimpleMIDIFile.read( "~/Desktop/toccata1.mid" );

// play it (cmd-. to stop)
m.p.play; // takes a few seconds to start because this midifile starts with a rest
m.p.postln;

I know that the contents of this Ppar are available when I execute m.p.inspect, but is it possible to obtain the original expression like this?

Pbind(
\instrument, \default,
\dur, Pseq ([1, 2, 3, 4], 1),
\chan, Pseq([1, 2, 3, 4], 1),
\midinote, Pseq([1, 2, 3, 4], 1),
\amp, Pseq([1, 2, 3, 4], 1),
\sustain, Pseq([1, 2, 3, 4], 1),
);

All the best,
Fellipe

If you’re willing to hack around some, this is code that I wrote for a project to ingest MIDI files so they can be used with patterns:

The LOADER loads one or more midi files (according to the path passed in, see example), merges the content onto a single timeline, and returns an OSequence of Events. From there, you can use OSequence:asStream to turn it into a regular Event stream (ala a Pbind). LOADER does some smart things, like combining several notes at the same point in time into one Event. There may be some parameters to tweak to control this, you’ll have to look at the source.

PBIND_PHRASE takes the events returned by LOADER and turns them into separate streams of values, and an actual Pbind filled with Pseq's as you described. It also does things like unwraps \midinote values back into a \degree plus \octave. I think it even adds an appropriate \scale value - it’s debatable whether this is useful… :slight_smile:

These require a few Quarks, specified in the example. You’ll have to read the docs of those to clarify what those components do. Though there’s no real need to use them extensively, OSequence is a useful way to perform operations on sequences of events.

1 Like

Hi @scztt , thanks for sharing this!!

Is there something missing? when running the lines

var metaphrase, metabind;
#metaphrase, metabind = Require("PBIND_PHRASE").(~eventStream);

I am getting the error message:

ERROR: Message 'minItem' not understood.

I just fixed in my gist, try grabbing PBIND_PHRASE again. Though, you’ll also see this error if ~eventStream is nil, so make sure you’ve successfully loading something via the previous LOADER step.