Old 11-29-2021, 01:33 PM   #1
xappn
Human being with feelings
 
Join Date: Feb 2021
Posts: 23
Default Quantize midi chord but keep relation

When I want to quantize a midi chord without destroying the relation between notes, I need to select the notes of the chord and then drag the note according to which I want the chord be quantized. 100% of time for me it will be the earliest note.



Is there an action or a script which could do this for me without the need of me figuring out which of the notes is the earliest and drag it?

Thank you
xappn is offline   Reply With Quote
Old 11-29-2021, 03:52 PM   #2
DrFrankencopter
Human being with feelings
 
Join Date: Jan 2011
Location: Ottawa, Canada
Posts: 293
Default

Just select the notes and hit Q?

Set your quantize options up to determine if you want to quantize the note duration as well as the start...and set your grid up based on where you want to quantize to (e.g. quarter notes, 8th notes, etc).
__________________
RME TotalMixFX Actions for Reaper here: https://stash.reaper.fm/v/29339/reape...MixOSC_x64.dll
DrFrankencopter is offline   Reply With Quote
Old 11-29-2021, 06:44 PM   #3
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 4,031
Default

Quote:
Originally Posted by xappn View Post
When I want to quantize a midi chord without destroying the relation between notes, I need to select the notes of the chord and then drag the note according to which I want the chord be quantized. 100% of time for me it will be the earliest note.



Is there an action or a script which could do this for me without the need of me figuring out which of the notes is the earliest and drag it?

Thank you
Interesting question, never tried. Experts will tell hopefully.
TonE is offline   Reply With Quote
Old 11-30-2021, 03:10 AM   #4
xpander
Human being with feelings
 
xpander's Avatar
 
Join Date: Jun 2007
Location: Terra incognita
Posts: 7,670
Default

Quote:
Originally Posted by xappn View Post
Is there an action or a script which could do this for me without the need of me figuring out which of the notes is the earliest and drag it?
Select all the notes of the chord and drag from any of them. The earliest one will naturally snap first to the grid, so just stop there.
xpander is offline   Reply With Quote
Old 11-30-2021, 06:20 AM   #5
DrFrankencopter
Human being with feelings
 
Join Date: Jan 2011
Location: Ottawa, Canada
Posts: 293
Default I think I "get" the question now...

I think what you're asking for is a script that:
1. Looks at all the selected note start times
2. Quantizes the earliest note (lowest start time) to the nearest grid line
3. Calculates the amount of time shift in step 2 (DeltaTime)
4. Applies the same DeltaTime to the remaining notes that have been selected

The end result would be equivalent to selecting the chord group and sliding it such that the earliest note starts on the bar line

Should be pretty straightforward to script...
__________________
RME TotalMixFX Actions for Reaper here: https://stash.reaper.fm/v/29339/reape...MixOSC_x64.dll
DrFrankencopter is offline   Reply With Quote
Old 11-30-2021, 03:47 PM   #6
xappn
Human being with feelings
 
Join Date: Feb 2021
Posts: 23
Default

Thanks all for the comments so far.

Quote:
Originally Posted by xpander View Post
Select all the notes of the chord and drag from any of them. The earliest one will naturally snap first to the grid, so just stop there.
This is what I've been doing so far, but I'd like to do this by a shortcut rather than manually dragging.

For me it seems to behave so that the note I choose to drag snaps to the grid with the relation between notes being preserved. So in this case it does matter which of the selected notes I drag.

Quote:
Originally Posted by DrFrankencopter View Post
I think what you're asking for is a script that:
1. Looks at all the selected note start times
2. Quantizes the earliest note (lowest start time) to the nearest grid line
3. Calculates the amount of time shift in step 2 (DeltaTime)
4. Applies the same DeltaTime to the remaining notes that have been selected

The end result would be equivalent to selecting the chord group and sliding it such that the earliest note starts on the bar line

Should be pretty straightforward to script...
I believe this would work! Is there any chance you or someone could give it a go? Myself I'm lost with the coding stuff.

Thanks
xappn is offline   Reply With Quote
Old 11-30-2021, 05:36 PM   #7
DrFrankencopter
Human being with feelings
 
Join Date: Jan 2011
Location: Ottawa, Canada
Posts: 293
Default

I gave it a shot, and coded something up. Try the attached script...

I'm sure it can fail if you've already manipulated the Midi timing and the order of the notes gets messed up. I didn't really do any error checking. But I think it works...

Feel free to look at the script, there's plenty of comments.

PS: Unfortunately, I can't figure out how to get the "undo" function to work...but if you undo selected notes your notes will go back where they were.
Attached Files
File Type: lua SoftQuantizeSelected.lua (3.0 KB, 112 views)
__________________
RME TotalMixFX Actions for Reaper here: https://stash.reaper.fm/v/29339/reape...MixOSC_x64.dll

Last edited by DrFrankencopter; 11-30-2021 at 05:44 PM. Reason: Added the PS
DrFrankencopter is offline   Reply With Quote
Old 12-01-2021, 03:38 AM   #8
xpander
Human being with feelings
 
xpander's Avatar
 
Join Date: Jun 2007
Location: Terra incognita
Posts: 7,670
Default

Quote:
Originally Posted by xappn View Post
For me it seems to behave so that the note I choose to drag snaps to the grid with the relation between notes being preserved. So in this case it does matter which of the selected notes I drag.
Darn, facepalm. I didn't realize I also got note ends snapping here, and they just happened to match grid when I was watching the start of the notes to snap when dragging. Sorry about that.
xpander is offline   Reply With Quote
Old 12-02-2021, 02:17 AM   #9
xappn
Human being with feelings
 
Join Date: Feb 2021
Posts: 23
Default

Quote:
Originally Posted by DrFrankencopter View Post
I gave it a shot, and coded something up. Try the attached script...

I'm sure it can fail if you've already manipulated the Midi timing and the order of the notes gets messed up. I didn't really do any error checking. But I think it works...

Feel free to look at the script, there's plenty of comments.

PS: Unfortunately, I can't figure out how to get the "undo" function to work...but if you undo selected notes your notes will go back where they were.
Hey that's so sweet of you! It works! I also appreciate the comments in the script.


Can the script be adjusted so that it only allows notes to move right, like you can set in the regular midi quantize settings?

I usually only want to quantize chords that are a little early, a little late doesnt seem to bother me. So when I'm moving fast and quantizing stuff, I would want the little late stuff to remain untouched.

Yes the undo mechanism seems to behave a little odd but it gets the job done.

Thanks a lot!

Quote:
Originally Posted by xpander View Post
Darn, facepalm. I didn't realize I also got note ends snapping here, and they just happened to match grid when I was watching the start of the notes to snap when dragging. Sorry about that.
Dont worry about it!
xappn is offline   Reply With Quote
Old 12-09-2021, 09:13 AM   #10
xappn
Human being with feelings
 
Join Date: Feb 2021
Posts: 23
Default

Quote:
Originally Posted by DrFrankencopter View Post
I gave it a shot, and coded something up. Try the attached script...
Quote:
Originally Posted by xappn View Post
Can the script be adjusted so that it only allows notes to move right, like you can set in the regular midi quantize settings?
Anyone?

Code:
local reaper = reaper

function Main( take )
      
  retval, notes, ccs, sysex = reaper.MIDI_CountEvts( take )
  
  firstSelPpq = -1 --Initilize this to something
  firstNoteNum = 0 -- init to zero
  
  for k=0, notes-1 do
    local retval, sel, muted, startppq, endppq, chan, pitch, vel = reaper.MIDI_GetNote( take, k )  -- read the note value
    if (sel) then
      if (firstSelPpq == -1) then
        --Assign firstSelPpq
        firstSelPpq = startppq
        firstNoteNum = k
      end
   end
  
  end --for loop
  
  haveValidRange = false
  
  if (firstSelPpq >  -1) then
    haveValidRange = true 
  else
    reaper.ShowMessageBox("No notes selected?", "Error", 0)
  end
  

  if (haveValidRange) then
 
    noteSlidePpq = 0 -- initialize for now
    
    -- Now let's re-loop through the notes and adjust
    for k = 0, notes - 1 do
      local retval, sel, muted, startppq, endppq, chan, pitch, vel = reaper.MIDI_GetNote( take, k )
      if (sel) then --If note is in our selected range
        if (k == firstNoteNum) then
          --Now we want to get the QN position of the note
          firstNoteQN = reaper.MIDI_GetProjQNFromPPQPos(take, startppq)
          --Ok great, now we need to get the grid spacing in QN
          myGridSpacing = reaper.MIDI_GetGrid(take) -- Hope the optional parameters aren't needed in Lua
          -- Now we want to round towards the nearest grid
          -- First we divide by the the QN val by the grid spacing
          firstNoteNumGrids = firstNoteQN/myGridSpacing
          --next we round it to the nearest integer..unfortunately this is a pain in Lua, so we add 0.5 and floor
          firstNoteNumGrids = math.floor(firstNoteNumGrids+0.5)  -- Now its an integer number
          -- Now we need to find the new ppq pos for the first note
          --So convert grids back to ppq
          firstNoteNewPpq = firstNoteNumGrids*myGridSpacing --Note it's still in Quarter notes here
          --and convert to ppq's
          firstNoteNewPpq = reaper.MIDI_GetPPQPosFromProjQN(take, firstNoteNewPpq) --The actual conversion to Ppq takes place here
          -- Now calcualte how much we are moving this note
          noteSlidePpq = firstNoteNewPpq - startppq  --Negative #'s mean we're sliding left, +ve means to the right
          
        end
        -- Now we actually do the note adjustment
        reaper.MIDI_SetNote(take,k,sel, muted, startppq + noteSlidePpq, endppq + noteSlidePpq, chan, pitch, vel, -1)
      end --if note start is in the selected range
    end --for loop thru notes
  end
  
  

end --main function


take = reaper.MIDIEditor_GetTake( reaper.MIDIEditor_GetActive() )

if take then
  
  reaper.Undo_BeginBlock() -- Begining of the undo block. Leave it at the top of your main function.
  
  Main( take ) -- Execute your main function
  
  reaper.Undo_EndBlock("Soft quantize selected notes to grid", -1) -- End of the undo block. Leave it at the bottom of your main function.
  
  reaper.UpdateArrange() -- Update the arrangement (often needed)

end -- ENDIF Take is MIDI

Last edited by xappn; 12-09-2021 at 09:21 AM.
xappn is offline   Reply With Quote
Old 12-09-2021, 12:21 PM   #11
DrFrankencopter
Human being with feelings
 
Join Date: Jan 2011
Location: Ottawa, Canada
Posts: 293
Default

Quote:
Originally Posted by xappn View Post
Anyone?
Hey man, I missed this. Yeah it should be pretty easy to force it to round up.

I don't have time to try anything out right now myself, but maybe look at this line
Code:
  firstNoteNumGrids = math.floor(firstNoteNumGrids+0.5)  -- Now its an integer number
and replace it with this:
Code:
  firstNoteNumGrids = math.ceil(firstNoteNumGrids)  -- Ceil should round upwards
That should force a round up...but it could fail for notes that are super super close to the grid line (like within machine precision).

At any rate, it's worth a shot.
__________________
RME TotalMixFX Actions for Reaper here: https://stash.reaper.fm/v/29339/reape...MixOSC_x64.dll
DrFrankencopter is offline   Reply With Quote
Old 12-14-2021, 12:14 PM   #12
xappn
Human being with feelings
 
Join Date: Feb 2021
Posts: 23
Default

Quote:
Originally Posted by DrFrankencopter View Post
Hey man, I missed this. Yeah it should be pretty easy to force it to round up.

I don't have time to try anything out right now myself, but maybe look at this line
Code:
  firstNoteNumGrids = math.floor(firstNoteNumGrids+0.5)  -- Now its an integer number
and replace it with this:
Code:
  firstNoteNumGrids = math.ceil(firstNoteNumGrids)  -- Ceil should round upwards
That should force a round up...but it could fail for notes that are super super close to the grid line (like within machine precision).

At any rate, it's worth a shot.
It's quite wonderful isn't it...

I wouldn't want to bug you for too long, but after days of delight, two things arose to mind.


As it stands, when quantizing a midi note that is just a bit late on the grid, the script forces the note to the next grid line.

In this scenario, what I'd like to happen instead, is the note, for which the script has been (accidently) applied, would remain unmoved. Only when it's half way or more to the direction of the next grid line, it would quantize to the next grid line.


Other than that, the undo function seems to undo the last two operations instead of just the latest one. I wonder if it would be too much to try to change the behaviour?


I hope these make sense, my describing might not be the best, sometimes I lose even myself.


Thank you!

Last edited by xappn; 12-15-2021 at 01:03 PM.
xappn is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 01:41 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.