Old 02-11-2023, 12:53 PM   #321
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by mister happy View Post
It would be great to follow up the Open Midid Editor function with a quick command to zoom horizontally to the project timeline loop points.
The reason I didn't add zoom to selection is that there's native actions for that in the MIDI editor section:

E.g. View: Zoom to project loop selection
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 02-11-2023, 01:23 PM   #322
mister happy
Human being with feelings
 
Join Date: Mar 2017
Location: in the moment
Posts: 647
Default

Triple face palm!!

You have reminded me that

1) Before I asked you about this the last time I thought about it I figured out that there is a native action all by myself. :-S

2) I made a homemade toolbar icon just for this action and added it to my tool bar next to the icons I added for your custom scripts.

3) ... and then I forgot about it.

Nothing to see here...

:-P

Thanks very much!!!
mister happy is offline   Reply With Quote
Old 02-12-2023, 04:58 PM   #323
ovnis
Human being with feelings
 
ovnis's Avatar
 
Join Date: Oct 2011
Posts: 2,924
Default

Hello,



Do you know what I have to change in this script (FTC_MeMagic (4-3) Horizontally zoom to 4 measures at mouse or edit cursor, restrict to item + Vertically zoom to all notes in item) to avoid the movement of my MIDI editor when I move the edit cursor inside the arrangment window?



Thx you!




Last edited by ovnis; 02-12-2023 at 05:22 PM.
ovnis is offline   Reply With Quote
Old 02-12-2023, 05:58 PM   #324
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by ovnis View Post
Do you know what I have to change in this script (FTC_MeMagic (4-3) Horizontally zoom to 4 measures at mouse or edit cursor, restrict to item + Vertically zoom to all notes in item) to avoid the movement of my MIDI editor when I move the edit cursor inside the arrangment window?
Don't think it's script related, but maybe "Options: Synchronize transport with main transport" is on?
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 02-12-2023, 06:00 PM   #325
ovnis
Human being with feelings
 
ovnis's Avatar
 
Join Date: Oct 2011
Posts: 2,924
Default

That's it! Thx you!
ovnis is offline   Reply With Quote
Old 02-22-2023, 10:14 AM   #326
ovnis
Human being with feelings
 
ovnis's Avatar
 
Join Date: Oct 2011
Posts: 2,924
Default

Hi!

Sometimes, when I click on an audio item, I have got this error message:



Attached Images
File Type: png bKQMMSJqKV.png (7.7 KB, 425 views)
File Type: png reaper_OaYisBQOmm.png (10.5 KB, 405 views)
ovnis is offline   Reply With Quote
Old 02-22-2023, 12:38 PM   #327
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by ovnis View Post
Hi!

Sometimes, when I click on an audio item, I have got this error message:



Can you post the code of the script pls (I think we had made some modifications). I'll look into it.
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 02-22-2023, 04:17 PM   #328
ovnis
Human being with feelings
 
ovnis's Avatar
 
Join Date: Oct 2011
Posts: 2,924
Default

Code:
--[[
  @author Ilias-Timon Poulakis (FeedTheCat)
  @license MIT
  @version 1.0.9
  @noindex
  @about Automatically generated configuration of MeMagic
]]
------------------------------ ZOOM MODES -----------------------------

-- HORIZONTAL MODES
-- 1: No change
-- 2: Zoom to item
-- 3: Zoom to number of measures at mouse or edit cursor
-- 4: Zoom to number of measures at mouse or edit cursor, restrict to item
-- 5: Smart zoom to number of notes at mouse or edit cursor
-- 6: Smart zoom to number of notes at mouse or edit cursor, restrict to item
-- 7: Scroll to mouse or edit cursor

-- VERTICAL MODES
-- 1: No change
-- 2: Zoom to notes in visible area
-- 3: Zoom to all notes in item
-- 4: Scroll note row under mouse cursor
-- 5: Scroll note row under mouse cursor, restrict to notes in visible area
-- 6: Scroll note row under mouse cursor, restrict to notes in item
-- 7: Scroll to center of notes in visible area
-- 8: Scroll to center of notes in item
-- 9: Scroll to lowest note in visible area
-- 10: Scroll to lowest note in item
-- 11: Scroll to highest note in visible area
-- 12: Scroll to highest note in item

-- Note: You can assign a different zoom mode to each MIDI editor timebase
-- by using an array with four elements, e.g {1, 2, 3, 1}
-- { Beats (project), Beats (source), Time (project), Sync to arrange }

-- Context: Toolbar button
local TBB_horizontal_zoom_mode = 4
local TBB_vertical_zoom_mode = 3

-- Context: MIDI editor note area
local MEN_horizontal_zoom_mode = 1
local MEN_vertical_zoom_mode = {6, 3, 3, 6}

-- Context: MIDI editor piano pane
local MEP_horizontal_zoom_mode = 2
local MEP_vertical_zoom_mode = 2

-- Context: MIDI editor ruler
local MER_horizontal_zoom_mode = 1
local MER_vertical_zoom_mode = {9, 9, 3, 9}

-- Context: MIDI editor CC lanes
local MEC_horizontal_zoom_mode = {1, 1, 5, 1}
local MEC_vertical_zoom_mode = {7, 7, 3, 7}

-- Context: Arrange view area
local AVA_horizontal_zoom_mode = 1
local AVA_vertical_zoom_mode = 3

-- Context: Arrange view item single click (mouse modifier)
local AIS_horizontal_zoom_mode = 5
local AIS_vertical_zoom_mode = 3

-- Context: Arrange view item double click (mouse modifier)
local AID_horizontal_zoom_mode = 2
local AID_vertical_zoom_mode = 2

------------------------------ GENERAL SETTINGS -----------------------------

-- Make this action non-contextual and always use modes from context: Toolbar button
local use_toolbar_context_only = true

-- Follow play cursor instead of edit cursor when playing
local use_play_cursor = false

-- Move edit cursor to mouse cursor
local set_edit_cursor = true

------------------------------ ZOOM SETTINGS -----------------------------

-- Number of measures to zoom to (for horizontal modes 3 and 4)
local number_of_measures = 8

-- Number of (approximate) notes to zoom to (for horizontal modes 5 and 6)
local number_of_notes = 10

-- Determines how influential the cursor position is on smart zoom levels
-- No influence: 0,  High influence: >1,  Default: 0.75
local smoothing = 0.75

-- Which note to zoom to when item/visible area contains no notes
local base_note = 60

-- Minimum number of vertical notes when zooming (not exact)
local min_vertical_notes = 8

-- Maximum vertical size for notes in pixels (smaller values increase performance)
local max_vertical_note_pixels = 20

------------------------------ FUNCTIONS ------------------------------------

local debug = false
local mb_title = 'MIDI Editor Magic'
local undo_name = 'Change media item selection (MeMagic)'
undo_name = use_toolbar_context_only and 'MeMagic zoom/scroll' or undo_name

function print(msg)
    if debug then
        reaper.ShowConsoleMsg(tostring(msg) .. '\n')
    end
end

function setOnlyItemSelected(sel_item)
    for i = reaper.CountSelectedMediaItems(0) - 1, 0, -1 do
        local item = reaper.GetSelectedMediaItem(0, i)
        if item then
            reaper.SetMediaItemSelected(item, false)
        end
    end
    reaper.SetMediaItemSelected(sel_item, true)
end

function getSelection()
    local getSetLoopTimeRange = reaper.GetSet_LoopTimeRange
    local sel_start_pos, sel_end_pos = getSetLoopTimeRange(false, true, 0, 0, false)
    local is_valid_sel = sel_end_pos > 0 and sel_start_pos ~= sel_end_pos
    if is_valid_sel then
        local sel = {}
        sel.start_pos = sel_start_pos
        sel.end_pos = sel_end_pos
        return sel
    end
end

function setSelection(sel_start_pos, sel_end_pos)
    reaper.GetSet_LoopTimeRange(true, true, sel_start_pos, sel_end_pos, false)
end

function getClickMode(cmd)
    local mode = 0
    local modifiers = {
        'MM_CTX_ITEM_CLK',
        'MM_CTX_ITEM_DBLCLK',
        'MM_CTX_ITEMLOWER_CLK',
        'MM_CTX_ITEMLOWER_DBLCLK'
    }
    for _, modifier in ipairs(modifiers) do
        for i = 0, 15 do
            local action = reaper.GetMouseModifier(modifier, i, '')
            if not tonumber(action) then
                local modifier_cmd = reaper.NamedCommandLookup(action)
                if modifier_cmd == cmd then
                    local mode_id = modifier:match('DBLCLK') and 2 or 1
                    mode = mode | mode_id
                    break
                end
            end
        end
    end
    return mode
end

function getCursorPosition(play_state)
    local cursor_pos = reaper.BR_GetMouseCursorContext_Position()
    if not cursor_pos or cursor_pos < 0 or set_edit_cursor then
        cursor_pos = reaper.GetCursorPosition()
    end
    if play_state > 0 and use_play_cursor then
        cursor_pos = reaper.GetPlayPosition()
    end
    return cursor_pos
end

function getZoomMode(context, timebase)
    local modes = {}

    modes[0] = {}
    modes[0].name = 'Toolbar button'
    modes[0].hzoom = TBB_horizontal_zoom_mode
    modes[0].vzoom = TBB_vertical_zoom_mode

    modes[10] = {}
    modes[10].name = 'Arrange view area'
    modes[10].hzoom = AVA_horizontal_zoom_mode
    modes[10].vzoom = AVA_vertical_zoom_mode

    modes[20] = {}
    modes[20].name = 'MIDI editor note area'
    modes[20].hzoom = MEN_horizontal_zoom_mode
    modes[20].vzoom = MEN_vertical_zoom_mode

    modes[21] = {}
    modes[21].name = 'MIDI editor piano pane'
    modes[21].hzoom = MEP_horizontal_zoom_mode
    modes[21].vzoom = MEP_vertical_zoom_mode

    modes[22] = {}
    modes[22].name = 'MIDI editor ruler'
    modes[22].hzoom = MER_horizontal_zoom_mode
    modes[22].vzoom = MER_vertical_zoom_mode

    modes[23] = {}
    modes[23].name = 'MIDI editor CC lanes'
    modes[23].hzoom = MEC_horizontal_zoom_mode
    modes[23].vzoom = MEC_vertical_zoom_mode

    modes[30] = {}
    modes[30].name = 'Arrange view item single click'
    modes[30].hzoom = AIS_horizontal_zoom_mode
    modes[30].vzoom = AIS_vertical_zoom_mode

    modes[31] = {}
    modes[31].name = 'Arrange view item double click'
    modes[31].hzoom = AID_horizontal_zoom_mode
    modes[31].vzoom = AID_vertical_zoom_mode

    local hzoom_mode, vzoom_mode
    local mode = modes[context]
    if not mode then
        print('Zoom mode of context not found')
    end

    local hzoom_min = 1
    local hzoom_max = 7

    local vzoom_min = 1
    local vzoom_max = 12

    local msg1 = 'Invalid %s zoom mode for context: %s\n'
    local msg2 = 'Mode has to be a number between %d and %d'
    local msg3 = 'Mode per timebase needs a table with 4 entries'

    if type(mode.hzoom) == 'number' then
        if mode.hzoom >= hzoom_min and mode.hzoom <= hzoom_max then
            hzoom_mode = mode.hzoom
        else
            local msg = msg1:format('horizontal', mode.name)
            msg = msg .. msg2:format(hzoom_min, hzoom_max)
            reaper.MB(msg, mb_title, 0)
        end
    end

    if type(mode.hzoom) == 'table' then
        if #mode.hzoom >= 4 then
            local timebase_hzoom = mode.hzoom[timebase]
            if timebase_hzoom >= hzoom_min and timebase_hzoom <= hzoom_max then
                hzoom_mode = timebase_hzoom
            else
                local msg = msg1:format('horizontal', mode.name)
                msg = msg .. msg2:format(hzoom_min, hzoom_max)
                reaper.MB(msg, mb_title, 0)
            end
        else
            local msg = msg1:format('horizontal', mode.name)
            reaper.MB(msg .. msg3, mb_title, 0)
        end
    end

    if type(mode.vzoom) == 'number' then
        if mode.vzoom >= vzoom_min and mode.vzoom <= vzoom_max then
            vzoom_mode = mode.vzoom
        else
            local msg = msg1:format('vertical', mode.name)
            msg = msg .. msg2:format(vzoom_min, vzoom_max)
            reaper.MB(msg, mb_title, 0)
        end
    end

    if type(mode.vzoom) == 'table' then
        if #mode.vzoom >= 4 then
            local timebase_vzoom = mode.vzoom[timebase]
            if timebase_vzoom >= vzoom_min and timebase_vzoom <= vzoom_max then
                vzoom_mode = timebase_vzoom
            else
                local msg = msg1:format('vertical', mode.name)
                msg = msg .. msg2:format(vzoom_min, vzoom_max)
                reaper.MB(msg, mb_title, 0)
            end
        else
            local msg = msg1:format('vertical', mode.name)
            reaper.MB(msg .. msg3, mb_title, 0)
        end
    end

    return hzoom_mode, vzoom_mode
end

function setMode(hwnd, mode)
    if mode then
        local cmds = {40042, 40043, 40056, 40954}
        reaper.MIDIEditor_OnCommand(hwnd, cmds[mode])
    end
end

function setHideUnused(hwnd, unused)
    if unused then
        local cmds = {40452, 40453, 40454}
        reaper.MIDIEditor_OnCommand(hwnd, cmds[unused])
    end
end

function setTimebase(hwnd, timebase)
    if timebase then
        local cmds = {40459, 40470, 40460, 40461}
        reaper.MIDIEditor_OnCommand(hwnd, cmds[timebase])
    end
end

function getEditorTimeBase()
    local timebase = 0
    timebase = reaper.GetToggleCommandStateEx(32060, 40459) == 1 and 1 or timebase
    timebase = reaper.GetToggleCommandStateEx(32060, 40470) == 1 and 2 or timebase
    timebase = reaper.GetToggleCommandStateEx(32060, 40460) == 1 and 3 or timebase
    timebase = reaper.GetToggleCommandStateEx(32060, 40461) == 1 and 4 or timebase
    return timebase
end

function getItemChunkConfig(item, chunk, config)
    -- Parse the chunk to get the correct config for the active take
    local curr_tk = reaper.GetMediaItemInfo_Value(item, 'I_CURTAKE')
    local pattern = config .. ' .-\n'
    local s, e = chunk:find(pattern, s)
    local i = 0
    for _ = 0, curr_tk do
        s = i
        i = i + 1
        s, e = chunk:find(pattern, s)
        i = chunk:find('\nTAKE[%s\n]', i)
    end
    if s and i and s > i then
        s = nil
    end
    return s and chunk:sub(s, e)
end

function getConfigMode(cfg_edit)
    local pattern = 'CFGEDIT .- .- .- .- .- (.-) '
    if cfg_edit then
        local mode = tonumber(cfg_edit:match(pattern))
        mode = mode & 37
        return mode == 32 and 4 or mode == 4 and 3 or mode == 1 and 2 or 1
    end
end

function getConfigHideUnused(cfg_edit)
    local pattern = 'CFGEDIT .- .- .- .- .- .- .- .- .- .- .- .- .- .- .- .- .- (.-) '
    if cfg_edit then
        local unused = tonumber(cfg_edit:match(pattern))
        return unused + 1
    end
end

function getConfigTimebase(cfg_edit)
    local pattern = 'CFGEDIT .- .- .- .- .- .- .- .- .- .- .- .- .- .- .- .- .- .- (.-) '
    if cfg_edit then
        local tb = tonumber(cfg_edit:match(pattern))
        return tb == 1 and 4 or tb == 2 and 3 or tb == 4 and 2 or 1
    end
end

function getConfigHZoom(cfg_edit_view)
    local pattern = 'CFGEDITVIEW (.-) (.-) '
    if cfg_edit_view then
        local offset, level = cfg_edit_view:match(pattern)
        return tonumber(level), tonumber(offset)
    end
    return -1, -1
end

function getConfigVZoom(cfg_edit_view)
    local pattern = 'CFGEDITVIEW .- .- (.-) (.-) '
    if cfg_edit_view then
        local offset, size = cfg_edit_view:match(pattern)
        return 127 - tonumber(offset), tonumber(size)
    end
    return -1, -1
end

function getItemHZoom(item)
    local _, chunk = reaper.GetItemStateChunk(item, '', true)
    local cfg_edit_view = getItemChunkConfig(item, chunk, 'CFGEDITVIEW')
    return getConfigHZoom(cfg_edit_view)
end

function getItemVZoom(item)
    local _, chunk = reaper.GetItemStateChunk(item, '', true)
    local cfg_edit_view = getItemChunkConfig(item, chunk, 'CFGEDITVIEW')
    return getConfigVZoom(cfg_edit_view)
end

function getRelativeSourcePPQ(take, pos)
    local ppq_pos = reaper.MIDI_GetPPQPosFromProjTime(take, pos)
    local qn_pos = reaper.TimeMap2_timeToQN(0, pos)

    local source = reaper.GetMediaItemTake_Source(take)
    local source_length = reaper.GetMediaSourceLength(source)

    local start_qn = reaper.MIDI_GetProjQNFromPPQPos(take, 0)
    local source_qn_pos = start_qn + (qn_pos - start_qn) % source_length
    return reaper.MIDI_GetPPQPosFromProjQN(take, source_qn_pos)
end

function getRelativeSourcePos(take, pos)
    local source_ppq_pos = getRelativeSourcePPQ(take, pos)
    return reaper.MIDI_GetProjTimeFromPPQPos(take, source_ppq_pos)
end

function getSourcePPQLength(take)
    local source = reaper.GetMediaItemTake_Source(take)
    local source_length = reaper.GetMediaSourceLength(source)
    local start_qn = reaper.MIDI_GetProjQNFromPPQPos(take, 0)
    return reaper.MIDI_GetPPQPosFromProjQN(take, start_qn + source_length)
end

function getHorizontalEditorLength(hwnd, item, timebase)
    if timebase == 2 or timebase == 4 then
        setTimebase(hwnd, 1)
    end

    local _, offset = getItemHZoom(item)
    -- Cmd: Scroll view right
    reaper.MIDIEditor_OnCommand(hwnd, 40141)

    local _, scroll_offset = getItemHZoom(item)
    -- Cmd: Scroll view left
    reaper.MIDIEditor_OnCommand(hwnd, 40140)

    if timebase == 2 or timebase == 4 then
        setTimebase(hwnd, timebase)
    end

    local take = reaper.GetActiveTake(item)
    local start_pos = reaper.MIDI_GetProjTimeFromPPQPos(take, offset)
    local end_pos = reaper.MIDI_GetProjTimeFromPPQPos(take, scroll_offset)

    -- A factor is necessary to convert to the selection used for the action
    -- "Zoom to project loop selection" which is smaller than the actual visible area
    local factor = timebase == 2 and 0.97087377 or 0.943396226415
    local area = end_pos - start_pos
    local center = start_pos + area / 2
    return area * factor, center
end

function getSmartZoomRange(take, pos, item_start_pos, item_end_pos)
    -- Algorithm is based on Shephard's method of inverse distance weighting
    -- https://en.wikipedia.org/wiki/Invers...ance_weighting

    -- An average of all note lengths and gaps between notes is calculated. By using
    -- inverse distance weighting, notes/gaps closer to the given position have a
    -- stronger influence on the result

    -- The smoothing factor determines how much stronger this influence can be.
    -- A smoothing factor of 0, would make the distance to the given position irrelevant.

    local item = reaper.GetMediaItemTake_Item(take)
    local source_ppq_length = getSourcePPQLength(take)

    local ppq_pos = reaper.MIDI_GetPPQPosFromProjTime(take, pos)
    local start_ppq = reaper.MIDI_GetPPQPosFromProjTime(take, item_start_pos)
    local end_ppq = reaper.MIDI_GetPPQPosFromProjTime(take, item_end_pos)

    local loop_start, loop_end = 0, 0
    if reaper.GetMediaItemInfo_Value(item, 'B_LOOPSRC') == 1 then
        local curr_iteration = math.floor(ppq_pos / source_ppq_length)
        -- For looped items
        if end_ppq - start_ppq > source_ppq_length then
            loop_start = math.max(0, curr_iteration - 1)
            loop_end = curr_iteration + 1
        end
    end

    local note_length_sum = 0
    local note_weight_sum = 0

    local prev_eppq = start_ppq
    local gap_length = 0
    local min_note_distance = math.huge

    local i = 0
    repeat
        local ret, _, _, sppq, eppq = reaper.MIDI_GetNote(take, i)
        if ret then
            local note_length = eppq - sppq
            -- Add gap between notes to note length
            if sppq >= prev_eppq then
                -- Limit gap length to something reasonable
                local min_gap_length = note_length * number_of_notes
                gap_length = math.min(min_gap_length, sppq - prev_eppq)
            end
            if eppq > prev_eppq then
                prev_eppq = eppq
            end
            for n = loop_start, loop_end do
                local sppq_o = sppq + n * source_ppq_length
                local eppq_o = eppq + n * source_ppq_length
                if eppq_o > start_ppq and sppq_o < end_ppq then
                    local note_center_ppq = sppq_o + note_length / 2
                    local note_distance = math.abs(note_center_ppq - ppq_pos)
                    -- Avoid dividing by zero (and attributing very high weights)
                    note_distance = math.max(note_distance, note_length)
                    min_note_distance = math.min(min_note_distance, note_distance)

                    local note_weight = 1 / note_distance ^ smoothing
                    local gap_note_length = note_length + gap_length
                    note_length_sum = note_length_sum + note_weight * gap_note_length
                    note_weight_sum = note_weight_sum + note_weight
                end
            end
        end
        i = i + 1
    until not ret

    if note_weight_sum == 0 then
        return
    end

    local avg_note_length = note_length_sum / note_weight_sum
    print('Avg note length: ' .. math.floor(avg_note_length))
    local zoom_ppq_length = avg_note_length * number_of_notes

    -- If the area is empty, keep at least one note visible
    if min_note_distance ~= math.huge and zoom_ppq_length / 2.5 < min_note_distance then
        print('Using empty area hzoom level')
        zoom_ppq_length = min_note_distance * 2.5
    end

    return zoom_ppq_length
end

function getPitchRange(take, start_pos, end_pos, item_start_pos, item_end_pos)
    local item = reaper.GetMediaItemTake_Item(take)
    local item_start_ppq = reaper.MIDI_GetPPQPosFromProjTime(take, item_start_pos)
    local item_end_ppq = reaper.MIDI_GetPPQPosFromProjTime(take, item_end_pos)

    local start_ppq = reaper.MIDI_GetPPQPosFromProjTime(take, start_pos)
    local end_ppq = reaper.MIDI_GetPPQPosFromProjTime(take, end_pos)

    start_ppq = math.max(start_ppq, item_start_ppq)
    end_ppq = math.min(end_ppq, item_end_ppq)

    if reaper.GetMediaItemInfo_Value(item, 'B_LOOPSRC') == 1 then
        local source_ppq_length = getSourcePPQLength(take)
        if end_ppq - start_ppq >= source_ppq_length then
            start_ppq = 0
            end_ppq = source_ppq_length
        else
            start_ppq = start_ppq % source_ppq_length
            end_ppq = end_ppq % source_ppq_length
        end
    end

    local function isNoteVisible(sppq, eppq)
        if end_ppq < start_ppq then
            return eppq > start_ppq or sppq < end_ppq
        else
            return eppq > start_ppq and sppq < end_ppq
        end
    end

    local note_lo = 128
    local note_hi = -1

    local density = 0
    local density_cnt = 0

    local i = 0
    repeat
        local ret, _, _, sppq, eppq, _, pitch = reaper.MIDI_GetNote(take, i)
        if ret and isNoteVisible(sppq, eppq) then
            note_lo = math.min(note_lo, pitch)
            note_hi = math.max(note_hi, pitch)
            density = density + pitch
            density_cnt = density_cnt + 1
        end
        i = i + 1
    until not ret

    return note_lo, note_hi, density_cnt > 0 and density / density_cnt
end

function zoomToPitchRange(hwnd, item, note_lo, note_hi)
    -- Get previous active note row
    local setting = 'active_note_row'
    local active_row = reaper.MIDIEditor_GetSetting_int(hwnd, setting)

    note_lo = math.max(note_lo, 0)
    note_hi = math.min(note_hi, 127)
    local target_row = math.floor((note_lo + note_hi) / 2)
    local curr_row = getItemVZoom(item)

    local target_range = math.ceil((note_hi - note_lo) / 2)

    -- Set active note row to set center of vertical zoom
    reaper.MIDIEditor_SetSetting_int(hwnd, setting, curr_row)

    -- Note: Zooming when row is visible centers the note row
    -- Cmd: Zoom out vertically
    reaper.MIDIEditor_OnCommand(hwnd, 40112)

    -- Debugging output
    local row_string = ' -> ' .. curr_row
    local zoom_string = ' -> out'

    local i = 0
    repeat
        local row, size = getItemVZoom(item)
        local pitch_range = math.min(-2, curr_row - row + 1) * -1

        if curr_row > target_row then
            curr_row = math.max(target_row, curr_row - pitch_range)
        else
            curr_row = math.min(target_row, curr_row + pitch_range)
        end
        -- Set active note row to set center of vertical zoom
        reaper.MIDIEditor_SetSetting_int(hwnd, setting, curr_row)
        row_string = row_string .. ' -> ' .. curr_row

        if pitch_range > target_range and size < max_vertical_note_pixels then
            -- Cmd: Zoom in vertically
            reaper.MIDIEditor_OnCommand(hwnd, 40111)
            zoom_string = zoom_string .. ' -> in'
        else
            -- Cmd: Zoom out vertically
            reaper.MIDIEditor_OnCommand(hwnd, 40112)
            zoom_string = zoom_string .. ' -> out'
        end
        i = i + 1
    until i == 50 or curr_row == target_row

    zoom_string = zoom_string .. ' |'

    repeat
        local row, size = getItemVZoom(item)
        local pitch_range = math.abs(curr_row - row)
        if size > max_vertical_note_pixels then
            print('Reached max zoom size!')
            break
        end
        -- Cmd: Zoom in vertically
        reaper.MIDIEditor_OnCommand(hwnd, 40111)
        zoom_string = zoom_string .. ' -> in'
        i = i + 1
    until i == 50 or pitch_range < target_range

    repeat
        local row, size = getItemVZoom(item)
        local pitch_range = math.abs(curr_row - row)
        if size == 4 then
            print('Reached min zoom size!')
            break
        end
        -- Cmd: Zoom out vertically
        reaper.MIDIEditor_OnCommand(hwnd, 40112)
        zoom_string = zoom_string .. ' -> out'
        i = i + 1
    until i == 50 or pitch_range >= target_range and size <= max_vertical_note_pixels

    print('Target row:' .. target_row)
    print(row_string)
    print(zoom_string)
    local _, zoom_cnt = zoom_string:gsub(' %-', '')
    print('Vertically zooming ' .. zoom_cnt .. ' times')

    -- Reset previous active note row
    if active_row and active_row ~= '' then
        reaper.MIDIEditor_SetSetting_int(hwnd, setting, active_row)
    end
end

function scrollToNoteRow(hwnd, item, target_row, note_lo, note_hi)
    -- Get previous active note row
    local setting = 'active_note_row'
    local active_row = reaper.MIDIEditor_GetSetting_int(hwnd, setting)

    local curr_row = getItemVZoom(item)
    -- Set active note row to set center of vertical zoom
    reaper.MIDIEditor_SetSetting_int(hwnd, setting, curr_row)

    if note_lo and note_hi then
        note_lo = math.max(note_lo, 0)
        note_hi = math.min(note_hi, 127)
        target_row = math.max(target_row, note_lo)
        target_row = math.min(target_row, note_hi)
    end

    -- Note: Zooming when row is visible centers the note row
    -- Cmd: Zoom in vertically
    reaper.MIDIEditor_OnCommand(hwnd, 40111)
    local zoom_in_cnt = 1
    local backup_target_row
    local target_range

    -- Debugging output
    local row_string = ' -> ' .. curr_row
    local zoom_string = ' -> in'

    local i = 0
    repeat
        local row, size = getItemVZoom(item)
        local pitch_range = math.min(-2, curr_row - row + 1) * -1

        if row == 127 and i == 0 and not backup_target_row then
            -- When row 127 is visible it's not possible to get the target range.
            -- Scroll down until it isn't and keep target row as backup
            backup_target_row = target_row
            target_row = 0
        end

        if row < 127 and zoom_in_cnt == 0 and not target_range then
            target_range = pitch_range
            target_row = backup_target_row or target_row

            local note_range = math.ceil((note_hi - note_lo) / 2)
            if pitch_range > note_range then
                local diff = pitch_range - note_range
                note_hi = note_hi + diff * 2
                note_lo = note_lo - diff * 2
            end
            if target_row < note_lo + pitch_range then
                target_row = note_lo + pitch_range
            else
                if target_row > note_hi - pitch_range then
                    target_row = note_hi - pitch_range
                end
            end
            zoom_string = zoom_string .. ' -> R'
            row_string = row_string .. ' -> R'
        end

        if curr_row > target_row then
            curr_row = math.max(target_row, curr_row - pitch_range)
        else
            curr_row = math.min(target_row, curr_row + pitch_range)
        end

        if curr_row == target_row and not target_range and backup_target_row then
            target_row = pitch_range
        end

        -- Set active note row to set center of vertical zoom
        reaper.MIDIEditor_SetSetting_int(hwnd, setting, curr_row)
        row_string = row_string .. ' -> ' .. curr_row

        if zoom_in_cnt > 0 then
            -- Cmd: Zoom out vertically
            reaper.MIDIEditor_OnCommand(hwnd, 40112)
            zoom_string = zoom_string .. ' -> out'
            zoom_in_cnt = zoom_in_cnt - 1
        else
            -- Cmd: Zoom in vertically
            reaper.MIDIEditor_OnCommand(hwnd, 40111)
            zoom_string = zoom_string .. ' -> in'
            zoom_in_cnt = zoom_in_cnt + 1
        end
        i = i + 1
    until i == 50 or curr_row == target_row and zoom_in_cnt == 0 and i > 2

    print('Target row:' .. target_row)
    print('Target range:' .. tostring(target_range))
    print(row_string)
    print(zoom_string)
    local _, zoom_cnt = zoom_string:gsub(' %-', '')
    print('Vertically zooming ' .. zoom_cnt .. ' times')

    -- Reset previous active note row
    if active_row and active_row ~= '' then
        reaper.MIDIEditor_SetSetting_int(hwnd, setting, active_row)
    end
end

--------------------------------- CODE START -----------------------------------

local start_time = reaper.time_precise()
local _, _, _, cmd, rel, res, val = reaper.get_action_context()
local extname = 'FTC.MeMagic_' .. cmd

reaper.Undo_BeginBlock()

-- Check if SWS extension installed
if not reaper.SNM_GetIntConfigVar then
    reaper.MB('Please install SWS extension', mb_title, 0)
    reaper.Undo_EndBlock(undo_name, -1)
    return
end

local config = reaper.SNM_GetIntConfigVar('midieditor', 0)
local editor_type = config % 4

-- Force setting: One MIDI editor per project
if not use_toolbar_context_only and editor_type ~= 1 then
    local msg =
        'This script requires the setting: One MIDI editor per project\z
    \n\nChange settings now?'
    local ret = reaper.MB(msg, mb_title, 4)
    if ret == 6 then
        config = config - editor_type + 1
        reaper.SNM_SetIntConfigVar('midieditor', config)
    else
        reaper.Undo_EndBlock(undo_name, -1)
        return
    end
end

local play_state = reaper.GetPlayState()
local hwnd = reaper.MIDIEditor_GetActive()
local editor_take = reaper.MIDIEditor_GetTake(hwnd)
local is_valid_take = reaper.ValidatePtr(editor_take, 'MediaItem_Take*')
local editor_item = is_valid_take and reaper.GetMediaItemTake_Item(editor_take)
local window, segment, details = reaper.BR_GetMouseCursorContext()
local _, _, note_row = reaper.BR_GetMouseCursorContext_MIDI()
local is_hotkey = not (rel == -1 and res == -1 and val == -1)

local timestamp = tonumber(reaper.GetExtState(extname, 'timestamp'))
local exec_time = tonumber(reaper.GetExtState(extname, 'exec_time'))

local click_mode = 0
local context = -1

local hzoom_mode
local vzoom_mode
local sel_item
local cursor_pos

-- Handle mouse modifiers
if window == 'arrange' and not is_hotkey then
    click_mode = getClickMode(cmd)
    if click_mode == 0 then
        -- This should only happen on item edges
        print('No mouse modifer found. Exiting')
        reaper.Undo_EndBlock(undo_name, -1)
        return
    end
    if click_mode == 3 then
        -- When script is used as both single and double click, use time interval
        -- to determine mode
        click_mode = timestamp and start_time - timestamp < 0.3 and 2 or 1
    end
end

if false and timestamp then
    reaper.SetExtState(extname, 'timespan', start_time - timestamp, false)
    if exec_time then
        local min_time = timestamp + exec_time * 4
        if start_time < min_time and click_mode ~= 2 then
            print('Previous script still running. Exiting')
            reaper.Undo_EndBlock(undo_name, -1)
            return
        end
    end
end
reaper.SetExtState(extname, 'timestamp', start_time, false)

if debug then
    reaper.ClearConsole()
end

if not use_toolbar_context_only and window == 'midi_editor' then
    -- Context: MIDI editor note area
    if segment == 'notes' then
        context = 20
    end
    -- Context: MIDI editor piano pane
    if segment == 'piano' then
        context = 21
    end
    -- Context: MIDI editor ruler
    if segment == 'ruler' then
        context = 22
    end
    -- Context: MIDI editor CC lanes
    if segment == 'cc_lane' then
        context = 23
    end
end

-- Context: Arrange view area
if window == 'arrange' then
    context = 10
end

if not is_hotkey then
    -- Context: Toolbar button
    if window == 'unknown' or segment == 'unknown' then
        context = 0
    end
    if window == 'arrange' then
        -- Context: Arrange view item single click (mouse modifier)
        if click_mode == 1 then
            context = 30
        end
        -- Context: Arrange view item double click (mouse modifier)
        if click_mode == 2 then
            context = 31
        end
    end
end

-- Non-Contextual mode
if use_toolbar_context_only then
    context = 0
end

if context == -1 then
    print('Unkown context. Exiting.')
    reaper.Undo_EndBlock(undo_name, -1)
    return
end

if window == 'arrange' and (context > 0 or click_mode > 0) then
    if set_edit_cursor and (play_state == 0 or not use_play_cursor) then
        -- Cmd: Move edit cursor to mouse cursor
        reaper.Main_OnCommand(40513, 0)
    end
    local sel_item_cnt = reaper.CountSelectedMediaItems(0)
    -- Cmd: Select item under mouse cursor (leaving other items selected)
    reaper.Main_OnCommand(40529, 0)

    if sel_item_cnt > 1 or sel_item_cnt ~= reaper.CountSelectedMediaItems(0) then
        -- Cmd: Select item under mouse cursor
        reaper.Main_OnCommand(40528, 0)
    end
    sel_item = reaper.GetSelectedMediaItem(0, 0)

    if sel_item then
        local take = reaper.GetActiveTake(sel_item)
        -- Handle empty take lanes
        if not reaper.ValidatePtr(take, 'MediaItem_Take*') then
            print('Take is an empty take lane')
            reaper.Undo_EndBlock(undo_name, -1)
            return
        end
        -- Handle non-MIDI takes
        if not reaper.TakeIsMIDI(take) then
            if click_mode == 2 then
                local source = reaper.GetMediaItemTake_Source(take)
                local file_name = reaper.GetMediaSourceFileName(source, '')
                local video_extensions = {'mp4', 'gif'}
                for _, extension in ipairs(video_extensions) do
                    if file_name:lower():match('[^.]+$') == extension then
                        local is_video_visible = reaper.GetToggleCommandState(50125) == 1
                        if not is_video_visible then
                            reaper.Main_OnCommand(50125, 0)
                            reaper.Undo_EndBlock(undo_name, -1)
                            return
                        end
                    end
                end
                local _, chunk = reaper.GetItemStateChunk(sel_item, '', true)
                local is_subproject = chunk:match('SOURCE RPP_PROJECT')
                if is_subproject then
                    -- Cmd: Open associated project in new tab
                    reaper.Main_OnCommand(41816, 0)
                    undo_name = 'Item: Open associated project in new tab'
                else
                    -- Cmd: Show media item/take properties
                    reaper.Main_OnCommand(40009, 0)
                    undo_name = 'Show media item/take properties'
                end
            end
            reaper.Undo_EndBlock(undo_name, -1)
            return
        end
    end
end

-- Quit when single click mouse modifier and editor is closed
if context == 30 and not hwnd then
    print('No editor open. Exiting')
    reaper.Undo_EndBlock(undo_name, -1)
    return
end

if context == 20 or context == 22 or context == 23 then
    if set_edit_cursor and (play_state == 0 or not use_play_cursor) then
        -- Cmd: Move edit cursor to mouse cursor
        reaper.MIDIEditor_OnCommand(hwnd, 40443)
    end
    -- Select closest item to cursor
    if editor_item then
        local getItemInfoValue = reaper.GetMediaItemInfo_Value
        local item_length = getItemInfoValue(editor_item, 'D_LENGTH')
        local item_start_pos = getItemInfoValue(editor_item, 'D_POSITION')
        local item_end_pos = item_start_pos + item_length
        local editor_track = reaper.GetMediaItem_Track(editor_item)
        cursor_pos = getCursorPosition(play_state)
        -- Check for other items on the same track
        if cursor_pos < item_start_pos then
            for i = 0, reaper.CountTrackMediaItems(editor_track) - 1 do
                local item = reaper.GetTrackMediaItem(editor_track, i)
                local length = getItemInfoValue(item, 'D_LENGTH')
                local start_pos = getItemInfoValue(item, 'D_POSITION')
                local end_pos = start_pos + length
                if cursor_pos < end_pos then
                    if item ~= editor_item then
                        sel_item = item
                        setOnlyItemSelected(sel_item)
                    end
                    break
                end
            end
        end
        if cursor_pos > item_end_pos then
            for i = reaper.CountTrackMediaItems(editor_track) - 1, 0, -1 do
                local item = reaper.GetTrackMediaItem(editor_track, i)
                local start_pos = getItemInfoValue(item, 'D_POSITION')
                if cursor_pos > start_pos then
                    if item ~= editor_item then
                        sel_item = item
                        setOnlyItemSelected(sel_item)
                    end
                    break
                end
            end
        end
    end
end

if not is_valid_take and not sel_item then
    print('No editor item found. Exiting')
    reaper.Undo_EndBlock(undo_name, -1)
    return
end

cursor_pos = cursor_pos or getCursorPosition(play_state)

local hlength, hcenter
local prev_hzoom_lvl = tonumber(reaper.GetExtState(extname, 'hzoom_lvl'))

if sel_item and editor_take ~= reaper.GetActiveTake(sel_item) or click_mode > 0 then
    print('Opening selected item in editor')
    local cfg_edit
    if is_valid_take then
        local chunk = select(2, reaper.GetItemStateChunk(editor_item, '', true))
        local cfg_edit_view = getItemChunkConfig(editor_item, chunk, 'CFGEDITVIEW')
        cfg_edit = getItemChunkConfig(editor_item, chunk, 'CFGEDIT')
        -- Check editor length in case reaper will change zoom level
        local hzoom_lvl = getConfigHZoom(cfg_edit_view)
        if hzoom_lvl ~= prev_hzoom_lvl then
            print('Getting horizontal editor length')
            local timebase = getEditorTimeBase()
            prev_hzoom_lvl = hzoom_lvl
            hlength, hcenter = getHorizontalEditorLength(hwnd, editor_item, timebase)
        end
    end
  


    -- Cmd: Open in built-in MIDI editor
    reaper.Main_OnCommand(40153, 0)
    hwnd = reaper.MIDIEditor_GetActive()
    editor_take = reaper.GetActiveTake(sel_item)
    editor_item = sel_item

    if cfg_edit then
        -- Sometimes editor modes are not kept. This fixes this issue
        local item_mode = getConfigMode(cfg_edit)
        setMode(hwnd, item_mode)
    end
end

local track = reaper.GetMediaItem_Track(editor_item)
local item_length = reaper.GetMediaItemInfo_Value(editor_item, 'D_LENGTH')
local item_start_pos = reaper.GetMediaItemInfo_Value(editor_item, 'D_POSITION')
local item_end_pos = item_start_pos + item_length

local timebase = getEditorTimeBase()

if timebase == 2 then
    if window == 'arrange' then
        cursor_pos = getRelativeSourcePos(editor_take, cursor_pos)
    end
    local source_ppq_length = getSourcePPQLength(editor_take)
    item_start_pos = reaper.MIDI_GetProjTimeFromPPQPos(editor_take, 0)
    item_end_pos = reaper.MIDI_GetProjTimeFromPPQPos(editor_take, source_ppq_length)
    item_length = item_end_pos - item_start_pos
end
local is_cursor_inside_item = cursor_pos >= item_start_pos and cursor_pos <= item_end_pos

----------------------------------- ZOOM MODES ---------------------------------------

local hzoom_mode, vzoom_mode = getZoomMode(context, timebase)

local prev_note_row, prev_note_lo, prev_note_hi
local timespan = tonumber(reaper.GetExtState(extname, 'timespan'))

if timespan and timespan < 0.25 then
    print('Fast mode: Preloading settings')
    prev_note_row = tonumber(reaper.GetExtState(extname, 'note_row'))
    prev_note_lo = tonumber(reaper.GetExtState(extname, 'note_lo'))
    prev_note_hi = tonumber(reaper.GetExtState(extname, 'note_hi'))
    hlength = tonumber(reaper.GetExtState(extname, 'hlength'))
    hcenter = tonumber(reaper.GetExtState(extname, 'hcenter'))

    -- Make horizontal movements smoother
    if hcenter and cursor_pos >= 0 and context >= 20 and context < 30 then
        local cursor_diff = cursor_pos - hcenter
        local factor = math.abs(cursor_diff / hlength * 2)
        cursor_pos = hcenter + cursor_diff * factor
        if hzoom_mode ~= 1 then
            hcenter = cursor_pos
        end
    end

    -- Make vertical movements smoother
    if prev_note_row and prev_note_row >= 0 then
        local row_diff = note_row - prev_note_row
        local row_diff_abs = math.abs(row_diff)
        if row_diff_abs > 1 then
            local sign = row_diff / row_diff_abs
            note_row = prev_note_row + sign * math.floor(row_diff_abs ^ 0.5)
        end
    end
end

if not vzoom_mode or not hzoom_mode then
    print('Invalid mode. Exiting')
    reaper.Undo_EndBlock(undo_name, -1)
    return
end

local is_smart_zoom_mode = hzoom_mode == 5 or hzoom_mode == 6
local hzoom_lvl = getItemHZoom(editor_item)

if not hlength or not hcenter or prev_hzoom_lvl ~= hzoom_lvl and not is_smart_zoom_mode then
    print('Getting horizontal editor length')
    hlength, hcenter = getHorizontalEditorLength(hwnd, editor_item, timebase)
end

if is_hotkey and is_smart_zoom_mode and not is_cursor_inside_item then
    -- TODO find a better solution
    vzoom_mode = 1
    hzoom_mode = 7
end

reaper.SetExtState(extname, 'hzoom_lvl', hzoom_lvl, false)
reaper.SetExtState(extname, 'hlength', hlength, false)
reaper.SetExtState(extname, 'hcenter', hcenter, false)

-------------------------------- HORIZONTAL ZOOM RANGE ----------------------------------

local zoom_start_pos, zoom_end_pos

if hzoom_mode == 1 then
    zoom_start_pos = hcenter - hlength / 2
    zoom_end_pos = hcenter + hlength / 2
end

if hzoom_mode == 2 then
    zoom_start_pos = item_start_pos
    zoom_end_pos = item_end_pos
end

-- Set zoom to number of measures
if hzoom_mode == 3 or hzoom_mode == 4 then
    local convQNToTime = reaper.TimeMap2_QNToTime
    local sig_num = reaper.TimeMap_GetTimeSigAtTime(0, cursor_pos)
    local cursor_qn = reaper.TimeMap2_timeToQN(0, cursor_pos)
    zoom_start_pos = convQNToTime(0, cursor_qn - sig_num * number_of_measures / 2)
    zoom_end_pos = convQNToTime(0, cursor_qn + sig_num * number_of_measures / 2)
end

-- Set zoom to number of notes
if hzoom_mode == 5 or hzoom_mode == 6 then
    local zoom_ppq_length =
        getSmartZoomRange(editor_take, cursor_pos, item_start_pos, item_end_pos)
    if zoom_ppq_length then
        local cursor_ppq_pos = reaper.MIDI_GetPPQPosFromProjTime(editor_take, cursor_pos)
        local getTimeFromPPQ = reaper.MIDI_GetProjTimeFromPPQPos
        zoom_start_pos = getTimeFromPPQ(editor_take, cursor_ppq_pos - zoom_ppq_length / 2)
        zoom_end_pos = getTimeFromPPQ(editor_take, cursor_ppq_pos + zoom_ppq_length / 2)
    else
        zoom_start_pos = item_start_pos
        zoom_end_pos = item_end_pos
    end
end

if hzoom_mode == 7 then
    zoom_start_pos = cursor_pos - hlength / 2
    zoom_end_pos = cursor_pos + hlength / 2
end

------------------------- HORIZONTAL ZOOM RANGE RESTRICTION ---------------------------

local zoom_length = zoom_end_pos - zoom_start_pos

-- Edge case: Zoom start is below zero
if zoom_start_pos < 0 then
    zoom_start_pos = 0
    zoom_end_pos = zoom_length
end

-- Edge case: Zoom start is below item start in timebase source beats
if timebase == 2 and zoom_start_pos < item_start_pos then
    zoom_start_pos = item_start_pos
    zoom_end_pos = zoom_start_pos + zoom_length
end

-- Restrict zoom to item edges based on mode
if hzoom_mode == 4 or hzoom_mode == 6 then
    if zoom_length < item_length then
        if zoom_start_pos < item_start_pos then
            zoom_start_pos = item_start_pos
            zoom_end_pos = zoom_start_pos + zoom_length
        end
        if zoom_end_pos > item_end_pos then
            zoom_start_pos = item_end_pos - zoom_length
            zoom_end_pos = item_end_pos
        end
    else
        zoom_start_pos = item_start_pos
        zoom_end_pos = item_end_pos
    end
end

----------------------------------- VERTICAL ZOOM -----------------------------------

local are_notes_hidden = reaper.GetToggleCommandStateEx(32060, 40452) ~= 1
local is_notation = reaper.GetToggleCommandStateEx(32060, 40954) == 1

-- Analyze take pitch in the given area. Find highest and lowest pitch
if vzoom_mode > 0 and not is_notation then
    -- Note: Visible zoom area is larger than project loop selection by a certain factor
    local factor = timebase == 2 and 0.015 or 0.03
    local start_pos = zoom_start_pos - zoom_length * factor
    local end_pos = zoom_end_pos + zoom_length * factor

    if vzoom_mode == 3 or vzoom_mode > 4 and vzoom_mode % 2 == 0 then
        start_pos = item_start_pos
        end_pos = item_end_pos
    end

    local note_lo, note_hi, note_density =
        getPitchRange(editor_take, start_pos, end_pos, item_start_pos, item_end_pos)

    if are_notes_hidden then
        print('Notes are hidden. Zooming to content')
        -- Cmd: Zoom to content
        reaper.MIDIEditor_OnCommand(hwnd, 40466)
    else
        if vzoom_mode >= 2 and vzoom_mode <= 3 then
            if note_hi == -1 then
                print('No note in area/take: Setting base note')
                note_lo, note_hi = base_note, base_note
            end

            if note_hi - note_lo < min_vertical_notes then
                print('Using minimum pitch range')
                note_hi = math.ceil((note_lo + note_hi + min_vertical_notes) / 2)
                note_lo = math.floor((note_lo + note_hi - min_vertical_notes) / 2)
                note_lo = note_hi < 127 and note_lo or 127
                note_hi = note_hi < 127 and note_hi or 127 - min_vertical_notes
            end

            if prev_note_lo ~= note_lo or prev_note_hi ~= note_hi then
                print('Vertically zooming to notes ' .. note_lo .. ' - ' .. note_hi)
                zoomToPitchRange(hwnd, editor_item, note_lo - 1, note_hi + 1)
            end
        end
        if vzoom_mode >= 4 and vzoom_mode <= 12 then
            if vzoom_mode == 4 or note_hi == -1 then
                note_lo, note_hi = 0, 127
            end

            if vzoom_mode >= 7 and vzoom_mode <= 8 then
                note_density = note_density or (note_lo + note_hi) / 2
                note_row = math.floor(note_density)
            end

            if vzoom_mode >= 9 and vzoom_mode <= 10 then
                note_row = 0
            end

            if vzoom_mode >= 11 and vzoom_mode <= 12 then
                note_row = 127
            end

            if note_row and note_row >= 0 then
                local scroll_changed = prev_note_row ~= note_row
                scroll_changed = scroll_changed or prev_note_lo ~= note_lo
                scroll_changed = scroll_changed or prev_note_hi ~= note_hi
                if scroll_changed then
                    print('Vertically scrolling to note ' .. note_row)
                    print('Scroll lo/hi limit: ' .. note_lo .. '/' .. note_hi)
                    scrollToNoteRow(hwnd, editor_item, note_row, note_lo - 1, note_hi + 1)
                end
            end
        end
    end
    reaper.SetExtState(extname, 'note_row', note_row, false)
    reaper.SetExtState(extname, 'note_lo', note_lo, false)
    reaper.SetExtState(extname, 'note_hi', note_hi, false)
end

---------------------------------- HORIZONTAL ZOOM ----------------------------------

-- Get previous time selection
local sel = getSelection()
reaper.PreventUIRefresh(1)

setSelection(zoom_start_pos, zoom_end_pos)
-- Cmd: Zoom to project loop selection
reaper.MIDIEditor_OnCommand(hwnd, 40726)

-- Reset previous time selection
local sel_start_pos = sel and sel.start_pos or 0
local sel_end_pos = sel and sel.end_pos or 0
if not debug then
    setSelection(sel_start_pos, sel_end_pos)
end

reaper.PreventUIRefresh(-1)

local exec_time = reaper.time_precise() - start_time
print('\nExecution time: ' .. math.floor(exec_time * 1000 + 0.5) .. ' ms')
reaper.SetExtState(extname, 'exec_time', exec_time, false)

if click_mode == 1 then
    reaper.SetCursorContext(1, 0)
end
reaper.Undo_EndBlock(undo_name, -1)
ovnis is offline   Reply With Quote
Old 02-24-2023, 10:04 AM   #329
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Just pushed the first MeMagic update in a while:
  • Added 16 new bundle scripts that zoom to a smart number of measures (they analyze MIDI content and zoom to 1,2,4,8... measures)
  • Support "MIDI editor per track/item" when JS_ReaScriptAPI is installed (experimental)
  • Various small bug fixes/improvements & code cleanup
I hadn't touched this code for a while, so let me know if I broke something
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 02-26-2023, 11:51 AM   #330
Hipox
Human being with feelings
 
Join Date: Apr 2022
Posts: 204
Default

I have some troubles with 'FTC_Multi edit zoom.lua' .
I would like to use it on double click mouse action, but it doesn't work as described, see below:

second behaviour that's suspicious to me:

one more while trying to zoom on audio items with the script:
https://imgur.com/a/2bQW8ex

Last edited by Hipox; 02-26-2023 at 12:30 PM.
Hipox is offline   Reply With Quote
Old 02-26-2023, 02:22 PM   #331
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by Hipox View Post
I have some troubles with 'FTC_Multi edit zoom.lua' .
I would like to use it on double click mouse action, but it doesn't work as described, see below:
Hmmm, that behavior must have broken at some point... The script used undo to reselect previous items, so it might actually be a good thing that it broke Wasn't a good solution anyway and I think I have a better one, let's see if it pans out.
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-02-2023, 08:38 AM   #332
Hipox
Human being with feelings
 
Join Date: Apr 2022
Posts: 204
Default

Quote:
Originally Posted by FeedTheCat View Post
Hmmm, that behavior must have broken at some point... The script used undo to reselect previous items, so it might actually be a good thing that it broke Wasn't a good solution anyway and I think I have a better one, let's see if it pans out.
Oh, well, I can't think of a better solution. It's weird that selected items get deselected on double click, same if we double click a track.

EDIT: hmm, it seems like it could be solved by setting left mouse click in Media Item context to another. For example, I prefer to have mouse modifier for Media Item & Left Click set on 'Select item and move edit cursor ignoring snap'. With this setting, executed script on double click registers only one selected item - which indicates that on double left click first gets triggered action for left click and then the double click action. Honestly, that is not very smart, maybe even a bug?

After setting mouse modifier for Media Item & Left Click set on 'Add items to selection' my script placed on Double Click action registers all selected items (I used function reaper.CountSelectedMediaItems(0) to test this behaviour).
So, saving preferences for mouse modifiers, changing it and then restoring back could solve this problem.

EDIT2: I tested it out, but I forgot that the single click action executes before double click gets executed, so setting it to another action is useless during execution of double click. Sorry for my confusion. I'm pretty sure you already thought of this possibility.

EDIT3: I tried to solve it with your existing scripts and made a mashup that quite works. There's only one problem. I can not set Single Left Click for Media Items to whatever action I want. It's stuck on '2 m' action, which is 'Select Items: just select' (selects item and moves edit cursor).
In 'reaper-mouse.ini' are contexts which I don't understand the difference between: 'MM_CTX_ITEM' and 'MM_CTX_ITEM_CLK'. Custom actions are written into the second one, but changing the first one to anything else, I did not get any difference in behaviour.

Basically, you get two scripts, one is for double click action, second is for single left click. Assign them in mouse modifiers settings.
Double click action only creates timestamp and everything is processed in the single click action.

Be aware that you have to edit script and before running it (just to tell it what Command ID has your FTC_Multi edit zoom).

One more thing - after this 'enhancement' I do have no need to use part of your code that checks if script is triggered by mouse, so I commented out lines (might be a bit offsetted) from 205 to 221, resp. starts with line 'local window = reaper.BR_GetMouseCursorContext()' and ends with 'end' (obviously).
Also, you might want to set the script to terminate when detected running instance while launching a new one.
Here is a demonstration:


Last edited by Hipox; 03-02-2023 at 01:50 PM.
Hipox is offline   Reply With Quote
Old 03-03-2023, 05:32 AM   #333
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

@Hipox

Sry, I completely missed your edits (no notifications for edits). Just pushed an update to FTC_Multi edit scroll. The solution I came up with is probably similar to what you did. If you don't want the edit cursor to snap to grid there's a setting inside the new script for that.
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi

Last edited by FeedTheCat; 03-03-2023 at 05:59 AM.
FeedTheCat is online now   Reply With Quote
Old 03-03-2023, 05:48 AM   #334
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Hi guys,

I completely reworked the Multi-Edit scroll script. If everything works as expected I'll port the changes to Multi-Edit zoom.

Multi edit scroll will now (hopefully) work reliably as a double click mouse modifier to allow you to edit multiple selected items. No more weird behavior caused by the undo hack.

What you need to know:
  • When the script is set as a double click mouse modifier it will also set itself for single clicks (it will ask). E.g. if you set it to "Shift+Double click" it will also need to set itself to "Shift+Left click".
  • Important! When the ReaScript task control asks whether to terminate the running instance click "New instance"! If you clicked wrong, uninstall, then reinstall the script. And then go bump this FR...
  • There's new settings inside the script to influence horizontal zoom behavior. E.g. you can disable zooming completely or zoom only when multiple items are selected.

P.S: If you don't usually open item properties with double click, give the "zoom_to_audio_items" setting a spin:

__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi

Last edited by FeedTheCat; 03-03-2023 at 06:07 AM.
FeedTheCat is online now   Reply With Quote
Old 03-05-2023, 03:25 AM   #335
_Stevie_
Human being with feelings
 
_Stevie_'s Avatar
 
Join Date: Oct 2017
Location: Black Forest
Posts: 5,066
Default

Concerning the "Multi edit scroll" script, is it possible to get rid of that short white flickering when executing the script?
__________________
My Reascripts forum thread | My Reascripts on GitHub
If you like or use my scripts, please support the Ukraine: Ukraine Crisis Relief Fund | DirectRelief | Save The Children | Razom
_Stevie_ is offline   Reply With Quote
Old 03-05-2023, 07:31 AM   #336
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by _Stevie_ View Post
Concerning the "Multi edit scroll" script, is it possible to get rid of that short white flickering when executing the script?
Did you try out the update? I went to check out flickering on Windows and realized the script doesn't work there (or MacOS), uups There's a few things that work different depending on the platform, sigh...

I think the flickering should be better than the previous version in general, not sure if I remember correctly though. (Might be the same actually)

Here are two ideas:

1. There doesn't need to be any flickering if I change the selection behavior. If you have multiple items selected and click one of them, it will always keep everything selected (double click or single click). While this will work and is simple to add, I'm not sure it's desirable as a workflow.

2. I can delay the selection change caused by single click a bit using defer. This will remove flickering for the most part, but there will be a balance between the flickering being annoying and the delay being annoying. Think I'll give this one a shot. 100ms delay won't be noticeable for the most part, but will remove double click flicker in most cases.
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-05-2023, 08:10 AM   #337
_Stevie_
Human being with feelings
 
_Stevie_'s Avatar
 
Join Date: Oct 2017
Location: Black Forest
Posts: 5,066
Default

Ah let me explain. I'm talking about that short white flickering when opening the ME with the script. There is no flickering, when actually executing the script while the ME is open.

I am experiencing some strange ME slow downs for quite a while now, in REAPER.
And I'm investigating in all directions right now (here's the thread in case you want to check: https://forums.cockos.com/showthread...11#post2655411), because I got Justin's attention.
I'm exclusively opening the ME with the "FTC Multi edit scroll".

The white flicker can be seen here and gets worse (longer) by the time I open the ME: https://nextcloud.stephanroemer.net/...4bF4sresLcfybS

And I'm wondering if there could be anything going on in that script that would trigger a resource leak in REAPER? The white flicker might only be a sign that there's something that makes the ME start slower.

I have quickly checked the new version of the script, but the flicker still appears.
__________________
My Reascripts forum thread | My Reascripts on GitHub
If you like or use my scripts, please support the Ukraine: Ukraine Crisis Relief Fund | DirectRelief | Save The Children | Razom
_Stevie_ is offline   Reply With Quote
Old 03-05-2023, 08:21 AM   #338
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by _Stevie_ View Post
Ah let me explain. I'm talking about that short white flickering when opening the ME with the script. There is no flickering, when actually executing the script while the ME is open.

I am experiencing some strange ME slow downs for quite a while now, in REAPER.
And I'm investigating in all directions right now (here's the thread in case you want to check: https://forums.cockos.com/showthread...11#post2655411), because I got Justin's attention.
I'm exclusively opening the ME with the "FTC Multi edit scroll".

The white flicker can be seen here and gets worse (longer) by the time I open the ME: https://nextcloud.stephanroemer.net/...4bF4sresLcfybS

And I'm wondering if there could be anything going on in that script that would trigger a resource leak in REAPER? The white flicker might only be a sign that there's something that makes the ME start slower.

I have quickly checked the new version of the script, but the flicker still appears.
So you're opening the script via mouse modifier, right? Or keyboard shortcut?

The script could be causing memory leaks if the SWS functions do so (SNM_SetIntConfigVar etc.). Definitely try without the script and check if that's the issue.
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-05-2023, 08:25 AM   #339
_Stevie_
Human being with feelings
 
_Stevie_'s Avatar
 
Join Date: Oct 2017
Location: Black Forest
Posts: 5,066
Default

Quote:
Originally Posted by FeedTheCat View Post
So you're opening the script via mouse modifier, right? Or keyboard shortcut?

The script could be causing memory leaks if the SWS functions do so (SNM_SetIntConfigVar etc.). Definitely try without the script and check if that's the issue.
Thanks FTC, that's some valuable info there.
I actually have it assigned to both, MM and Keyboard.

Right now, it seems stable to keep the ME open and only click in the arrange to select the item I want to edit. WIll investigate further.

IF it is SNM_SetIntConfigVar... What do you think, would it be possible to mimic that behavior in one go by creating a script and changing the same value in a loop a 1000 times and simulate that leak behavior?
__________________
My Reascripts forum thread | My Reascripts on GitHub
If you like or use my scripts, please support the Ukraine: Ukraine Crisis Relief Fund | DirectRelief | Save The Children | Razom
_Stevie_ is offline   Reply With Quote
Old 03-05-2023, 08:52 AM   #340
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by _Stevie_ View Post
Right now, it seems stable to keep the ME open and only click in the arrange to select the item I want to edit. WIll investigate further.
What's stable, the flickering?

Quote:
Originally Posted by _Stevie_ View Post
IF it is SNM_SetIntConfigVar... What do you think, would it be possible to mimic that behavior in one go by creating a script and changing the same value in a loop a 1000 times and simulate that leak behavior?
Yeah, I assume that would work. Btw, the memory leak could also be caused by a native action, it's just that SWS is more likely.

I'm using two SWS functions SNM_SetIntConfigVar and BR_GetMouseCursorContext. I'd suspect the second one. (Hmm, you probably can remove BR_GetMouseCursorContext along with the window == 'arrange' check in the next line. The script should keep working just fine)
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-05-2023, 08:54 AM   #341
_Stevie_
Human being with feelings
 
_Stevie_'s Avatar
 
Join Date: Oct 2017
Location: Black Forest
Posts: 5,066
Default

Quote:
Originally Posted by FeedTheCat View Post
What's stable, the flickering?
Actually the whole performance of the ME. The flickering doesn't show, because I keep the ME open


Quote:
Originally Posted by FeedTheCat View Post
Yeah, I assume that would work. Btw, the memory leak could also be caused by a native action, it's just that SWS is more likely.

I'm using two SWS functions SNM_SetIntConfigVar and BR_GetMouseCursorContext. I'd suspect the second one. (Hmm, you probably can remove BR_GetMouseCursorContext along with the window == 'arrange' check in the next line. The script should keep working just fine)
Okay, thanks, I will try that and report back!
__________________
My Reascripts forum thread | My Reascripts on GitHub
If you like or use my scripts, please support the Ukraine: Ukraine Crisis Relief Fund | DirectRelief | Save The Children | Razom
_Stevie_ is offline   Reply With Quote
Old 03-05-2023, 09:22 AM   #342
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Just uploaded v1.2.2

Now certain selection changes are delayed which improves flickering (with double click mouse modifier).

@Stevie
I also removed BR_GetMouseCursorContext
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-05-2023, 09:45 AM   #343
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Uups... v1.2.2 had a wrong default setting enabled (wouldn't keep items selected).

v1.2.3 is online.
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-05-2023, 03:10 PM   #344
Hipox
Human being with feelings
 
Join Date: Apr 2022
Posts: 204
Default

Quote:
Originally Posted by FeedTheCat View Post
Uups... v1.2.2 had a wrong default setting enabled (wouldn't keep items selected).

v1.2.3 is online.
Works great for me no noticeable flickering on my Windows 11 machine.
Hipox is offline   Reply With Quote
Old 03-07-2023, 07:59 AM   #345
YuriOl
Human being with feelings
 
Join Date: Sep 2018
Location: lugansk
Posts: 153
Default

Great scripts!
Added button - Script: FTC_Multi edit scroll.lua to midi editor toolbar, but it doesn't work.
It works in midi editor if run from a hotkey or from the Actions window, but it doesn't work from the midi toolbar.
Can I somehow fix this?
YuriOl is offline   Reply With Quote
Old 03-07-2023, 08:19 AM   #346
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by YuriOl View Post
Great scripts!
Added button - Script: FTC_Multi edit scroll.lua to midi editor toolbar, but it doesn't work.
It works in midi editor if run from a hotkey or from the Actions window, but it doesn't work from the midi toolbar.
Can I somehow fix this?
Hmmm, was working on the item double click behavior so much that maybe I broke something. Is that on MacOS or Windows? (on Linux it works in the MIDI editor toolbar)
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-07-2023, 10:00 AM   #347
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Nvm, I know what broke it.

It was this:
Quote:
Originally Posted by FeedTheCat View Post
@Stevie
I also removed BR_GetMouseCursorContext
1.2.5 is online. I also added the script to the MIDI editor section by default.
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-07-2023, 05:29 PM   #348
YuriOl
Human being with feelings
 
Join Date: Sep 2018
Location: lugansk
Posts: 153
Default

Quote:
Originally Posted by FeedTheCat View Post
Nvm, I know what broke it.

It was this:


1.2.5 is online. I also added the script to the MIDI editor section by default.
Thank you
Now everything works!
YuriOl is offline   Reply With Quote
Old 03-08-2023, 06:39 AM   #349
sockmonkey72
Human being with feelings
 
sockmonkey72's Avatar
 
Join Date: Sep 2021
Location: Berlin
Posts: 1,957
Default

Hey FTC,

I realize this is in "bite the hand that feeds you" territory, AND I wonder something: I use exactly ONE script, "FTC_MeMagic (1-2) Vertically zoom to notes in visible area", and I want it to remain up-to-date, but I don't want 75(! did I count correctly?) scripts polluting all of my Main and MIDI namespaces and complicating my ability to search in the Actions window.

Are you aware of any way to slim this down without losing the ability to get updates as they are available? Barring that, which scripts do I actually need to satisfy the dependencies of the script mentioned above so I can just batch delete it all whenever an update arrives and repopulates the Actions list?

Thanks, also for entertaining my luxury complaints...
__________________
ReaPack Repository: right-click and copy index URL

Last edited by sockmonkey72; 03-08-2023 at 06:49 AM.
sockmonkey72 is online now   Reply With Quote
Old 03-08-2023, 08:37 AM   #350
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by sockmonkey72 View Post
Hey FTC,

I realize this is in "bite the hand that feeds you" territory, AND I wonder something: I use exactly ONE script, "FTC_MeMagic (1-2) Vertically zoom to notes in visible area", and I want it to remain up-to-date, but I don't want 75(! did I count correctly?) scripts polluting all of my Main and MIDI namespaces and complicating my ability to search in the Actions window.
That's a completely fair request... I also don't like polluting my actions list with scripts I don't use (can't understand the people that install complete repositories). And I also only use a couple of MeMagic scripts.

Quote:
Originally Posted by sockmonkey72 View Post
Are you aware of any way to slim this down without losing the ability to get updates as they are available? Barring that, which scripts do I actually need to satisfy the dependencies of the script mentioned above so I can just batch delete it all whenever an update arrives and repopulates the Actions list?

Thanks, also for entertaining my luxury complaints...
I published this as a bundle which in hindsight wasn't the best idea. Maybe I'll convert the bundle scripts to individual ReaPack packages. I need to check if/how that's possible without annoying people that have the bundle installed...

There are no dependencies though, the scripts are generated and each one contains the full code. So for now you can safely remove all the ones you're not using.
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-10-2023, 05:10 PM   #351
_Stevie_
Human being with feelings
 
_Stevie_'s Avatar
 
Join Date: Oct 2017
Location: Black Forest
Posts: 5,066
Default

JFYI: the script has nothing to do with the slow down. All good!
Still investigating what else it could be...
__________________
My Reascripts forum thread | My Reascripts on GitHub
If you like or use my scripts, please support the Ukraine: Ukraine Crisis Relief Fund | DirectRelief | Save The Children | Razom
_Stevie_ is offline   Reply With Quote
Old 03-23-2023, 10:14 PM   #352
YuriOl
Human being with feelings
 
Join Date: Sep 2018
Location: lugansk
Posts: 153
Default

FeedTheCat, Thanks again for the great scripts!
It has become much more convenient to work with the MIDI Editor.
YuriOl is offline   Reply With Quote
Old 03-27-2023, 09:49 AM   #353
daeavelwyn
Human being with feelings
 
daeavelwyn's Avatar
 
Join Date: Dec 2014
Posts: 600
Default

Hello FTC,

I'm trying to optimize my workflow using your script and I'd like to known if some behaviour can be acheived.

I'm using MIDI editor in a separate window. When I select multiple tracks with a midi item on each, I can open every items in the windowed midi editor with your multi-zoom script (I use "w" shortcut) to open the midi editor with your script once I selected futher tracks.

For example, I select all my brass instruments and hit "w" and it opens the midi editor showing every items.

This work very well, thanks a lot for that !

BUT, once the midi editor is opened, if I zoom in a portion, I can't find a way to zoom out to the "global picture" and see all my items as I previously saw them.

I would like to find a way to do this because, while dealing with orchestral sections, I need to zoom in and out of the section a lot to tweak, change stuff.

Any process/workaround/ideas about the way I could acheive this ?
daeavelwyn is offline   Reply With Quote
Old 03-28-2023, 04:41 AM   #354
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by daeavelwyn View Post
For example, I select all my brass instruments and hit "w" and it opens the midi editor showing every items.

This work very well, thanks a lot for that !

BUT, once the midi editor is opened, if I zoom in a portion, I can't find a way to zoom out to the "global picture" and see all my items as I previously saw them.

I would like to find a way to do this because, while dealing with orchestral sections, I need to zoom in and out of the section a lot to tweak, change stuff.

Any process/workaround/ideas about the way I could acheive this ?
Hmm, as long as the items stay selected you should be able to run the script again and zoom back to all items.

__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-30-2023, 06:04 PM   #355
daeavelwyn
Human being with feelings
 
daeavelwyn's Avatar
 
Join Date: Dec 2014
Posts: 600
Default

Hello FTC,

Here is an animated version of my problem :


I use "w" key to open the midi editor (a, even if I select multiple items, double clicking just open the last clicked....)

Once open, every time you see the "z" key, I try to zoom the entire 3 items. I got a weird mess you can see in the track list of the midi editor, it's like editability and visibility have a weird behaviour. I'd like them to stay enabled but they disabled.

So where am I wrong ?
daeavelwyn is offline   Reply With Quote
Old 03-31-2023, 12:54 AM   #356
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Hmm, can you send me a screenshot of your MIDI editor settings?
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-31-2023, 06:07 AM   #357
daeavelwyn
Human being with feelings
 
daeavelwyn's Avatar
 
Join Date: Dec 2014
Posts: 600
Default

Quote:
Originally Posted by FeedTheCat View Post
Hmm, can you send me a screenshot of your MIDI editor settings?
Yes, sure ! here it is :
daeavelwyn is offline   Reply With Quote
Old 03-31-2023, 07:33 AM   #358
FeedTheCat
Human being with feelings
 
FeedTheCat's Avatar
 
Join Date: May 2019
Location: Berlin
Posts: 2,198
Default

Quote:
Originally Posted by daeavelwyn View Post
Once open, every time you see the "z" key, I try to zoom the entire 3 items. I got a weird mess you can see in the track list of the midi editor, it's like editability and visibility have a weird behaviour. I'd like them to stay enabled but they disabled.
Is the behavior different when you don't run the script? The only thing that strikes me as weird (there's a lot going on in the GIF) is that when you press Z, the items don't go back to editable + visible. I can't replicate this, they do for me. Z in the editor is mapped to "multi-edit zoom" as well, right?
__________________
Featured scripts: REAPER Update UtilityLil ChordboxGridbox/Adaptive gridMX TunerRS5K LinkMIDI Editor Magic Donate💝: PayPal|ko-fi
FeedTheCat is online now   Reply With Quote
Old 03-31-2023, 08:47 AM   #359
daeavelwyn
Human being with feelings
 
daeavelwyn's Avatar
 
Join Date: Dec 2014
Posts: 600
Default

Quote:
Originally Posted by FeedTheCat View Post
Z in the editor is mapped to "multi-edit zoom" as well, right?
Oh sh**t ! that the point...it is mmaped to "Script: FTC_MeMagic (2-3) Horizontally zoom to item + Vertically zoom to all notes in item.lua".

So I uninstalled everything about your zoom tools, I went back to your first post and read carefully and found that :
Quote:
"I highly recommend trying MeMagic as the default mouse modifier for left and double click in Preferences > Editing > Mouse Modifiers > Media Item. This will make double clicks zoom to the whole item, and single clicks to a usable "smart" area at the edit cursor. "
I reinstall multi-edit zoom (whitout the memagic bundle), set the mouse modifiers as you mentioned in the first post and finaly it seems to work as expected !

So I guess I should apologize because I should have read your first post more careffuly :-/. Thanks for your patience, your help and, of course, your awesome scripts !

Last question, do you know if there is a way to keep item as editable in the track list whatever I do to selection ?
daeavelwyn is offline   Reply With Quote
Old 03-31-2023, 09:02 AM   #360
daeavelwyn
Human being with feelings
 
daeavelwyn's Avatar
 
Join Date: Dec 2014
Posts: 600
Default

ERRATUM: well, I guess I reply to quickly...

Actually I don't want the midi editor to open every time I left click on an item. In fact I try to mimic the Cubase behaviour which is pretty handy when you need to deal with midi editor open/close for orchestral arrangement navigation.

So here are the behaviours. first of all, one item selected.
1- one left click -> select item
2- double click -> open item in midi editor
3- editability it enabled
I guess this is the default Reaper behaviour.

newt, Midi editor is closed. Select multiple items :
1- double click -> open midi editor with every items selected
2- every items have editability and visibility enabled
3- double clicking a note change item selection but doesnt change editability/visibility for other items as long as those items are still selected int the arrange view.
4- selecting multiple notes over opened items (right drag) should select them and make them editable whatever the item focused is in front.

Option Z shortcut should do a zoom to selected notes over items if futher items are selected/editable.

Actually, the main problem for me comes from the fact editability/visibility constantly change when i'm changing selection into the midi editor, I'm trying to find a way to keep everything visible and editable.

Can your script does this ?
daeavelwyn 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:40 AM.


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