|
|
|
06-18-2017, 01:59 PM
|
#1
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Reascript: new function MIDIEditor_Update for faster MIDI scripts
REAPER's API includes functions to either prevent the arrange view from updating while a script is running ( PreventUIRefresh), or to force the arrange view to update ( UpdateArrange and UpdateTimeline).
The MIDI editor does not currently enjoy similar functionality as UpdateArrange and UpdateTimeline:
By default, REAPER does not update the MIDI editor UI while scripts are running -- which is very good, since it makes execution of scripts much faster.
However, it would be useful in some cases to be able to force a MIDI editor to update its UI even before a script ends -- *without* updating the arrange view too. In particular, MIDI editing scripts (that track mouse movements and update the MIDI editor in realtime) currently have to use deferred loops instead of a plain while-loops, since the MIDI editor cannot be updated inside such while-loops.
I expect that while-loops would execute much faster than deferred loops, since while-loops can skip updating of the arrange view and all the other background stuff. (Note that REAPER's native MIDI editing mouse modifier actions do not update the arrange window while the action is running, either.)
I therefore propose a new API function:
Code:
Lua: reaper.MIDIEditor_Update(HWND midieditor)
Redraw the MIDI editor, without updating the arrange view and ruler
Last edited by juliansader; 06-18-2017 at 02:25 PM.
|
|
|
06-23-2017, 11:22 AM
|
#2
|
Human being with feelings
Join Date: May 2016
Posts: 369
|
as a little hack you could do
reaper.MIDIEditor_LastFocused_OnCommand(40501,0) --Invert Selection x2 ... little hack to activate the new notes ...
reaper.MIDIEditor_LastFocused_OnCommand(40501,0) --... reaper.MIDI_Sort(MidiTake) is messing up the notes
yes i just used that yesterday as reaper.MIDI_Sort(MidiTake) messes up overlapping notes
it also seems to update the arrange view and midiplayback (updates the midi editor)
every selection action does that .. i haven´t tried any more .. maybe theres an action with even less impact to trigger the update
|
|
|
06-23-2017, 01:21 PM
|
#3
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Thanks for the reply!
Unfortunately (if I am not mistaken?), the OnCommand actions are only visibly drawn in the MIDI editor once a script exits, or starts a new defer cycle. What I would like to achieve, is to force the MIDI editor to immediately redraw itself on the screen while a script is still running -- without having to exit the script, and without redrawing the arrange view (and without doing anything else that is time-consuming). Hopefully this will speed up deferred scripts.
|
|
|
12-15-2017, 08:58 PM
|
#5
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
I just stumbled across the same problem. I have a script that will add +12 semitones to a MIDI take. The script can be run in the arrangement. However, the item does not update itself and the added notes are not visible.
Adding invert selection only works, if the MIDI Editor is open.
Is there any other solution to update the take in the arrangement?
|
|
|
12-16-2017, 02:50 AM
|
#6
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Quote:
Originally Posted by _Stevie_
I just stumbled across the same problem. I have a script that will add +12 semitones to a MIDI take. The script can be run in the arrangement. However, the item does not update itself and the added notes are not visible.
Adding invert selection only works, if the MIDI Editor is open.
Is there any other solution to update the take in the arrangement?
|
Some API functions that change an item's appearance don't automatically trigger a redraw of the item. So if a script is run in the arrange view, it is often safer to include one of the "Update" functions at the end of the script to ensure that the graphics are updated:
UpdateItemInProject() updates only one item (probably the fastest option)
UpdateArrange() updates all items but not the ruler.
UpdateTimeLine() updates everything.
|
|
|
12-16-2017, 05:08 AM
|
#7
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
I already tried all 3 of these and it doesn't work :/
The only thing that seems to work is a selection of the notes in the midi editor, then a redraw happens.
|
|
|
12-16-2017, 05:39 AM
|
#8
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Could you post the script here?
|
|
|
12-16-2017, 05:41 AM
|
#9
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
Sure!
Code:
interval = 12 -- semitones
function add_notes(interval)
for i = 0, reaper.CountSelectedMediaItems(0)-1 do -- loop through all selected items
item = reaper.GetSelectedMediaItem(0, i)
for t = 0, reaper.CountTakes(item)-1 do -- Loop through all takes within each selected item
take = reaper.GetTake(item, t)
if reaper.TakeIsMIDI(take) then -- make sure, that take is MIDI
notes = reaper.MIDI_CountEvts(take) -- count notes and save amount to "notes"
for n = 0, notes - 1 do -- loop thru all notes
_, selectedOut, _, _, _, _, _, _ = reaper.MIDI_GetNote(take, n) -- get selection status
if selectedOut == true then -- if at least note is selected
notes_selected = true -- set notes_selected to true
break -- break the for loop, because at least one selected note was found
end
end
for n = 0, notes - 1 do -- loop thru all notes
_, selectedOut, _, startppqposOut, endppqposOut, chanOut, pitchOut, velOut = reaper.MIDI_GetNote(take, n) -- get selection status and pitch
if notes_selected == true then -- if there is a note selection
if selectedOut == true then -- filter out selected notes to add notes
reaper.MIDI_InsertNote(take, false, false, startppqposOut, endppqposOut, chanOut, pitchOut+interval, velOut, true) -- add notes by interval to selected notes
end
else
reaper.MIDI_InsertNote(take, false, false, startppqposOut, endppqposOut, chanOut, pitchOut+interval, velOut, true) -- add notes by interval to all notes
end
end
end
end
end
end
add_notes(interval) -- call function
reaper.Undo_OnStateChange2(proj, "Add notes +12")
|
|
|
12-16-2017, 06:07 AM
|
#10
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Ah, the problem is that you need to run reaper.MIDI_Sort(take) for each take, after inserting all the notes into the take.
If you use the option noSort=true when inserting notes with MIDI_InsertNote, the note data is temporarily placed in incorrect order at the end of the take, *after* the end-of-take signal.
* You can also use MIDI_EnumSelNotes to find selected notes.
|
|
|
12-16-2017, 06:10 AM
|
#11
|
Human being with feelings
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
|
Quote:
*without* updating the arrange view too
|
How do you expect MIDI items view will be refreshed without updating arrange (or at least updating local item)?
Isn`t GetProjectStateChangeCount solve often refresh issue?
|
|
|
12-16-2017, 06:54 AM
|
#12
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
Quote:
Originally Posted by juliansader
Ah, the problem is that you need to run reaper.MIDI_Sort(take) for each take, after inserting all the notes into the take.
If you use the option noSort=true when inserting notes with MIDI_InsertNote, the note data is temporarily placed in incorrect order at the end of the take, *after* the end-of-take signal.
* You can also use MIDI_EnumSelNotes to find selected notes.
|
Julian, you are my hero! I just fixed it *joy*. This is so awesome
Will take a look into MIDI_EnumSelNotes, it seems I could delete some unnecessary lines of code
|
|
|
05-27-2018, 05:54 AM
|
#14
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
Absolutely agreed, would be awesome!
|
|
|
07-03-2018, 06:27 AM
|
#15
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
A function MIDIEditor_Update that can be used in a "while" loop (thereby avoiding "defer" loops), will have another advantage: scripts would be able to change the mouse cursor.
If a script tries to change the mouse cursor during a defer loop, REAPER restores the mouse cursor during each cycle, resulting in a cursor that flashes between two images.
If a script uses a while loop, REAPER doesn't change the custom cursor until the script is terminated.
|
|
|
04-14-2019, 05:55 PM
|
#16
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
I noticed that undoing changes in the MIDI editor is extremely slow.
Whereas applying the scripts (my nudge notes script based on Set_AllEvts)
executes extremely fast. Even when pressing and holding the shortcut for the script,
visual updates are drawn very fast. But when undoing all these changes, the MIDI editor really struggles. Could this be related somehow?
|
|
|
09-19-2022, 01:22 PM
|
#17
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
Bumping this FR
|
|
|
09-22-2022, 07:36 AM
|
#18
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
Well, apparently, again Julian Sader had to come to the rescue and (unconsciously?) solve this issue. Read further...
This whole MIDI Editor refresh issue is what hinders ALL midi scripts, that need to be refreshed regularly to function properly.
In my experience, this mostly affects Windows machines. Macs don't suffer from this.
Now to the solution. You need to add this in your scripts, after your MIDI has been changed by your script:
Code:
reaper.JS_Window_Update(windowHWND)
Where windowHWND should be the hwnd of your MIDI Editor.
I'm literally speechless, that this issue had to be solved with a 3rd party library and not with a native REAPER solution.
|
|
|
09-26-2022, 10:59 AM
|
#19
|
Human being with feelings
Join Date: Jul 2009
Posts: 3,714
|
Wow, this is a wonderful discovery!!!
I can update the MIDI editor within a for- or while-loop, without waiting for defer!
In my experiments, it seems that updating will only work if MIDI_Sort has been called (including if SetCC/Note is called with the no-sort option = false).
One potential problem: the script will terminate after the timeout period set in Preferences -> ReaScript -> Timeout limit for Lua ReaScripts, and it does so without calling the atexit function.
EDIT: It seems that the termination is handled like a normal script error, so if the script is protected within a pcall, it can continue to its atexit.
Last edited by juliansader; 09-26-2022 at 11:11 AM.
|
|
|
09-26-2022, 11:06 AM
|
#20
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
I discovered this thanks to sockmonkey72, because we were trying to find a way to refresh the ME
But I still find it crazy, that we have to jump through hoops in order to get MIDI scripts refresh often enough.
|
|
|
02-26-2023, 04:37 PM
|
#21
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,067
|
Quote:
Originally Posted by juliansader
Wow, this is a wonderful discovery!!!
I can update the MIDI editor within a for- or while-loop, without waiting for defer!
|
But will this also work, if the executed script is a defer script?
Or did I misunderstand?
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 03:37 AM.
|