Architect beta for macOS, Windows, and Linux. 0.10.5 now available

Official support for: loomer.co.uk
Post Reply New Topic
RELATED
PRODUCTS

Post

cturner wrote: Wed Dec 04, 2019 8:43 pm Hi Colin! I hope you're doing well?
I am, very well indeed. I trust you are well, too?
(Side question: when I see a warning in the console, does the succeeding [print] object print the data that caused the warning, or does the warning abort the print?)
The latter: any error will abort the event, so if you want to print what is causing the [unpack tuple] error, you would need to ensure that the [print] module goes before the [unpack tuple].
Architect, the modular MIDI toolkit, beta now available for macOS, Windows, and Linux.

Post

Related to the patch (troubles) I’m having though, I assume that the order of output on a multi-output object like [unpack MIDI] runs from left to right? So any further processing of the pitch output executes before velocity, for example?
Tranzistow Tutorials: http://vze26m98.net/tranzistow/
Xenakis in America: http://oneblockavenue.net

Post

(I think we were both replying at the same time.) Yes, I’m well thanks. Still very much enjoying your Architect!
Tranzistow Tutorials: http://vze26m98.net/tranzistow/
Xenakis in America: http://oneblockavenue.net

Post

cturner wrote: Thu Dec 05, 2019 10:35 amI assume that the order of output on a multi-output object like [unpack MIDI] runs from left to right? So any further processing of the pitch output executes before velocity, for example?
Yes, that's (generally) correct: most modules will output left to right. There are a few exceptions: I can't enforce this order in a custom Lua script, for example. But it's true in most cases, and certainly is in all situations where a single inlet event will causes multiple events to sent from a number of outlets.
Architect, the modular MIDI toolkit, beta now available for macOS, Windows, and Linux.

Post

Thanks Colin!
Tranzistow Tutorials: http://vze26m98.net/tranzistow/
Xenakis in America: http://oneblockavenue.net

Post

Colin, another question if you would be so kind: can I use the [pack noteon] object for both noteons and noteoffs? In other words, a noteon of zero velocity and false coupling? I think one of my current troubles is having to split flow of execution between two [pack] objects, when it’s really just a question of a datum.
Tranzistow Tutorials: http://vze26m98.net/tranzistow/
Xenakis in America: http://oneblockavenue.net

Post

cturner wrote: Thu Dec 05, 2019 1:02 pm Colin, another question if you would be so kind: can I use the [pack noteon] object for both noteons and noteoffs?
I was about to say you can't, but once I checked and it seems that you can create noteons with zero velocity, which are, as you say, effectively noteoffs, even though in type they are noteons. So yes, I believe what are proposing should work.
Architect, the modular MIDI toolkit, beta now available for macOS, Windows, and Linux.

Post

By the way, if you are struggling to get something working, if you send me a minimal complete example of the problem (as xml patch, ideally), I can likely help diagnose the issue.
Architect, the modular MIDI toolkit, beta now available for macOS, Windows, and Linux.

Post

Thanks for the offer. I think I have my troubles licked at this point though. I had successfully created my patch in Max first; and really it’s the translation, between top-to-bottom and Max’s lack of a separate “call” inlet for many objects, that’s been at the root of my difficulties.
Tranzistow Tutorials: http://vze26m98.net/tranzistow/
Xenakis in America: http://oneblockavenue.net

Post

cturner wrote: Thu Dec 05, 2019 3:14 pm Thanks for the offer. I think I have my troubles licked at this point though. I had successfully created my patch in Max first; and really it’s the translation, between top-to-bottom and Max’s lack of a separate “call” inlet for many objects, that’s been at the root of my difficulties.
This is also probably the reason why I didn't go further with Architect. I'm not saying Max is perfect but I coulnd't get my head around with the order of events. I also thought the left to right approach was clearly a mistake but everyone else thought otherwise. As a stepsequencer it's awesome btw.

Post

Thanks for the feedback, bronswerk. I've got a few plans to make the flow of events clearer, so perhaps that'll help you (and others) out.
Architect, the modular MIDI toolkit, beta now available for macOS, Windows, and Linux.

Post

bronswerk wrote:
colin@loomer wrote:
I got my patch working about four hours after my last post. It seems to be working well.

I must point out I was attempting something I think is pretty difficult, which is the data merge of two MIDI streams, something beyond a simple polyphonic addition of notes. In the end I wrote my own versions of [logical and] and [data thinner], I guess motivated by Max idioms I’m already conversant with. The Architect version, which runs as a plug in Reaper, is way more flexible and easy-to-use for me than whatever I could build in Max.

I’ll post the patch in the sharing thread after a few days of use, and some time to do a decent write up.
Tranzistow Tutorials: http://vze26m98.net/tranzistow/
Xenakis in America: http://oneblockavenue.net

Post

cturner wrote: Thu Dec 05, 2019 10:25 pm I must point out I was attempting something I think is pretty difficult, which is the data merge of two MIDI streams, something beyond a simple polyphonic addition of notes.
Glad you've got it working. If you've any thoughts about how Architect could handle this case better, I'd love to hear them.
Architect, the modular MIDI toolkit, beta now available for macOS, Windows, and Linux.

Post

Update: There's a revision to this patch with source file download here: viewtopic.php?p=7600213#p7600213

Hi Colin-

I'll post the working patch in the sharing thread when I'm satisfied it's robust, and while I'll refrain from making suggestions, below please find a short narrative of my patch's (herein named MFELL) evolution.

Max/MSP "proof of concept"

I was interested in how one musical line could effect the note onsets and duration of another line, and put together a quick patch that would take two pulse trains derived from MIDI files, and merge the onsets and durations in various ways. For example, two audio files like this:

Image

Image

Would be combined using a patch like this:

Image

The audio pulse trains were derived from MIDI files and consist of 0 and 1 values corresponding to noteon/noteoff events. The two pulse trains are read into buffers k1 and k2, which are then played back through the k1 and k2 [wave~] objects. The [phasor~] is set to play back at "normal" speed, and the two number boxes going into the [phasor~] objects control their phase relationship. The two pulse trains are brought together via [bitand~] which creates merged onsets and durations according to the Boolean formula. There are of course, many other ways to merge the trains at this juncture in the patch. The resulting train is sent to [edge~] which signals transitions from 0->1 and 1->0 out its two outlets. These transitions trigger messages--noteon/noteoff pairs--that are then formatted and output as MIDI.

MIDI version in Max

Image

Pre-preparation of MIDI files was a certain annoyance, but also I believe I found a defect in Max's [bitor~] object, and so I moved to create a MIDI-only version of the above patch. The [seq] [midiparse] objects form the "players" for two MIDI files, supported by a UI button and attendant "read", "print" and "stop" messages. I take the leftmost outlet of [midiparse] to obtain the pitch/velocity pairs of the noteon/noteoffs.

[zl] is Max's list processor, and [zl 2 nth 2] splits the pitch/velocity pair into its components. It does so with evaluation order swapped, so there's a corresponding [zl.swap 0 1] as the last operation to "unswap" the order right before [midiformat].

I take the velocity data and convert from 0-127 to 0-1 via the "if then else" objects. This transformation then feeds two [&&] objects which form the Boolean truth table. I use two objects so that the AND is performed whenever either MIDI sequence generates a noteon or noteoff: one sequence stores, but is triggered by a change in the other, and vice versa.

The outcome of the Boolean operation goes into a [change] object, which encapsulates some powerful MIDI functionality. The leftmost outlet produces results equivalent to Architect's [data thinner] object, where successive duplicate values of a data stream are tossed away. Additionally, the next two outlets produce the results of 0->X and X->0 transitions, and produce no output otherwise. So I use [change] to reduce the data stream to the merged noteon/noteoff transitions, and split flow of control into those two streams. Given these streams now consist of 1s or nothing, it's a simple matter to [-1] to get 0 for noteoff velocity, and 1 [*] the original MIDI note velocity to reintroduce the velocity data from the first MIDI sequence. These are [pack]-ed back with the original MIDI pitch data. And [swap]-ed into correct order for format into MIDI.

First Architect version

Image

The Architect version of the MFELL patch is conceived as a "filter", a plugin that would work on a Reaper track, and take advantage of all of Reaper's routing and MIDI playback/editing features. I have it set up as a Reaper folder of two tracks, which simply automates the routing of two separate tracks of MIDI into a third, which hosts the Architect MFELL filter and the VSTi that interprets the resulting MIDI stream. One MIDI track is presumde to use MIDI Channel 1, and the other Channel 2.

There was a lot of thrashing about yesterday, and I started afresh quite a few times, so the above is merely the last in a series of "broken" attempts at translating the patch into Architect objects. Retrospectively I wasted a lot of time, having forgotten that [data thinner] was not the equivalent of Max's [change]. IIRC years ago, when I first started using Max/MSP they were equivalent, but I used the newer features here, and then promptly forgot I had!

MIDI input from the Host is evaluated for its channel assignment: the channel range of 1->2 is transformed into 0->1 by subtraction, and these form the truth values for [branch], which then splits the MIDI stream into its channel components.

Retrospectively, I don't know why I preferred [MIDI to tuple] to [unpack MIDI]. The addition of the "noteon/noteoff" tags and the "true/false" uncoupling data seemed (probably falsely) to be extraneous to my project. In the end, [MIDI to tuple] did provide a simple debug string that I could print out rather than corralling all the unpacked data--but again--this is a trivial matter.

EDIT: I didn't correctly recall my thinking in the above choice. There is no [unpack MIDI] in Architect AFAIK, but [unpack noteon] and [unpack noteoff]. Given I was going to process the velocity streams, it seemed an advantage to have the velocity data combined (although I should re-assess that). Plus the choice of [MIDI to tuple] took the object count down by two.

The AND logic has superficial differences from Max: the "if then else" construct becomes [!=] 0. The separate "call" inlet on [AND] enables the use of one object, but then there's the issue (in this case) of having to preload (false) data into the object to keep flow of control happy. The results go into a [data thinner], and as above, constitutes my chief barrier to success. [data thinner] was creating a stream of filtered noteon/notoff transitions, but it wasn't splitting execution control into two streams. [branch] is supposed to do this routing, but it can't distinguish between 0->1 and 1->0, which is the crux of the matter.

The original pitch and velocity data is fed into [pack noteon] along with a setting for MIDI Channel 3 and Architect "note uncoupling".

Latest Architect version

Image

So this one finally is successful. After I stupidly recalled that [data thinner] isn't the equivalent of Max [change], I wrote my own variant.

One small change is the move to [modulo] 2 to split the MIDI Channel streams. This flips the execution order so that visually, Channel 1 is on the left, Channel 2 is on the right of the screen.

Looking at the objects in the dark yellow box, I use [order] to give control over order of execution (although I feel this is a cop-out: it should be able to be written using Architect's natural order T->B, L->R). The [latch] is read before it's updated, so it retains the previous value of the stream. A read of [latch] loads the [!=] comparison of current against previous value. If [!=] is true, the current value from [order] flows through the [branch], otherwise it's discarded. The resulting stream is then of velocity values 0-127 representing the transition to noteon or noteoff.

I realized that [pack noteon] also work as [pack noteoff]. After all, MIDI noteoff is just a noteon with a 0 velocity value. So I eliminated the [pack noteoff] object as something that unnecessarily complicated my task.

As I was now producing a logical data stream of integers 0-127 instead of trues and falses for note control, I was moved to write my own AND logic that would eliminate a data conversion process. In the "AND Logic" blue box, I use [clamp] to scale the 0-127 velocity stream to 0-1. Multiplying 0s and 1s together gives the Boolean AND truth table. The result of "AND Logic" and "Change" is then multiplied together to create the merged velocity, which is combined with the rest of the MIDI stream, and sent to the VSTi.

So that's it! Thanks again for Architect!

All the best, Charles
Last edited by cturner on Sun Dec 08, 2019 2:08 pm, edited 2 times in total.
Tranzistow Tutorials: http://vze26m98.net/tranzistow/
Xenakis in America: http://oneblockavenue.net

Post

thanks, this will be quite useful to me - once I understand what it does :) Is it the intersection of note on/off for two midi streams?

Post Reply

Return to “Loomer”