Old 12-06-2022, 11:11 AM   #1
mozart999uk
Human being with feelings
 
Join Date: Nov 2010
Posts: 1,742
Default Retroactive record in MIDI editor

Could we have retroactive ability within the midi editor?

Midi item open
Press play and play some notes or move a controller.
Stop playback
Press shortcut of choice and voila - notes or controller now in the item. :-)
mozart999uk is offline   Reply With Quote
Old 12-06-2022, 11:21 AM   #2
tonalstates
Human being with feelings
 
tonalstates's Avatar
 
Join Date: Jun 2020
Posts: 665
Default

yes pls +1
tonalstates is online now   Reply With Quote
Old 12-06-2022, 12:57 PM   #3
juan_r
Human being with feelings
 
juan_r's Avatar
 
Join Date: Oct 2019
Posts: 1,082
Default

+1

Great workflow indeed
__________________
My ReaPack repository: https://github.com/juanriccio/Reaper...ster/index.xml
juan_r is offline   Reply With Quote
Old 12-06-2022, 02:24 PM   #4
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
Default

Code:
 
  function MPL_DumpRetrospectiveLog(take) -- collect raw data 
    local t = {}
    local idx = 0
    local evt_id = 0      
    local SR = tonumber(reaper.format_timestr_pos( 1-reaper.GetProjectTimeOffset( 0,false ), '', 4 )) -- get sample rate obey project start offset
    
    while true do
      local retval, rawmsg, tsval, devIdx, projPos, projLoopCnt = reaper.MIDI_GetRecentInputEvent(idx)
      if retval == 0 then break end -- stop if return null sequence
      idx = idx + 1 
      if (devIdx & 0x10000) == 0 or devIdx == 0x1003e then -- should works without this after REAPER6.39rc2, so thats just in case
        local isNoteOn = rawmsg:byte(1)>>4 == 0x9
        local isNoteOff = rawmsg:byte(1)>>4 == 0x8
        evt_id = evt_id + 1 
        
        if t[evt_id-1] and math.abs(tsval/SR - t[evt_id-1].tsval) > 10 then goto skip end -- filter last long pause
        
        t[evt_id] = {rawmsg=rawmsg, tsval=tsval/SR}
      end
    end 
    
    ::skip::
    -- reverse table
      local rev_t = {}
      local rev_t_id = 0
      for i=#t, 1, -1 do rev_t_id = rev_t_id + 1 rev_t[rev_t_id] = t[i] end
      local sub = -  rev_t[1].tsval 
      for i=1, #rev_t do rev_t[i].tsval = rev_t[i].tsval + sub end
      
    -- get ppq 
      local curpos =  reaper.GetCursorPosition()
      for i=1, #rev_t do rev_t[i].tsval_PPQ = math.floor(reaper.MIDI_GetPPQPosFromProjTime( take, rev_t[i].tsval+curpos)) end
      
      local retval, srcmidistr = reaper.MIDI_GetAllEvts( take )
      local midistr = ''
      local ppq_cur_last   = 0  
      for i=1, #rev_t do
        local evt = rev_t[i]
        local ppq_evt = rev_t[i].tsval_PPQ
        ppq_cur = ppq_evt
        if not ppq_cur_last then ppq_cur_last = ppq_cur end
        local str_per_msg = string.pack("i4BI4BBB", ppq_cur - ppq_cur_last, 0, 3, evt.rawmsg:byte(1), evt.rawmsg:byte(2), evt.rawmsg:byte(3))
        ppq_cur_last = ppq_cur
        midistr = midistr..str_per_msg
      end
      
      local str_per_msg = string.pack("i4BI4BBB", 0 - ppq_cur_last, 0, 3, 0,0,0)
      midistr = midistr..str_per_msg
      
      reaper.MIDI_SetAllEvts(take, midistr..srcmidistr)
      reaper.MIDI_Sort(take) 
    return rev_t
  end

    
    
    local midieditor,take =  reaper.MIDIEditor_GetActive()
    if midieditor then take = reaper.MIDIEditor_GetTake( midieditor ) end
    if take then 
      reaper.Undo_BeginBlock2( 0 )
      midi_t = MPL_DumpRetrospectiveLog(take)
      reaper.Undo_EndBlock2( 0, 'MPL_DumpRetrospectiveLog', 4)
    end
mpl is offline   Reply With Quote
Old 12-06-2022, 06:08 PM   #5
juan_r
Human being with feelings
 
juan_r's Avatar
 
Join Date: Oct 2019
Posts: 1,082
Default

@mpl to the rescue :-)
Thank you - impressively quick!
__________________
My ReaPack repository: https://github.com/juanriccio/Reaper...ster/index.xml
juan_r is offline   Reply With Quote
Old 12-06-2022, 09:58 PM   #6
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,984
Default

that doesn't break data just like it does in the main script or native action though. Instead it split play blocks if pause between them more than 10 seconds.
mpl is offline   Reply With Quote
Old 12-07-2022, 04:21 AM   #7
juan_r
Human being with feelings
 
juan_r's Avatar
 
Join Date: Oct 2019
Posts: 1,082
Default

Thanks for the heads up. I didn't notice that since I just had a quick run at it to verify it works.

I guess the native action request still stands, then?
__________________
My ReaPack repository: https://github.com/juanriccio/Reaper...ster/index.xml
juan_r is offline   Reply With Quote
Old 12-11-2022, 07:55 AM   #8
juan_r
Human being with feelings
 
juan_r's Avatar
 
Join Date: Oct 2019
Posts: 1,082
Default

I just noticed that this action doesn't seem to add an undo point. How can I modify it so that it does?

Also, I'm not clear about which section to add the script to. It gets added to Main by default but apparently still works OK in the MIDI Editor section (that's where it gets used normally, right?).
__________________
My ReaPack repository: https://github.com/juanriccio/Reaper...ster/index.xml
juan_r is offline   Reply With Quote
Old 12-11-2022, 08:00 AM   #9
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by juan_r View Post
Also, I'm not clear about which section to add the script to. It gets added to Main by default but apparently still works OK in the MIDI Editor section (that's where it gets used normally, right?).
With scripts it doesn't matter.
vitalker is offline   Reply With Quote
Old 12-19-2022, 03:18 AM   #10
mozart999uk
Human being with feelings
 
Join Date: Nov 2010
Posts: 1,742
Default

Quote:
Originally Posted by mpl View Post
Code:
 
  function MPL_DumpRetrospectiveLog(take) -- collect raw data 
    local t = {}
    local idx = 0
    local evt_id = 0      
    local SR = tonumber(reaper.format_timestr_pos( 1-reaper.GetProjectTimeOffset( 0,false ), '', 4 )) -- get sample rate obey project start offset
    
    while true do
      local retval, rawmsg, tsval, devIdx, projPos, projLoopCnt = reaper.MIDI_GetRecentInputEvent(idx)
      if retval == 0 then break end -- stop if return null sequence
      idx = idx + 1 
      if (devIdx & 0x10000) == 0 or devIdx == 0x1003e then -- should works without this after REAPER6.39rc2, so thats just in case
        local isNoteOn = rawmsg:byte(1)>>4 == 0x9
        local isNoteOff = rawmsg:byte(1)>>4 == 0x8
        evt_id = evt_id + 1 
        
        if t[evt_id-1] and math.abs(tsval/SR - t[evt_id-1].tsval) > 10 then goto skip end -- filter last long pause
        
        t[evt_id] = {rawmsg=rawmsg, tsval=tsval/SR}
      end
    end 
    
    ::skip::
    -- reverse table
      local rev_t = {}
      local rev_t_id = 0
      for i=#t, 1, -1 do rev_t_id = rev_t_id + 1 rev_t[rev_t_id] = t[i] end
      local sub = -  rev_t[1].tsval 
      for i=1, #rev_t do rev_t[i].tsval = rev_t[i].tsval + sub end
      
    -- get ppq 
      local curpos =  reaper.GetCursorPosition()
      for i=1, #rev_t do rev_t[i].tsval_PPQ = math.floor(reaper.MIDI_GetPPQPosFromProjTime( take, rev_t[i].tsval+curpos)) end
      
      local retval, srcmidistr = reaper.MIDI_GetAllEvts( take )
      local midistr = ''
      local ppq_cur_last   = 0  
      for i=1, #rev_t do
        local evt = rev_t[i]
        local ppq_evt = rev_t[i].tsval_PPQ
        ppq_cur = ppq_evt
        if not ppq_cur_last then ppq_cur_last = ppq_cur end
        local str_per_msg = string.pack("i4BI4BBB", ppq_cur - ppq_cur_last, 0, 3, evt.rawmsg:byte(1), evt.rawmsg:byte(2), evt.rawmsg:byte(3))
        ppq_cur_last = ppq_cur
        midistr = midistr..str_per_msg
      end
      
      local str_per_msg = string.pack("i4BI4BBB", 0 - ppq_cur_last, 0, 3, 0,0,0)
      midistr = midistr..str_per_msg
      
      reaper.MIDI_SetAllEvts(take, midistr..srcmidistr)
      reaper.MIDI_Sort(take) 
    return rev_t
  end

    
    
    local midieditor,take =  reaper.MIDIEditor_GetActive()
    if midieditor then take = reaper.MIDIEditor_GetTake( midieditor ) end
    if take then 
      reaper.Undo_BeginBlock2( 0 )
      midi_t = MPL_DumpRetrospectiveLog(take)
      reaper.Undo_EndBlock2( 0, 'MPL_DumpRetrospectiveLog', 4)
    end

Thanks MPL! It doesn't add the notes where I played them though. It adds them at the current edit cursor position (wherever it is after I stopped playback)
mozart999uk 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 04:17 PM.


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