Old 06-16-2017, 03:46 PM   #1
Yorkz
Human being with feelings
 
Yorkz's Avatar
 
Join Date: Jan 2007
Location: Canada
Posts: 120
Default Copy/Paste Velocity Data

I can't find a way to copy velocity data (example, a pattern of velocities) and paste it later in the same midi editor track. Is this possible in Reaper?
Apologies if I missed something obvious.
Yorkz is offline   Reply With Quote
Old 06-16-2017, 04:16 PM   #2
grinder
Human being with feelings
 
grinder's Avatar
 
Join Date: Jan 2009
Location: New Zealand
Posts: 2,905
Default

Hi I have not done this for a while but when I did I think I did this

Highlight all the automation dots on the screen view you want / rt click on active file and select "copy" Afterwards click a point in the file where you wish the new automation to be then paste, you will find this at the top left hand side of the page under edit, PASTE .

Hope that makes sense .
Hope I have got it right.

Grinder
grinder is offline   Reply With Quote
Old 06-16-2017, 04:37 PM   #3
Yorkz
Human being with feelings
 
Yorkz's Avatar
 
Join Date: Jan 2007
Location: Canada
Posts: 120
Default

Thanks for the quick reply! Unfortunately, my copy/paste includes all data including notes. I'm looking specifically at copying note velocity from source to destination locations.
Yorkz is offline   Reply With Quote
Old 06-16-2017, 06:07 PM   #4
AugerJ
Human being with feelings
 
Join Date: Dec 2015
Posts: 476
Default

Hi.
Velocity isn't exactly automation, is it?

I can think of some kind of (groove? advanced?) quantization that lets you untick all the checkboxes except Velocity and use your pattern as the groove...

Ah,
SWS/FNG: Show groove tool
!
Strength
Position: 0%.
Velocity: 100%.

That's the idea.
AugerJ is offline   Reply With Quote
Old 06-16-2017, 10:30 PM   #5
Yorkz
Human being with feelings
 
Yorkz's Avatar
 
Join Date: Jan 2007
Location: Canada
Posts: 120
Default

Thanks for the workaround but I was hoping for something inside the midi editor. It looks like the functionality is available for cc data but not fpr velocity data. Too bad, I would use it a lot when building ostinato rhythms.
Yorkz is offline   Reply With Quote
Old 06-17-2017, 10:26 AM   #6
DarkStar
Human being with feelings
 
DarkStar's Avatar
 
Join Date: May 2006
Location: Surrey, UK
Posts: 19,677
Default

'Fraid not; there is no such thing as 'velocity data'.

Velocity is a property of each MIDI note (as are its note number and channel). So you cannot copy the velocities, you can only copy the notes.
__________________
DarkStar ... interesting, if true. . . . Inspired by ...
DarkStar is online now   Reply With Quote
Old 06-17-2017, 06:38 PM   #7
Yorkz
Human being with feelings
 
Yorkz's Avatar
 
Join Date: Jan 2007
Location: Canada
Posts: 120
Default

Presonus Studio One has this functionality with the Studio One X add-on.

http://studioonex.narechk.net/index_en.html
(see halfway down the page)

http://studioonex.narechk.net/content/CopyVelocity.gif

Must be tricky to implement.

Last edited by Yorkz; 06-17-2017 at 07:56 PM.
Yorkz is offline   Reply With Quote
Old 06-17-2017, 10:38 PM   #8
ivansc
Human being with feelings
 
Join Date: Aug 2007
Location: Near Cambridge UK and Near Questembert, France
Posts: 22,754
Default

OK I think the problem lies with how you described what you want. That script isnt copying the velocities really.
What it IS doing (which is rather cool) is applying the *note* velocities from the first section to the *notes* of the later sections. There is a subtle but crucial difference. What the script is really doing is modifying the later velocities to conform to what the earlier section has. In other words it is CHANGING velocities, not pasting them.
__________________
Ici on parles Franglais
ivansc is offline   Reply With Quote
Old 06-18-2017, 12:05 AM   #9
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Code:
  function CopySelectedNotesVelocities()
    local midieditor =  reaper.MIDIEditor_GetActive()
    if not midieditor then return end
    local take =  reaper.MIDIEditor_GetTake( midieditor )
    if not take or not reaper.TakeIsMIDI(take) then return end
    local _, notecnt = reaper.MIDI_CountEvts( take )    
    local t = {}
    local str = ""
    for i = 1, notecnt do
      _, selectedOut, _, _, _, _, _, vel = reaper.MIDI_GetNote( take, i-1 )
      if selectedOut == true then str = str..vel..',' end    
    end    
    reaper.SetExtState('mplCopyVel', 'buf', str, false)    
  end
CopySelectedNotesVelocities()
Code:
  function PasteVelocitiesToSelectedNotes()
    local midieditor =  reaper.MIDIEditor_GetActive()
    if not midieditor then return end
    local take =  reaper.MIDIEditor_GetTake( midieditor )
    if not take or not reaper.TakeIsMIDI(take) then return end
    local _, notecnt = reaper.MIDI_CountEvts( take )    
    str = reaper.GetExtState('mplCopyVel', 'buf')
    t = {}
    for num in str:gmatch('[%d]+') do t[#t+1] = tonumber(num) end    
    for i = 1, notecnt do
      retval, sel, m, s, e, c, p, v = reaper.MIDI_GetNote( take, i-1 )
      if sel == true then reaper.MIDI_SetNote( take, i-1, true, m, s, e, c, p, t[i%#t], true ) end    
    end  
    reaper.MIDI_Sort(take)     
  end  
PasteVelocitiesToSelectedNotes()

Last edited by mpl; 06-18-2017 at 12:51 AM.
mpl is offline   Reply With Quote
Old 06-18-2017, 02:11 AM   #10
ivansc
Human being with feelings
 
Join Date: Aug 2007
Location: Near Cambridge UK and Near Questembert, France
Posts: 22,754
Default

Damn you scripters are smart!
I will probably never have a use for this, but it is still pretty cool that one can write something like this in Lua or similar and just insert it in Reaper.
Wish I had the right sort of brain to do this....
__________________
Ici on parles Franglais
ivansc is offline   Reply With Quote
Old 06-18-2017, 06:07 AM   #11
Pet
Human being with feelings
 
Pet's Avatar
 
Join Date: Nov 2015
Location: Germany
Posts: 1,015
Default

Quote:
Originally Posted by ivansc View Post
Damn you scripters are smart!
And mpl is the coolest one ever! No needless descriptions or anything. JUST A SOLUTION. Baaaamm, here you are!

I love it.
__________________
If the v5 Default Theme is too bright for you take a gander at my mod of it: Default v5 Dark Theme
Pet is offline   Reply With Quote
Old 06-18-2017, 07:51 AM   #12
ivansc
Human being with feelings
 
Join Date: Aug 2007
Location: Near Cambridge UK and Near Questembert, France
Posts: 22,754
Default

evidently Mixbus 4 (I didnt update from 3) now has lua scripting so it will be interesting to see what sort of stuff HEIR user come up with.
__________________
Ici on parles Franglais
ivansc is offline   Reply With Quote
Old 06-18-2017, 10:29 AM   #13
Yorkz
Human being with feelings
 
Yorkz's Avatar
 
Join Date: Jan 2007
Location: Canada
Posts: 120
Default

Wow, the Reaper community is amazing!
Thanks so much mpl! I'll give it a try and hopefully I can get it working.
Yorkz is offline   Reply With Quote
Old 07-06-2017, 12:10 PM   #14
Yorkz
Human being with feelings
 
Yorkz's Avatar
 
Join Date: Jan 2007
Location: Canada
Posts: 120
Default

Yup. Works brilliantly, even better than the Presonus example. Thanks mpl!
Yorkz is offline   Reply With Quote
Old 09-26-2017, 09:56 AM   #15
jojojopo
Human being with feelings
 
Join Date: Sep 2017
Posts: 2
Default

Hello everyone!

mpl, I tried to use your scripts in a project but they weren't working for me, and after some testing I found that it was because simultaneous notes are listed in the order they are created which does not provide consistency. Using the procedure showcased in your scripts I expanded them to be able to manage these cases.

I'll leave them here so that in the future they can be of use to anyone who needs this functionality.

Code:
function CopySelectedNotesVelocities()
  local script_name = "MIDI-velocity-copy"

  --Get current take
  local midieditor = reaper.MIDIEditor_GetActive()
  if not midieditor then 
    reaper.ShowConsoleMsg( script_name.." error: there is no active MIDI Editor.\n" )
    return
  end
  local take = reaper.MIDIEditor_GetTake( midieditor )
  if not take or not reaper.TakeIsMIDI(take) then 
    reaper.ShowConsoleMsg( script_name.." error: there is no selected MIDI take.\n" )
    return
  end
  local _, notecnt, _, _ = reaper.MIDI_CountEvts( take )

  --Set needed variables
  local current_note = {}   --Store the current note  
  local last_note = {}      --Remember the last selected note while iterating through all the notes
  local temp = {}           --Temporary table to remember all the notes that share position to sort them by pitch
  local str = ""            --String of concatenated velocities to export  
  
  local action_definitions = {  --Define the different actions the script has to perform while iterating through the take
    ["clean_temp"] = function(current_note, last_note, temp, str)
      local temp_size = #temp
      if temp_size > 0 then
        table.sort(temp, function (note1, note2) return note1.pitch < note2.pitch end)
        for _, note in ipairs(temp) do
          str = str..note.vel..','
        end
        temp = {}
      end
      return current_note, last_note, temp, str
    end,
    ["add_note_to_temp"] = function(current_note, last_note, temp, str)
      table.insert(temp, current_note)
      return current_note, last_note, temp, str
    end,
    ["update"] = function(current_note, last_note, temp, str)
      last_note = current_note
      return current_note, last_note, temp, str
    end
  }
  
  --Iterate through the take
  for i = 1, notecnt do
    local last_run = (i == notecnt and true or false)  --true if this is the last note in the take
    
    --Get current note data
    local _, current_selected, _, current_pos, _, _, current_pitch, current_vel = reaper.MIDI_GetNote( take, i-1 )
    local current_note = {
      selected = current_selected, 
      pos = current_pos, 
      pitch = tonumber(current_pitch), 
      vel = current_vel }
    
    --Create stack of actions to resolve and populate it with the right actions in the right order for the situation
    local actions = {}
    --If position has changed, current temp will have to be cleaned before current note is processed
    if current_note.pos ~= last_note.pos then table.insert(actions, "clean_temp") end
    --If current note is selected it will have to be added to temp
    if current_note.selected then table.insert(actions, "add_note_to_temp") end
    --If current note is the last note and it is selected, temp needs to be cleaned after it is processed
    if current_note.selected and last_run then table.insert(actions, "clean_temp") end
    --After everything else, update last_note
    table.insert(actions, "update")
    
    --Perform actions
    for _, to_do in ipairs(actions) do
      current_note, last_note, temp, str = action_definitions[to_do](current_note, last_note, temp, str)
    end
  end
  reaper.SetExtState( 'CopyVel', 'buf', str, false )
  reaper.ShowConsoleMsg( script_name .. " copied velocities: "..str )
end

CopySelectedNotesVelocities()
Code:
function PasteVelocitiesToSelectedNotes()
  local script_name = "MIDI-velocity-paste"
  
  --Get current take
  local midieditor =  reaper.MIDIEditor_GetActive()
  if not midieditor then 
    reaper.ShowConsoleMsg( script_name.." error: there is no active MIDI Editor.\n" )
    return
  end
  local take =  reaper.MIDIEditor_GetTake( midieditor )
  if not take or not reaper.TakeIsMIDI(take) then 
    reaper.ShowConsoleMsg( script_name.." error: there is no selected MIDI take.\n" )
    return
  end
  local _, notecnt = reaper.MIDI_CountEvts( take )
  
  --Get copied velocities
  if not reaper.HasExtState('CopyVel', 'buf') then      --Exit if there are none
    reaper.ShowConsoleMsg( script_name.." error: copy some velocities first.\n" )
    return
  end
  local str = reaper.GetExtState('CopyVel', 'buf')      --Load the string                        
  local velocities = {}                                 --Create a table to store them
  for velocity in str:gmatch('[%d]+') do 
    table.insert(velocities, tonumber(velocity))        --Add them to the table
  end
  
  --Iterate through the take and find the ids and all atributes of selected notes.
  local selected_notes = {}
  for i = 1, notecnt do
    local retval, sel, m, s, e, c, p, v = reaper.MIDI_GetNote( take, i-1 )
    if sel == true then
      local current_note = {
        id = i-1,
        muted = m,
        startpos = s,
        endpos = e,
        channel = c,
        pitch = p,
        velocity = v }
      table.insert( selected_notes, current_note )
    end
  end
  
  --Exit if number of velocities is different than the number of selected notes
  if #velocities ~= #selected_notes then
    reaper.ShowConsoleMsg( script_name.." error: can't paste " .. #velocities .. " velocity/ies into " .. #selected_notes .. " note/s. Number must be the same.\n" )
    return
  end
  
  --selected_notes are already sorted by position, now sort notes in the same position by pitch from low to high
  local sorting_function = function (note1, note2)
    local values_to_compare = {
      { note1.startpos, note2.startpos },
      { note1.pitch, note2.pitch }
    }

    for _, values in ipairs(values_to_compare) do
      if values[1] < values[2] then return true 
      elseif values[1] > values[2] then return false end
    end
    
    return false
  end
  table.sort( selected_notes, sorting_function )
  
  --Perform the changes
  for i, note in ipairs( selected_notes ) do
    reaper.MIDI_SetNote( take, note.id, true, note.muted, note.startpos, note.endpos, note.channel, note.pitch, velocities[i], true )
  end
  reaper.MIDI_Sort( take )
  
  reaper.ShowConsoleMsg( script_name.." successfully copied velocities into " .. #selected_notes .. " note/s.\n" )
end  

PasteVelocitiesToSelectedNotes()
jojojopo is offline   Reply With Quote
Old 11-01-2017, 11:50 AM   #16
_Stevie_
Human being with feelings
 
_Stevie_'s Avatar
 
Join Date: Oct 2017
Location: Black Forest
Posts: 5,054
Default

Thanks guys, this is an awesome script! I always wished for something like that in Cubase.
_Stevie_ is offline   Reply With Quote
Old 12-24-2017, 08:40 AM   #17
timbralzoom
Human being with feelings
 
timbralzoom's Avatar
 
Join Date: Apr 2010
Location: Turkey/Istanbul
Posts: 1,820
Default

Thank you mpl & jojojopo!

@jojojopo
nothing serious but
any change to have a version that doesn't run the Console after action executed?
timbralzoom is offline   Reply With Quote
Old 12-26-2017, 07:08 AM   #18
jojojopo
Human being with feelings
 
Join Date: Sep 2017
Posts: 2
Default

@timbralzoom
Sure, you are right that it can get annoying. I made it so that a message is showed only when there is some kind of error.

Code:
function CopySelectedNotesVelocities()
  local script_name = "MIDI-velocity-copy"

  --Get current take
  local midieditor = reaper.MIDIEditor_GetActive()
  if not midieditor then 
    reaper.ShowConsoleMsg( script_name.." error: there is no active MIDI Editor.\n" )
    return
  end
  local take = reaper.MIDIEditor_GetTake( midieditor )
  if not take or not reaper.TakeIsMIDI(take) then 
    reaper.ShowConsoleMsg( script_name.." error: there is no selected MIDI take.\n" )
    return
  end
  local _, notecnt, _, _ = reaper.MIDI_CountEvts( take )

  --Set needed variables
  local current_note = {}   --Store the current note  
  local last_note = {}      --Remember the last selected note while iterating through all the notes
  local temp = {}           --Temporary table to remember all the notes that share position to sort them by pitch
  local str = ""            --String of concatenated velocities to export  
  
  local action_definitions = {  --Define the different actions the script has to perform while iterating through the take
    ["clean_temp"] = function(current_note, last_note, temp, str)
      local temp_size = #temp
      if temp_size > 0 then
        table.sort(temp, function (note1, note2) return note1.pitch < note2.pitch end)
        for _, note in ipairs(temp) do
          str = str..note.vel..','
        end
        temp = {}
      end
      return current_note, last_note, temp, str
    end,
    ["add_note_to_temp"] = function(current_note, last_note, temp, str)
      table.insert(temp, current_note)
      return current_note, last_note, temp, str
    end,
    ["update"] = function(current_note, last_note, temp, str)
      last_note = current_note
      return current_note, last_note, temp, str
    end
  }
  
  --Iterate through the take
  for i = 1, notecnt do
    local last_run = (i == notecnt and true or false)  --true if this is the last note in the take
    
    --Get current note data
    local _, current_selected, _, current_pos, _, _, current_pitch, current_vel = reaper.MIDI_GetNote( take, i-1 )
    local current_note = {
      selected = current_selected, 
      pos = current_pos, 
      pitch = tonumber(current_pitch), 
      vel = current_vel }
    
    --Create stack of actions to resolve and populate it with the right actions in the right order for the situation
    local actions = {}
    --If position has changed, current temp will have to be cleaned before current note is processed
    if current_note.pos ~= last_note.pos then table.insert(actions, "clean_temp") end
    --If current note is selected it will have to be added to temp
    if current_note.selected then table.insert(actions, "add_note_to_temp") end
    --If current note is the last note and it is selected, temp needs to be cleaned after it is processed
    if current_note.selected and last_run then table.insert(actions, "clean_temp") end
    --After everything else, update last_note
    table.insert(actions, "update")
    
    --Perform actions
    for _, to_do in ipairs(actions) do
      current_note, last_note, temp, str = action_definitions[to_do](current_note, last_note, temp, str)
    end
  end
  reaper.SetExtState( 'CopyVel', 'buf', str, false )
  --reaper.ShowConsoleMsg( script_name .. " copied velocities: "..str )
end

CopySelectedNotesVelocities()
Code:
function PasteVelocitiesToSelectedNotes()
  local script_name = "MIDI-velocity-paste"
  
  --Get current take
  local midieditor =  reaper.MIDIEditor_GetActive()
  if not midieditor then 
    reaper.ShowConsoleMsg( script_name.." error: there is no active MIDI Editor.\n" )
    return
  end
  local take =  reaper.MIDIEditor_GetTake( midieditor )
  if not take or not reaper.TakeIsMIDI(take) then 
    reaper.ShowConsoleMsg( script_name.." error: there is no selected MIDI take.\n" )
    return
  end
  local _, notecnt = reaper.MIDI_CountEvts( take )
  
  --Get copied velocities
  if not reaper.HasExtState('CopyVel', 'buf') then      --Exit if there are none
    reaper.ShowConsoleMsg( script_name.." error: copy some velocities first.\n" )
    return
  end
  local str = reaper.GetExtState('CopyVel', 'buf')      --Load the string                        
  local velocities = {}                                 --Create a table to store them
  for velocity in str:gmatch('[%d]+') do 
    table.insert(velocities, tonumber(velocity))        --Add them to the table
  end
  
  --Iterate through the take and find the ids and all atributes of selected notes.
  local selected_notes = {}
  for i = 1, notecnt do
    local retval, sel, m, s, e, c, p, v = reaper.MIDI_GetNote( take, i-1 )
    if sel == true then
      local current_note = {
        id = i-1,
        muted = m,
        startpos = s,
        endpos = e,
        channel = c,
        pitch = p,
        velocity = v }
      table.insert( selected_notes, current_note )
    end
  end
  
  --Exit if number of velocities is different than the number of selected notes
  if #velocities ~= #selected_notes then
    reaper.ShowConsoleMsg( script_name.." error: can't paste " .. #velocities .. " velocity/ies into " .. #selected_notes .. " note/s. Number must be the same.\n" )
    return
  end
  
  --selected_notes are already sorted by position, now sort notes in the same position by pitch from low to high
  local sorting_function = function (note1, note2)
    local values_to_compare = {
      { note1.startpos, note2.startpos },
      { note1.pitch, note2.pitch }
    }

    for _, values in ipairs(values_to_compare) do
      if values[1] < values[2] then return true 
      elseif values[1] > values[2] then return false end
    end
    
    return false
  end
  table.sort( selected_notes, sorting_function )
  
  --Perform the changes
  for i, note in ipairs( selected_notes ) do
    reaper.MIDI_SetNote( take, note.id, true, note.muted, note.startpos, note.endpos, note.channel, note.pitch, velocities[i], true )
  end
  reaper.MIDI_Sort( take )
  
  --reaper.ShowConsoleMsg( script_name.." successfully copied velocities into " .. #selected_notes .. " note/s.\n" )
end  

PasteVelocitiesToSelectedNotes()
jojojopo is offline   Reply With Quote
Old 12-26-2017, 07:44 AM   #19
timbralzoom
Human being with feelings
 
timbralzoom's Avatar
 
Join Date: Apr 2010
Location: Turkey/Istanbul
Posts: 1,820
Default

Great! Thank you so much!
timbralzoom is offline   Reply With Quote
Old 09-21-2021, 02:47 AM   #20
richardj
Human being with feelings
 
Join Date: Nov 2012
Posts: 178
Default

This script is not working for me. I installed it via Extensions - Reapack - Browse - 'Copy selected notes velocities' and 'Paste selected notes velocities'

See the video - it's clearly pasting the velocities onto the selected notes too quickly. The notes are identical, except for being a semitone higher than the copied notes.

https://streamable.com/ypoion

How do I fix this please?
richardj is offline   Reply With Quote
Old 06-08-2022, 03:53 AM   #21
Hexode
Human being with feelings
 
Join Date: Apr 2020
Posts: 6
Default

Thanks for the script!
I'm a bit of a noob when it comes to scripts: would you be kind enough to explain how I can make it work in Reaper?
And how does it work while it's installed?

Thanks a bunch
Hexode is offline   Reply With Quote
Old 03-09-2024, 05:31 AM   #22
ownlife
Human being with feelings
 
Join Date: Aug 2021
Posts: 6
Default Scripting wizard to extend these scripts?!?!

This is my dream:
- Copy selected cc1 points in a MIDI editor lane
- Paste values from copied cc1's as velocities where note-on events are present at this "time"

I'm too inept to script this myself... May be a piece of cake for a reascript pro...

Thanx to anyone who can do it! ;-)
ownlife 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:46 PM.


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