Interval based melody transposer in midihub (like m4l Reboard/In theory keyboard)

hello,
I’m curious if it’s possible to create a patch with midihub that functions like a (simplified) Reboard: ReBoard - interval based Midi Player – Soundmanufacture
or InTheory keyboard: In Theory - Interval Based MIDI Keyboard

The central idea is that you define a default/central note, say C1 – playing notes above C1 transpose the outgoing note by the interval between the played note to C1.
As an example case:

(I play → midihub computation → output )

C1 → 0 transposition → C1 output
D1 → previous output of C1 is transposed +2 → D1 output
D1 (again) → previous output of D1 is transposed +2 → E1 output
G0 → previous output of E1 is transposed -5 → B0 output

Is there a way for midihub to hold in memory the last played note? (in a way that could potentially be reset?).
Thanks for any tips/insights you all may have

Hi @zippo4545 (welcome to Midihub forum, btw)

A few questions on your idea:

  • What happens when the patch starts and has yet to be given a note to “remember”?
    Is it OK to have C0 stored in the patch as “previous note” so that it has a starting point?

  • ‘melody’ = monophonically, ie note A ends before the patch is asked to “remember” a new note B?
    (asking because note_offs need to be considered)

  • Do you want to preserve velocity?
    Or are you happy for Midihub to set velocity (and then maybe randomise)?

  • can we assume all notes are on a fixed channel?


tips/insights

I can’t say definitively whether this is possible without sitting down and actually trying to write the patch…
… I think it is but I have a nagging suspicion that those note_offs are a stumbling block.



I’m not sure whether you’ve got a lot of experience creating Midihub patches…

…are just getting started…

…or are considering buying a Midihub and are asking in principle – I wrote some more notes then put them aside for later cos I didn’t know at what level to pitch the explanation.
(definitely needs a physical-loopback with several passes – of this sort of intricacy)



Nice problem, btw!

Yes, possible:

Screen Shot 2023-06-11 at 10.52.43

What you see in screenshot is

  • Monitor of VirtualA–IN being used to check input vs ‘melody transposed’:

  • The input notes (at USBA–IN) get CH REMAP to Ch16

  • The ‘melody transposed’ notes (created in the loopback out of shot) stay on Ch1…
    …enabling you to compare input and output


I don’t want to spell out the strategy unless you ask me to…
…but the sketch approach is to

  • use the incoming note_on to set up transpose & velocity maps and ‘trigger’ ccs then send them into the loop

  • then, in the loop, use Transforms to re-create the note_on&off (using the ‘trigger’ ccs) based on the stored Note Number…
    …and then transpose it

  • finally, use that note_off to create a mapping back to the note-creating Transforms
    thus setting the Note Number for the next note

my sketch is based on monophonic channel1 notes. (It would be possible to set it up for multiple channels by setting Note Number mappings for each channel)

thanks for the replies!

to answer your earlier Qs

  • What happens when the patch starts and has yet to be given a note to “remember”?
    Is it OK to have C0 stored in the patch as “previous note” so that it has a starting point?
    ya, I’d be ok w/ some arbitrary staring point at least in the proof of concept patch

  • ‘melody’ = monophonically, ie note A ends before the patch is asked to “remember” a new note B? (asking because note_offs need to be considered)
    right, I’m thinking of a monophonic patch for now and ideally the length of the output notes (note on to note off) would equal the duration of the held down key (not all legato).

  • Do you want to preserve velocity?
    Or are you happy for Midihub to set velocity (and then maybe randomise)?
    I’d be ok with either way as a starting point

  • can we assume all notes are on a fixed channel?
    yep yep

  • I’m not sure whether you’ve got a lot of experience creating Midihub patches…
    I’ve experimented with most modifier blocks at this point, but generally to accomplish simple end goals like filtering, channel/note remapping, arp, harmonizing, etc – definitely inexperienced with more complex patches (only now learning of the utility of a physical loopback & the transform modifier for ex)

I’m going to do some experimenting based on your recent notes and see if I can piece it together.
Thanks for the help!

1 Like

Excellent.

From what you’ve said, you can achieve what you want and then some!:+1:t4:

(Message sent)

1 Like

thanks for the tips! –
I think I understood the high-level workflow you were describing (let me know if this looks right/wrong):

  1. the input note’s on& off is converted to two CCs where the cc value corresponds to the previously played note’s value
  2. these on/off CCs are converted back into note on/off messages
  3. those notes get transposed, and the amount of transposition is based on the input note number
  4. the now transposed note now needs to be mapped to step 1’s transform blocks’ “value” parameter so the next played note is turned into a CC with an amount corresponding to the previously played note (which is transposed downstream)

I was in the middle of writing a reply about how the patch I was working on was broken and I didn’t know why, but I just found a mistake I made and now it seems to be working!
It does miss sending a note off event every now and then however and I’m sure there are other improvements to be made.

I’ve attached my patch – There are probably some completely arbitrary decisions in there that may not make sense or can be streamlined/simplified – but the general signal flow is:

pipe1) primary keyboard input from midiD ch remapped to 16, sent out to physical loopback midi B
pipe2) midi B loopback

  • transpose for ease of data processing below (this transpose is undone before the final output)
  • input ch filtered to 16
  • transform note on to CC15 with its value set to the input note’s note number
  • transform note on to CC 14 on channel 10 with its value set to Arg2, (which is mapped to be the previous played note’s value)
  • transform note off to CC 16 on channel 10 with its value set to arg2, (which is also mapped to be the previous played note’s value)
  • filtered to only pass through CCs on channel 10, output to physical loopback midi B
    pipe3) midi B looback
  • filter to midi ch 10 CC messages
  • transform CC 14 into note ON on channel 11
  • transform CC 16 in to note OFF on channel 11
    - I ch remapped 10+11 data to ch 11 here (I did this in the moment bc I wanted to map a ch 11 CC signal to the transpose amount – but in hindsight I could have mapped the transpose amount to the CH 10 CC15 signal in the B loopback path /shrug)
    - output to physical B loopback
    pipe4) midi B loopback
  • filter to ch 11 data (the reconstructed notes)
  • transpose, with the amount mapped to ch 11 CC 15 (the input note’s note number)
  • output to virt A
    pipe5) virtual A
  • filter to ch 11 note on/off
  • transform note off (insert before) to CC 17 with value of note number
  • transform note off (replace) to CC 14 with value of note number (these are the CCs that map to the noteON/OFF->CC transform blocks in pipe2 ‘value’ parameters (CC 14 & 16) – For pipe 5, I created two CC messages here because I had trouble getting both transform blocks in pipe2 to map to the same CC message created here – but maybe it’s possible and creating two new CCs here is overkill)
  • ch remap all created CCs to ch 12, output to physical B loopback
    pipe 6) virtual A
  • filter to note ON/OFF on ch 11
  • remap to ch 1
  • correctively transpose back into the desired note range and output via USB-A

some issues w my patch:

  • sometimes a note will stick (note off message is dropped somewhere)
  • I haven’t accounted for input note velocity on the output notes - seems relatively doable to accomplish though
  • ability to reset the stored note sounds cool/useful

I’d definitely be interested in seeing your patch to see how you’ve gone about it too. Also, I’m totally comfortable w/ you posting your patch to patchstorage!
wip-interval-transposer.mhp (800 Bytes)

2 Likes

looks like a lot of thinking going on there!

Haven’t got time right now to give your notes and patch the attention they deserve.
Will give it a proper look tomorrow.

In the meantime, here are my sketches:
zippo4545_MelodyTransposer.mhp (2.3 KB)
zippo4545_MelodyTransposerReset.mhp (2.5 KB)
Each have some explanatory description.
They both use MIDI-D as the loopback: probably best to just swap your cables to test them to avoid remapping!

Talk to you in 12hrs or so.

1 Like

hey, @zippo4545,
I taken a bit of time analysing your patch this a.m but haven’t yet hooked it up to see it play.

You’ve done a very good job of using various filters and channel remap to ensure you avoid endless feedback. As a result you’ve seen the amount of pipe clutter that can build up to keep loopbacks safe.

Your approach is similar to mine in some ways. Because of the issues above , once I reframed the original design as “the incoming note mainly defines the Transpose that is made to the ‘stored’ note_on/off (and just needs to pass on velocity and when on/off”, I was able to only send CCs into the loop for the first pass.
Because your patch sends the notes in, they then get changed into CCs in the loop, which adds an extra pass with all the attendant “feedback hygiene”(!)

There’s a little redundancy in that the two Transforms in line 5: Note Off → CC17/14 could be just one: in addition to
“a property can have have more than one mapping”
there is
“a mapping can go to more than one property”

I haven’t accounted for input note velocity on the output notes - seems relatively doable

Yes. set up Transform to create velocity-mapping outside


I can’t see off-hand why you’re getting hanging notes, either.
The only way I can think that happens is if Transpose get changed in between. Can’t see that yet.

PS. I now realise my (line1) Transpose+28 differs cos we’re using different Note Value Displays.