Old 09-15-2019, 03:35 AM   #1
wwcdgm
Human being with feelings
 
Join Date: Oct 2018
Posts: 17
Default cakewalk function: Scale Velocity (lua - help)

Hello everyone, I am learning to write a script. Implement a feature of cakewalk: Scale Velocity.

See the picture


127 -> 1

The input Begin and end with Velocity, and the script will calculate the results at the beginning and end.

I have a problem and don't know how to get the total number of selected notes. So my calculations have problems and the scripts are not working properly.
Attached Images
File Type: png 127 2 1.png (11.1 KB, 628 views)
File Type: png 10 2 100.png (11.2 KB, 329 views)
File Type: png reaper vel.png (9.3 KB, 299 views)

Last edited by wwcdgm; 09-18-2019 at 10:56 AM.
wwcdgm is offline   Reply With Quote
Old 09-15-2019, 06:35 AM   #2
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

TO get total of selected notes,


Loop first in all notes and increment a variable +1 each time you have sel == true,


then you can do your second loop with this number.
X-Raym is offline   Reply With Quote
Old 09-15-2019, 01:38 PM   #3
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

Or you can use reaper.MIDI_EnumSelNotes( take, noteidx ) in a loop until it returns -1; might be faster for large numbers of notes.
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate
Lokasenna is offline   Reply With Quote
Old 09-16-2019, 12:04 PM   #4
wwcdgm
Human being with feelings
 
Join Date: Oct 2018
Posts: 17
Default

Quote:
Originally Posted by X-Raym View Post
TO get total of selected notes,


Loop first in all notes and increment a variable +1 each time you have sel == true,


then you can do your second loop with this number.
Thank you, X-Raym. I used your method to get the total number of notes selected. I can finally continue to write the next step.

Now, the script can be quite satisfactory. However, I have encountered new problems. It works fine with a single melody, but if there are many notes in the same position (such as chords), the calculations will exceed expectations. Obviously an error occurred and some notes were eliminated because of errors.

The reason is that notes at the same time are constantly matched to new values, and many values exceed 127 (I think there are some problems with my calculation formula? -_-!!). In addition, notes of the same time should only use one value, and now it seems that each note has a superimposed assignment.

So, what should you do if the notes at the same time can only match one value?

Please see my code

Code:
function Msg(param)
	reaper.ShowConsoleMsg(tostring(param) .. "\n")
end

function Warn(msg)
    reaper.ShowMessageBox(tostring(msg), "warning", 0)
end

reaper.ShowConsoleMsg("")

local take=reaper.MIDIEditor_GetTake(reaper.MIDIEditor_GetActive())
retval, notes, ccs, sysex = reaper.MIDI_CountEvts(take)

userOK, userInputsCSV = reaper.GetUserInputs("Scale Velocity", 
                                                 2, 
                                                 "Begin,End", 
                                                 "10,100")
if not userOK then return reaper.SN_FocusMIDIEditor() end

vel_begin, vel_end = userInputsCSV:match("(.*),(.*)")
vel_begin, vel_end = tonumber(vel_begin),tonumber(vel_end)
if vel_begin > 127 or vel_end > 127 or vel_begin < 1 or vel_end < 1 then return end

noteidx = 0
note_count = 0

for noteidx=0, notes-1 do
  retval, sel, muted, startppq, endppq, chan, pitch, vel = reaper.MIDI_GetNote(take, noteidx)
  if sel == true then
    note_count = note_count + 1
  end
  noteidx=noteidx+1
end
Msg("Note count = "..note_count) -- Get the total number of selected notes

local k = note_count-1
local j = math.abs(math.floor( (vel_begin-vel_end)/k) )
Msg("print K  = "..k)
Msg("Value added each time = "..j)

if vel_begin > vel_end then
  for i = 0,  notes-1 do
	retval, sel, muted, ppq_start, ppq_end, chan, pitch, vel = reaper.MIDI_GetNote( take, i )
	  if sel == true then
        vel_begin = vel_begin-j
        reaper.MIDI_SetNote( take, i, sel, muted, ppq_start, ppq_end, chan, pitch, vel_begin+j, true )
        Msg(vel_begin+j) -- Increase from the input begin value
	  end
  end
else
  for i = 0,  notes-1 do
    retval, sel, muted, ppq_start, ppq_end, chan, pitch, vel = reaper.MIDI_GetNote( take, i )
      if sel == true then
    	vel_begin = vel_begin+j
    	reaper.MIDI_SetNote( take, i, sel, muted, ppq_start, ppq_end, chan, pitch, vel_begin-j, true )
    	Msg(vel_begin-j) -- Increase from the input begin value
      end
    end
end

reaper.UpdateArrange()
reaper.SN_FocusMIDIEditor()

Last edited by wwcdgm; 09-18-2019 at 10:55 AM.
wwcdgm is offline   Reply With Quote
Old 09-16-2019, 12:19 PM   #5
wwcdgm
Human being with feelings
 
Join Date: Oct 2018
Posts: 17
Default

Quote:
Originally Posted by Lokasenna View Post
Or you can use reaper.MIDI_EnumSelNotes( take, noteidx ) in a loop until it returns -1; might be faster for large numbers of notes.
Thank you very much Lokasenna. I used your method to successfully loop notes, but I haven't figured out how to get the total number of all selected notes, only the continuous value of 012345.... It seems that MIDI_EnumSelNotes is faster, is it convenient to provide a solution?
wwcdgm is offline   Reply With Quote
Old 09-16-2019, 12:47 PM   #6
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

EnumSelNotes will give you the index (within all of the notes) of the next selected note after whatever index you pass in. After the last selected note, the next index it returns will be -1 - if you have a counter going, at that point you should have the total number of selected notes.
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate
Lokasenna is offline   Reply With Quote
Old 09-16-2019, 03:19 PM   #7
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by wwcdgm View Post
Hello everyone, I am learning to write a script. Implement a feature of cakewalk: Scale Velocity.
Cool, I'm just trying to get back into MIDI and wanting to do the same thing, So using whats posted I came up with this so far,...

Code:
local take=reaper.MIDIEditor_GetTake(reaper.MIDIEditor_GetActive())
if take == nil then return end

local cnt, index = 0, {}
local val = reaper.MIDI_EnumSelNotes(take, -1)
while val ~= - 1 do
  cnt = cnt + 1
  index[cnt] = val
  val = reaper.MIDI_EnumSelNotes(take, val)
end

if #index > 0 then
  local retval, userInputsCSV = reaper.GetUserInputs("Scale Velocity", 2, "Begin,End", "17,127") 
  if not retval then return end
  local vel_first, vel_end = userInputsCSV:match("(.*),(.*)")
  local offset = (vel_end - vel_first) / cnt -- Lua provides automatic conversion between string and number values at run time. 
  for i = 1, #index do 
    local retval, sel, muted, ppq_start, ppq_end, chan, pitch, _ = reaper.MIDI_GetNote(take, index[i])  
    reaper.MIDI_SetNote(take, index[i], sel, muted, ppq_start, ppq_end, chan, pitch, math.floor(vel_first), true)
    vel_first = vel_first + offset
  end
  reaper.UpdateArrange()
else
  reaper.MB("No notes selected","ERROR",0)  
end

reaper.SN_FocusMIDIEditor()
reaper.defer(function () end)

Better, Worse?

Last edited by Edgemeal; 09-17-2019 at 09:31 AM.
Edgemeal is offline   Reply With Quote
Old 09-17-2019, 02:26 PM   #8
wwcdgm
Human being with feelings
 
Join Date: Oct 2018
Posts: 17
Default

Quote:
Originally Posted by Edgemeal View Post
Cool, I'm just trying to get back into MIDI and wanting to do the same thing, So using whats posted I came up with this so far,...

Code:
local take=reaper.MIDIEditor_GetTake(reaper.MIDIEditor_GetActive())
if take == nil then return end

local cnt, index = 0, {}
local val = reaper.MIDI_EnumSelNotes(take, -1)
while val ~= - 1 do
  cnt = cnt + 1
  index[cnt] = val
  val = reaper.MIDI_EnumSelNotes(take, val)
end

if #index > 0 then
  local retval, userInputsCSV = reaper.GetUserInputs("Scale Velocity", 2, "Begin,End", "17,127") 
  if not retval then return end
  local vel_first, vel_end = userInputsCSV:match("(.*),(.*)")
  local offset = (vel_end - vel_first) / cnt -- Lua provides automatic conversion between string and number values at run time. 
  for i = 1, #index do 
    local retval, sel, muted, ppq_start, ppq_end, chan, pitch, _ = reaper.MIDI_GetNote(take, index[i])  
    reaper.MIDI_SetNote(take, index[i], sel, muted, ppq_start, ppq_end, chan, pitch, math.floor(vel_first), true)
    vel_first = vel_first + offset
  end
  reaper.UpdateArrange()
else
  reaper.MB("No notes selected","ERROR",0)  
end

reaper.SN_FocusMIDIEditor()
reaper.defer(function () end)

Better, Worse?
Wow, that's great.You have finished it.thank you very much.

There is no problem with the code running, I really admire you.
wwcdgm is offline   Reply With Quote
Old 09-17-2019, 02:54 PM   #9
wwcdgm
Human being with feelings
 
Join Date: Oct 2018
Posts: 17
Default

Quote:
Originally Posted by Lokasenna View Post
EnumSelNotes will give you the index (within all of the notes) of the next selected note after whatever index you pass in. After the last selected note, the next index it returns will be -1 - if you have a counter going, at that point you should have the total number of selected notes.
Ok,thank you.Your help was greatly appreciated.

Last edited by wwcdgm; 09-17-2019 at 03:00 PM.
wwcdgm is offline   Reply With Quote
Old 09-17-2019, 03:05 PM   #10
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Ya thanks!
Edgemeal is offline   Reply With Quote
Old 09-22-2019, 11:29 AM   #11
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by wwcdgm View Post
Wow, that's great.You have finished it.thank you very much.

There is no problem with the code running, I really admire you.
FWIW, I tweaked it so the first and last selected note values are used for the input defaults, it makes fine tuning a little quicker for me.

Code:
local take=reaper.MIDIEditor_GetTake(reaper.MIDIEditor_GetActive())
if take == nil then return end

local cnt, index = 0, {}
local val = reaper.MIDI_EnumSelNotes(take, -1)
while val ~= - 1 do
  cnt = cnt + 1
  index[cnt] = val
  val = reaper.MIDI_EnumSelNotes(take, val)
end

if #index > 1 then
  local _, _, _, _, _, _, _, begin_vel = reaper.MIDI_GetNote(take, index[1])
  local _, _, _, _, _, _, _, end_vel = reaper.MIDI_GetNote(take, index[#index])
  local cur_range = tostring(begin_vel)..','..tostring(end_vel)
  local retval, userInputsCSV = reaper.GetUserInputs("Scale Velocity", 2, "Begin,End", cur_range)
  if not retval then return end
  local vel_first, vel_end = userInputsCSV:match("(.*),(.*)")
  local offset = (vel_end - vel_first) / cnt --  Lua provides automatic conversion between string and number values at run time.
  for i = 1, #index do
    local retval, sel, muted, ppq_start, ppq_end, chan, pitch, _ = reaper.MIDI_GetNote(take, index[i])
    reaper.MIDI_SetNote(take, index[i], sel, muted, ppq_start, ppq_end, chan, pitch, math.floor(vel_first), true)
    vel_first = vel_first + offset
  end
  reaper.UpdateArrange()
else
  reaper.MB("Please select two or more notes","Scale Velocity", 0)
end

reaper.SN_FocusMIDIEditor()
reaper.defer(function () end)

Last edited by Edgemeal; 10-02-2019 at 06:53 PM. Reason: FIX: Bug in reaper.MB call, was missing title text
Edgemeal 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 05:14 AM.


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