ReaScripts (скрипты для Reaper) - Учимся создавать!!!

Тема в разделе "Reaper", создана пользователем Archchie, 29 дек 2017.

  1. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    Учимся создавать скрипты ,анализируя чужие!
    Выкладываем в этой теме несложные скрипты ,свои первые наработки (С подробным описанием!!!)
    А также задаем вопросы касаемые скриптов (как,что и почему)
     
    Последнее редактирование: 22 апр 2018
    Dunai, incubator и Furqat нравится это.
  2. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    ---
    MPL_function ShowChildrenInMCP
    PHP:
    function ShowChildrenInMCP(tris_show)
      
    local _,tr_chunk reaper.GetTrackStateChunk(tr,'',true)
      
    local BUSCOMP_var1 tr_chunk:match('BUSCOMP (%d+)')
      
    local tr_chunk_out tr_chunk:gsub('BUSCOMP '..BUSCOMP_var1..' %d+''BUSCOMP '..BUSCOMP_var1..' '..(is_show and or 1))
      
    reaper.SetTrackStateChunk(trtr_chunk_out,true)
    end

    tr 
    reaper.GetTrack(0,0)
    ShowChildrenInMCP(trtrue)

    ---
    ⋄⋄⋄⋄⋄⋄⋄⋄⋄⋄⋄⋄⋄⋄⋄⋄⋄
    Select all tracks, Unselect all tracks__________[Archie]
    PHP:
    --Select all tracksUnselect all tracks

    reaper
    .PreventUIRefresh(1)--замораживаем GUI
    counttracks 
    reaper.CountTracks(0)  -- даёт значение кол-ва треков (кроме Мастера)
    if 
    counttracks == 0 then return end -- если треков нетостановить скрипт
    for i=1counttracks  do  -- создаём цикл опроса по каждому треку (кроме Мастера)
       
    local track reaper.GetTrack(0i-1) -- получаем объект Медиа Трек для каждого порядкового номера трека (кроме Мастера)
       
    reaper.SetMediaTrackInfo_Value(track"I_SELECTED"1) -- выделям трек (если 1 то выделитьесли 0 снять выделение)
    end
    reaper
    .PreventUIRefresh(-1)--размораживаем GUI

    Удалить выделенные треки__________[Archie]

    PHP:
    --Удалить выделенные треки

    reaper
    .Undo_BeginBlock()--для тогочтобы можно было отменить действие(Ctrl+Z)
      
    kolichestvo reaper.CountSelectedTracks) --получаем кол-ва выделенных треков (кроме Мастера)
      for 
    1,kolichestvo do                     --создаём цикл опроса по каждому выделенному треку (кроме Мастера)
      
    local track reaper.GetSelectedTrack(0,0)  --Получаем выбранный трек из проекта
       
    if  track ~= 0 then                       --Если трек выдылен то
       reaper
    .DeleteTracktrack )              --удаляем трэк
       end
      end
    reaper
    .Undo_EndBlock("Delete select track",1)--завершаем действие отменить действие(Ctrl+Z)
    Оригинал
    Код:
    
    if update_gfx then -- cначала определяем триггер, по которому в какой-либо из буферов будет писаться графика
    gfx.dest = 1 -- номер буфера 1..32 (кажется)
    gfx.setimgdim(1, -1, -1) -- этим я сбрасываю графику внутри этого буфера, иначе она будет писаться поверх того, что уже есть
    gfx.setimgdim(1, w, h) -- определяем размеры записываемой графики
    gfx.a = 1
    gfx.rect(0,0, w,h) -- рисуем что требуется
    end
    
    
    gfx.dest = -1 -- -1 - это основной слой
    gfx.a = 1 -- альфа для буферов
    gfx.blit(1, 1, 0, -- этим вытаскиваем первый буфер и сразу его переворачиваем/обрезаем/сжимаем при необходимости
    0,0,w,h,
    0,0,w,h,0,0)
    
    
     
    Последнее редактирование: 30 сен 2018
    Furqat нравится это.
  3. EUGEN27771

    EUGEN27771 Well-Known Member

    Регистрация:
    23 апр 2010
    Сообщения:
    2.321
    Симпатии:
    1.963
    Пол:
    Мужской
    Интересно. Я думаю, Александр не будет против, если я кое-что выложу из переписок.
    Это ох..но интересная информация.
    --[[
    Все графические ф-и и переменные собраны в таблице gfx.
    Их немного, но они позволяют сделать достаточно серьезные графические интерфейсы.
    С оговоркой - обычно всем обломно этим заниматься, а мне в первую очередь:)

    Рисовать строки, фигуры, картинки и прочее очень просто.
    Это вообще не стоит объяснения.
    Труднее все это дело сделать активным, заставить реагировать на мышь.
    Для этого нам нужно знать, какая конкретно кнопка мыши была нажата и ее координаты.
    Координаты - можно посмотреть напрямую(gfx.mouse_x, gfx.mouse_y).
    Какая кнопка - можно узнать через gfx.mouse_cap.
    Поэтому мы и решили легализовать ганжу...точнее - сделать маленький маленький пример.
    Нужно разобраться с mouse_cap.
    mouse_cap
    Вы видели gfx.mouse_cap&1, gfx.mouse_cap&2 и тп.
    Каждый бит соответствует опр. кнопке. Кнопка нажата - бит установлен в 1, отпущена - бит сброшен в 0.
    Побитовое "И"(&) - используется, чтобы узнать состояние бита, и кнопки соответственно.
    --]]
    PHP:
    --------------------------------------------------
    -- 
    Ф-я инициализирует gfx-окно с заданными параметрами
    -- Кроме тогоустановим шрифткоторый будем использовать
    function Init()
      
    local name,width,height,dockstate,xpos,ypos "Test"10002000200200
      gfx
    .init(name,width,height,dockstate,xpos,ypos)
      
    local fontidxfontfacefontszfontflags 1"Verdana"20
      gfx
    .setfont(1,"Verdana",20) -- set font 1
    end

    --------------------------------------------------
    -- 
    Здесь будем рисовать каждый кадрв дефолтный framebuffer
    -- Описываю подробно встречающиеся ф-ихотя все это в документации
    function Draw()
      -- 
    Информационная строка -------------
      
    gfx.set(1,0.6,1,1) -- r,g,b,aустанавливаем цветкоторым будем рисовать info
      gfx
    .xgfx.1010 -- устgfx.xgfx.yстроки рисуются отталкиваясь от этих координат!
      
    local info "Внутри окна нажмите правую, левую кнопку мыши, Alt, Ctrl, Shift, нажмите все одновременно."
      
    gfx.drawstr(info)
     
     
      -- 
    Иллюстрация -----------------------
      
    gfx.set(1,0.7,0.4,1) -- цветкоторым будем рисовать иллюстрацию
      
    -- Текущее значение mouse_cap --
      
    gfx.xgfx.1080
      gfx
    .drawstr("mouse_cap = " .. gfx.mouse_cap)
     
      
    local x90080 -- начальные координатырисовать будем справа налевоот младшего к старшим разрядам
      local w
    4040  -- здесь зададим ширину и высоту квадратиковсоответствующих разрядам
     
      
    for 015do -- будем идти от нулевогодо 15 разрядаВ Lua счет от единицыно нам здесь удобнееникто не запрещает!
        
    gfx.rect(xywh0) -- рисуем квадратиксоотвразряду
        
    -- над квадратиком номер разряда
        gfx
    .xgfx.x-- устgfx.xgfx.y
        
    -- от gfx.xgfx.говорил вышено...здесь тоже есть возможность выравниванияопять жеиспользуются флаги!!!
        
    gfx.drawstr(tostring(i), 5gfx.wgfx.h) -- над квадратиком номер разрядаflags 5!
        ------------------------------
        -- 
    вот здесь мы создадим битовую маску
        local Mask 
    1<<-- с помощью сдвига влево("<<"устанавливаем один конкретный бит
        
    if gfx.mouse_cap&Mask ~= 0 then -- с помощью побитового "И"("&"проверяемустановлен ли этот бит в mouse_cap
          
    -- в квадратике значение маски
          gfx
    .xgfx.xy
          gfx
    .drawstr(tostring(Mask), 5gfx.wgfx.h)
        
    end
        
    ------------------------------
        
    w
      end

    end


    --------------------------------------------------
    -- 
    Оснлуп будет вызывать ф-ю Draw() примерно 30 раз в секундупока gfx-окно открыто
    function mainloop()

      ---------------
      
    Draw()
      ---------------
      
    local char gfx.getchar() -- символ с клавиатурыа если =-окно gfx закрыто
      
    if char~=-1 then reaper.defer(mainloopend -- defer(пока окно открыто)
      
    gfx.update() -- обновляет кадр
    end


    --------------------------------------------------
    Init() -- Инициализируем окно
    mainloop
    () -- Запускаем оснлуп
    --- добавлено 30 дек 2017 ---
    Потом я продолжу.
     
    Archchie и dmitryga нравится это.
  4. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Есть ошибки как в синтаксисе, так и в описании и лучше их сразу разобрать и исправить.
    1. Строка -
    PHP:
    counttracks reaper.CountTracks(0)    -- даёт значение кол-ва треков
    Но в это кол-во не входит Мастер трэк
    2. Строка -
    PHP:
    if counttracks ~= nil then              -- если треков нетто и ни чего не делать
    не верно описана, да и по сути не верна. Описание должно звучать так -
    если в проекте есть хоть один трек, делать то, что дальше в коде между then и end.
    И вообще-то я не знаю при каких таких обстоятельствах counttracks будет равен nil.
    nil - это Ни Чего, а если треков в проекте нет, то counttracks будет равен НУЛЮ, а не nil,
    значит правильным будет записать -
    PHP:
    if counttracks 0 then
    Ещё для того-же (чтоб не получать ошибку кода при отсутствии в проекте объектов для которых код написан, в данном случаи для треков) пишут так -
    PHP:
    if counttracks == 0 then return end -- если треков нетостановить скрипт
    3. Строка -
    PHP:
    selecttrack reaper.GetTrack(0i-) --получаем объект Трек для каждого порядкового номера трека
    Получаемый в этой строке объект Медиа Трек не имеет ни какого отношения к select track и называть так объект не правильно! Лучше назвать track или tr.
    4. Строка -
    PHP:
    selecttrack reaper.SetMediaTrackInfo_Value(selecttrack,"I_SELECTED",1)--(выделям трек)Если 1 то выделитьЕсли 0 снять выделение
    Функции типпа Get отдают значения одного или нескольких параметров, по этому когда мы пишем в цикле -
    PHP:
    track reaper.GetTrack(0i-)
    мы каждый цикл (каждое i) получаем новое значение объекта Media Track (например).
    Функции типпа Set ни чего по сути не отдают, кроме подтверждения своего выполнения. Т.е. в этом выражении selecttrack у вас будет всегда иметь значение boolean = true.
    На самом действии выделения это ни как не скажется, но может негативно сказаться на дальнейшем ходе событий скрипта, особенно в вашем синтаксисе, когда вы переменной selecttrack в начале назначаете значение Media Track, а потом просто для всех треков true.
    5. Оправданность заморозки GUI в таком вот простом скрипте спорна, так как даже если в проекте 1 млн треков их выделение произойдёт за 1 секунду (это приблизительная скорость цикла) и врядли вы увидите последовательное мельтишение выделения.

    И ещё одно, если переменные используются только в рамках одного цикла или одной функции, то лучше их обозначать как local - это убережёт от ошибок в дальнейшем, когда по ходу скрипта одним и тем-же по названию переменным будете давать разные значения, и ускорит работу скрипта, так как с локальными переменными скрипт работает быстрее.

    Резюмируя, верный код будет выглядеть где-то так -
    PHP:
    counttracks reaper.CountTracks(0)  -- даёт значение кол-ва треков (кроме Мастера)
    if 
    counttracks == 0 then return end -- если треков нетостановить скрипт
    for i=1counttracks  do  -- создаём цикл опроса по каждому треку (кроме Мастера)
      
    local track reaper.GetTrack(0i-1) -- получаем объект Медиа Трек для каждого порядкового номера трека (кроме Мастера)
      
    reaper.SetMediaTrackInfo_Value(track"I_SELECTED"1) -- выделям трек (если 1 то выделитьесли 0 снять выделение)
    end
    В общем, ошибки в каждой строке :)
     
    Последнее редактирование: 30 дек 2017
    Archchie нравится это.
  5. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    @Aleksandr Oleynik, Спасибо!Все внятно,понятно разъяснили.
     
  6. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    @Aleksandr Oleynik, я, конечно, пока в этом почти нибумбум, но глядя на этот код, я бы его сократил вообще до трех строк и выкинул совершенно лишние проверки и переменные.
    Код:
    for i=0, reaper.CountTracks(0)-1 do
      reaper.SetMediaTrackInfo_Value(reaper.GetTrack(0, i), "I_SELECTED", 1)
    end
    
     
  7. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    @Alex_V,
    цикл в LUA начинать с Нуле (i=0) нельзя, хотя это может и работать.
    Проверять, есть ли в проекте объект, с которым скрипт должен работать, обязательно нужно, потому как это освободит Рипер от не нужных вычислений - как минимум, а часто - от выдачи скриптом ошибки.
    А так - я могу ещё пару вариантов предложить для этого конкретного случая -
    PHP:
    for i=1reaper.CountTracks(0) do
      
    reaper.SetTrackSelectedreaper.GetTrack(0i-1), )
    end
    Могу вообще одной строкой предложить записать с тем-же эффектом -
    PHP:
    reaper.Main_OnCommand(40296,0)
    Но тема то называется -
    Учиться нужно начиная с азбуки.
    Азбука понятнее, когда она последовательно и понятно изложена.
    Нет цели сделать скрипт из меньших строк, есть цель сделать его легко читаемым, чтоб вы потом, когда в скрипте будет 1000 строк, разобрались в нём сами.

    И честно говоря, предложенный вами синтаксис споткнётся о первые же более сложные скрипты, когда track, как Медиа Трек нужен будет в десятке функций в цикле.
     
  8. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Эммм... Это откуда такое? Я вот в документации не нашел ничего подобного: https://www.lua.org/pil/4.3.4.html

    Это да, это нужно, но в данном случае проверка была лишней. Там просто цикл не будет выполняться, если CountTracks вернет 0.

    Когда это будет нужно, тогда и надо переменные заводить. Извиняюсь конечно, но в данном случае это просто было создание сущностей (объявление переменных) без должной на то необходимости.
     
  9. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Не знаю, не искал - но ни у кого нет циклов с i=0, да и как-то привычнее понимать, что кол-во чего либо считается с еденицы. Мне более НЕ Удобно то, как это в Рипере сделанно - с нуля.
    В данном случаи и во многих других проверка лишняя, но пишешь какой-то скрипт и по ходу -- была лишней, а стала не лишней.
    @Alex_V, вы видимо знакомы с програмированием?
    А я вот абсолютно не знаком и это не мешает мне писать не примитивные скрипты для себя и для других. И те, кто пытается это делать так-же как и я - тоже програмированием занялись вот прям сейчас, так как в Рипере это полезно.
    Так что для учёбы очень хорошо разложить код на мельчайшие составляющие, и я уверен, что код -

    PHP:
    counttracks reaper.CountTracks(0)    -- даёт значение кол-ва треков
    if counttracks == 0 then return end -- если треков нетостановить скрипт
      
    for i=1counttracks  do                -- создаём цикл опроса по каждому треку
        track 
    reaper.GetTrack(0i-1) -- получаем объект Медиа Трек для каждого порядкового номера трека
        reaper
    .SetMediaTrackInfo_Value(track"I_SELECTED"1) -- выделям трек (если 1 то выделитьесли 0 снять выделение)
      
    end
    end
    на много более понятен новичку, чем то, что написали вы -
    PHP:
    for i=0reaper.CountTracks(0)-do
      
    reaper.SetMediaTrackInfo_Value(reaper.GetTrack(0i), "I_SELECTED"1)
    end
    Ваш код даже откоментировать крайне тяжело.
     
    Последнее редактирование: 30 дек 2017
  10. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Ну, в Lua индексация массивов обычно - с единицы (но, в принципе, может быть с любого индекса). Поэтому, думается, и перебор индексов делают чаще с 1. Почему в Рипере индексы с нуля, это как раз понятно. Он написан на C, а там индексация с нуля. В большинстве языков программирования ровно точно так же. На деле это во многом удобнее.
     
  11. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    PHP:
     
    reaper
    .PreventUIRefresh(1)--замораживаем GUI
    reaper
    .Undo_BeginBlock() --для тогочтобы можно было отменить действие (Ctrl+Z)

    for 
    i=1,reaper.CountSelectedTracks (0) do      --создаём цикл опроса по каждому выделенному треку (кроме Мастера)
      
    tr reaper.GetSelectedTrack0)           --получаем выбранный трек из проекта (кроме Мастера)
      
    reaper.SetMediaTrackInfo_Value(tr,"I_SELECTED",0)--Снимаем выделения
    end
    kol_vo 
    reaper.CountTracks)          -- даёт значение кол-ва треков в проекте (кроме Мастера)
    if 
    kol_vo == 0 then  return end            -- если треков нетостановить скрипт
      
    for 1,kol_vo do                       --создаём цикл опроса по каждому треку в проекте (кроме Мастера)
       
    track reaper.GetTrack(0,i-1)            --получаем Трек для каждого порядкового номера трека
       item 
    reaper.CountTrackMediaItemstrack )--подсчитать количество item в треке
         
    if item == 0 then                         --если item нетто 
          reaper
    .SetMediaTrackInfo_Valuetrack"I_SELECTED")-- выделям трек
         end
      end
    for 1,reaper.CountSelectedTracks) do   --создаём цикл опроса по каждому выделенному треку (кроме Мастера)
     
    local track reaper.GetSelectedTrack0)  --получаем выбранный трек из проекта (кроме Мастера)   
     
    track reaper.DeleteTracktrack )             --удаляем трэк
    end   
    reaper
    .Undo_EndBlock("Remove all tracks with no items",1) --завершаем действие отменить действие(Ctrl+Z)     
    reaper.PreventUIRefresh(-1)--размораживаем GUI 
     
     
  12. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    @Archchie, я попытался написать то же самое, но иначе. Получилось так:
    Код:
    reaper.PreventUIRefresh(1)
    reaper.Undo_BeginBlock()
    
    for i = reaper.CountTracks(0) - 1, 0, -1 do
      local track = reaper.GetTrack(0,i)
      if reaper.GetTrackMediaItem(track, 0) == nil then
        reaper.DeleteTrack(track)
      end
    end
    
    reaper.Undo_EndBlock("Remove all tracks with no items",1)
    reaper.PreventUIRefresh(-1)
    
    
    Отличия:
    1. Выделение не снимается.
    2. Нам не нужен подсчет MediaItem на треке, достаточно попытаться получить первый. Если там nil, то трек пустой
    3. Удаление сразу после того, как нашли пустой трек
    4. Цикл по трекам - в обратную сторону, от последнего к первому, для того, чтобы не получалось так, что обращаемся по индексу к треку, который уже удалили
     
    Aleksandr Oleynik и RJ Baker нравится это.
  13. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Я же написал - я не програмист от слова ВООБЩЕ, по этому мне с еденицы понятнее :)
     
  14. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Ну а я всего лишь попытался объяснить, откуда ноги растут. Вот и все. :) На самом деле, если лезть в программирование, то надо понимать, что там, как правило (с некоторыми исключениями), все индексируется с нуля. Но надо быть готовым к индексации любого вида.
     
    Aleksandr Oleynik нравится это.
  15. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    @Alex_V, идея с обратным отсчётом в цикле крутая своей простотой - браво!
    С точки зрения обучения, позволю себе ещё один вариант, возможно более понятный -

    PHP:
    reaper.Undo_BeginBlock()
    -- задаём параметркоторый нам поможет знать сколько треков без айтемов удаляется
    -- в процессе прохождения цикла потому как сразу смещаем порядковый номер с 1 на ноль
    -- при первом же цикле
    for i=1reaper.CountTracks(0) do
      
    i--- по сути меняем значение порядкового номера трекаотнимая от него удалённые треки
      local track 
    reaper.GetTrack(0i)
      if 
    reaper.GetTrackMediaItem(track0) == nil then -- если айтемов на треке нетто -
        
    reaper.DeleteTrack(track)
        
    c+-- при каждом циклеесли трек удаляетсямы их кол-во приплюсовываем
      end
    end
    reaper
    .Undo_EndBlock("Remove all tracks without items"1)
     
    Последнее редактирование: 30 дек 2017
  16. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    @Aleksandr Oleynik, да ничего там крутого. Сотни раз написанная операция удаления элементов из списка по условию - такие вещи на подкорке уже живут. :)
     
  17. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    У вас возможно. У меня этот вариант войдёт в используемый благодаря вам - частенько бывает нужен, но как Я его решал раньше - написал выше.
     
  18. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Не смотря на то, что ваш вариант не сильно оптимален для решения поставленной задачи, что хорошо продемонстрировал своим кодом @Alex_V, я пройдусь всё же
    по ошибкам -
    PHP:
    kol_vo reaper.CountTracks)
    item reaper.CountTrackMediaItemstrack )
    это функции отдающие кол-во, и если в первой функции вы конечно могли параметр назвать kol_vo, хотя потом сами будете вспоминать чего же это кол-во,
    то во второй item - всегда называют объект, а ни как не его кол-во!!!
    Т.е. лучше называть -
    counttrack
    countitem
    Дальше ошибка, которую вы уже делали и я вас поправил -
    функция - reaper.DeleteTrack( track ) функция из той-же серии Set - т.е. функция действия и писать -
    track = reaper.DeleteTrack( track ) нельзя и бессмысленно, так как track у вас тут быдет всегда получать значение true - т.е. подтверждение выполнения и больше ни чего,
    но если бы в коде дальше была бы функция, в которой нужно было бы с треком ещё что-то делать, то скрипт бы ваш НЕ РАБОТАЛ, так как вы полученный
    функцией track = reaper.GetTrack(0,i-1) Медиа Трек затёрли бы значением true.
     
  19. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    С точки зрения обучения изменять счетчик цикла внутри тела цикла - моветон. В некоторых компилируемых языках такое даже не компилируется.
     
    Aleksandr Oleynik нравится это.
  20. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Отлично - прислушаюсь к мнению программиста и делать этого впредь не стану, собственно и не делал ни когда - не было необходимости!
    А вот проход цикла в обратном направлении уже несколько раз был нужен и я тут по горячим следам, благодаря вам, в текущей своей работе поменял вот этот вот код -
    PHP:
        index_k 0
        
    if IndexUp IndexDown then
          
    for i=1#RegionName do
            
    if RegionName[i].Index IndexUp and <= IndexDown then
              prevIndex 
    IndexDown index_k
              RegionName
    [prevIndex].SongName RegionName[prevIndex-1].SongName
              index_k 
    index_k+1
            end
          end
          RegionName
    [IndexUp].SongName SongNameDown
        end
    (По сути делал тоже обратный отсчёт в цикле, но теперь понимаю - через задницу - ещё раз спасибо!)

    На вот такой -
    PHP:
        if IndexUp IndexDown then
          
    for i=#RegionName, 1, -1 do
            
    if RegionName[i].Index IndexUp and <= IndexDown then
              RegionName
    [i].SongName RegionName[i-1].SongName
            end
          end
          RegionName
    [IndexUp].SongName SongNameDown
        end
    (Теперь же это стало красиво, без лишних глобальных переменных :))

    Делаю свой первый скрипт с GUI, у Жени (@EUGEN27771) вот учусь.
    Нужно было сделать визуализацию (и перезапись в таблице) перетаскивания композиции с большим порядковым номером на меньший со сдвижкой всех композиций в очереди.
    И та-же фигня - поскольку перезапись происходит верхнего по рангу элемента в нижний, при классическом цикле первым затирался верхний и брать данные уже было негде, во всяком случаи за один цикл сделать это можно было вот только ТАК - пройдясь по циклу в обратном порядке.
    GUI TEST 8.gif
     
    Последнее редактирование: 30 дек 2017
  21. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Я чуть ещё подумал - а я ведь там не меняю счётчик цикла, он как отсчитывал от i=1 до reaper.CountTracks(0), так и отсчитывает.
    Я там меняю в цикле индекс трека, смещая его на кол-во удалённых треков.
    Я ведь мог и не перезаписывать i в цикле, а написать новую переменную - y = i-c например, и брать Медиа Трек по y, а не по i
     
    Последнее редактирование: 30 дек 2017
  22. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Можно так, а можно и цикл другого типа - не со счетчиком, а while (работать будет слегка медленнее). Но цикл от конца в начало списка получается проще для понимания и в реализации. Тут главное - понять проблему, которая возникает при удалении элементов, если идти по списку от начала и при этом удалять из него элементы.
     
  23. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    100%
     
  24. EUGEN27771

    EUGEN27771 Well-Known Member

    Регистрация:
    23 апр 2010
    Сообщения:
    2.321
    Симпатии:
    1.963
    Пол:
    Мужской
    Цикл всегда с нуля. Это в луа с единицы
     
  25. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Но тогда вся система исчислений должна начинаться с нуля.
    Иначе получается бред - функция подсчёта кол-ва треков выдает число 3 и это значит что треков ТРИ, а не ЧЕТЫРЕ, как если бы исчисление начиналось с нуля.
    Да и с нулём и в других местах не всё в порядке -
    В документации по LUA написанно, что nil - это ноль, тогда почему функции подсчёта треков, айтемов, FX-ов, если ИХ нет совсем выдают НОЛЬ, а не nil и если в выражениях, использующих эти данные написать не НОЛЬ, а nil - они работать не будут.
    Мне лично было бы понятнее и логичнее, если бы НОЛЬ это действительно был nil - ничего, т.е. отсутствие.

    Но с другой стороны, я уже понимаю отличие nil от нуля - nil это как бы вообще ни чего не заданно, свободная ячейка памяти у параметра....., а НОЛЬ, это уже какие то данные.
     
    Последнее редактирование: 31 дек 2017
  26. vitalker

    vitalker Well-Known Member

    Регистрация:
    8 окт 2013
    Сообщения:
    3.053
    Симпатии:
    1.181
    Адрес:
    Гродно
    @Aleksandr Oleynik, потому что по умолчанию целочисленным переменным присваивается ноль. А nil - это, по-моему, тип данных.
    UPD: ну да - я был прав: https://www.lua.org/pil/2.1.html
    Не может же переменная одного типа принять значение другого типа или может? А, Александр?
     
  27. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Не до конца понимаю что такое тип данных и к какому типу относится nil, но переменной, которая было равна НУЛЮ, я запросто значение nil могу присвоить.
     
  28. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Нет, не должна. Не надо путать количество элементов, номер элемента в списке и его индекс. Количество элементов в списке, если он не пуст, больше нуля. Индекс элемента в списке - это не его порядковый номер, это способ адресации элементов. Это, кстати, может вообще не числом быть (в ассоциативном массиве, например).

    Насчет nil. На мой взгляд проще это воспринимать, как специальное значение, означающее отсутствие данных.
     
  29. vitalker

    vitalker Well-Known Member

    Регистрация:
    8 окт 2013
    Сообщения:
    3.053
    Симпатии:
    1.181
    Адрес:
    Гродно
  30. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Так в вашем же примере первом вы кол-во элементов задали с нуля (ноль у вас тоже был еденицей измерения) - иначе ваш цикл с нуля и не заработал бы.
    Т.е. в цикле с i=0 при ОДНОМ треке в проекте counttrack = 0, иначе это не заработает.
    Я это знаю. В Lua таблицах индекс это ключ и он может быть хоть объектом, хоть функцией, хоть таблицей.
    Да. Так и воспринимаю.

    Но вот кажется мне, что для МОЕГО обучения обсуждение очень даже в кассу, но вот для новичков - сомневаюсь.... Им бы в общем до таблиц дойти и познакомится с их разновидностями, а уж потом разбиратся с индексами, ключами и пр...
     
  31. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Я нигде не задавал количество элементов. Я запрашивал количество элементов и делал цикл по их индексам. И при одном треке CountTracks конечно же вернет единицу.

    Знаете, мне кажется, что для новичка полезнее понимание, того, как оно на самом деле сразу, а не потом, чтобы после когнитивный диссонанс не наступал.
     
  32. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Вообще то вы задали кол-во элементов. Вы запросили кол-во треков, в проекте из двух треков (например) получили значение 1, и потом задали кол-во как 1-1, т.е. ноль.
    А если бы вы единицу поставите как кол-во треков в цикл их опроса, где i=0, то получите вместо одного цикла (что было бы логично) - два. Вот и неувязочка...
    Согласен, я же только за, если кто-то, с реальными знаниями програмирования, будет следить за этой темой и указывать на ошибки.
    Но не дойдя в обучении до таблиц разбираться с индексами и ключами на мой взгляд ошибка.
    Хотя..., может и нормально. Вот про nil мы уже практически все разобрали.
     
    Последнее редактирование: 31 дек 2017
  33. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Нет. Я запросил количество элементов (треков в проекте). В проекте из двух треков их будет, сюрпрайз, два. Это значение и возвращается. Затем создается цикл который проходит по индексам от нуля до 1 (количество треков - 1). То есть цикл выполнится два раза - для индекса 0 и для индекса 1. Если в проекте 1 трек то цикл выполняется один раз - для индекса 0. Если в проекте треков нет то второй параметр цикла равен минус единице и он не выполняется ни разу. У меня никаких неувязок.
     
    Aleksandr Oleynik нравится это.
  34. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    Разобрался как ваш скрипт сделан,но вот возник вопрос!
    Если цикл от количества до 0 то скрипт работает, а от 0 до количества не работает,почему?
     
  35. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Так объяснил @Alex_V почему в первом же посте по этому скрипту -
    Если цикл от 0 до кол-ва, значит движемся по трекам от первого к последнему. Как только дойдём до трека без айтема - мы его удалим и треков станет на один меньше и их индексы сдвинутся на один и цикл сломается.
    А когда движемся от последнего по индексу трека (который собственно и равен кол-ву треков в проекте минус 1 (ну вот нумерация в Рипере не с 1, а с 0) - тогда мы удаляем трек, который в цикле дальнейшем уже не участвует.
     
    Archchie нравится это.
  36. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Потому, что при удалении происходит смещение индексов треков, которые до удаления имели индекс, больше, чем удаляемый.
    Попробую разобрать на примере.
    Допустим у нас есть пять треков (с индексами от 0 до 4), из них надо удалить треки 2 и 3 ( с индексами 1 и 2 соответственно). Треки имеют имена Track1, Track2 и т.д.
    Рассматривать буду только те шаги цикла, которые влияют на работу.

    Проход от начала списка.
    шаг 1- не рассматриваю

    На втором шаге (i = 1) мы должны удалить Track2
    Список треков до удаления Track2:
    Track1(индекс = 0)
    Track2(индекс = 1)
    Track3(индекс = 2)
    Track4(индекс = 3)
    Track5(индекс = 4)

    Список треков после удаления Track2:
    Track1(индекс = 0)
    Track3(индекс = 1)
    Track4(индекс = 2)
    Track5(индекс = 3)

    Видно, что у треков Track3...Track5 изменились индексы, поэтому на третьем шаге цикла (i=2) мы будем проверять в результате не Track3, а Track4. Поэтому Track3 удален не будет. Более того, когда цикл дойдет до пятого шага (i=4), то возникнет ошибка. Она возникнет потому, что будет запрошен трек с индексом больше максимального.

    Проход от конца списка
    шаги 1 (i = 4) и 2 (i = 3) не рассматриваю/


    На шаге третьем шаге цикла (i=2) мы удаляем Track3
    Список треков до удаления Track3:
    Track1(индекс = 0)
    Track2(индекс = 1)
    Track3(индекс = 2)
    Track4(индекс = 3)
    Track5(индекс = 4)

    Список треков после удаления Track3:
    Track1(индекс = 0)
    Track2(индекс = 1)
    Track4(индекс = 2)
    Track5(индекс = 3)

    На четвертом шаге цикла (i=1) мы удаляем Track2
    Список треков до удаления Track2:
    Track1(индекс = 0)
    Track2(индекс = 1)
    Track4(индекс = 2)
    Track5(индекс = 3)

    Список треков после удаления Track2:
    Track1(индекс = 0)
    Track4(индекс = 1)
    Track5(индекс = 2)

    На пятом шаге цикла (i=0) будет проверен Track1 и цикл благополучно завершит работу.
    --- добавлено 1 янв 2018 ---
    На самом деле это данное мною описание немного неверное. Там возникает не только эта проблема. Еще будут пропускаться элементы, пример выше.
     
    Archchie и Aleksandr Oleynik нравится это.
  37. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Я не стал свои сомнения описывать, но вы уточнили - и это круто! Проблема, что мы обращаемся по индексу к треку которого нет, возникает не после первого удалённого трека, а в конце - как вы и уточнили (СПАСИБО за уточнение, хорошо когда голова полностью ясная!), ну и пропуски треков из-за смещения индекса на удалённый трек...
    И мой пример вот этот -
    http://rmmedia.ru/threads/130417/#post-2191941
    как раз и устранял не соответствие заданного изначально кол-ва циклов и номеров индексов, и по ходу и в конце.
    Но вы описали в примере круто!
    --- добавлено 1 янв 2018 ---

    Кстати, вот на этой же задаче простой, можно рассмотреть работу с таблицами.
    Вот скрипт, который делает тоже самое и первоначальный цикл мы можем использовать прямой (а не в обратную сторону).
    Пример чисто для начала изучения таблиц (без которых более-менее сложные скрипты писать не получиться), и понятно, что пример ниже ни в какое сравнение с простым скриптом с обратным циклом не идёт.

    PHP:
    Tracks = {} -- объявляем таблицу

    for i=1reaper.CountTracks(0) do
      
    local DeleteTrack -- объявляемчто переменная будет локальной в цикле
      DeleteTrack 
    false -- объявляем что переменнаяесли ни чего другого в цикле не произойдёт false
      local track 
    reaper.GetTrack(0i-1)
      if 
    reaper.GetTrackMediaItem(track0) == nil then
        DeleteTrack 
    true -- если на треке айтемов нетменяем значение переменной на true для этого конкретного цикла (Медиа Трека)
      
    end
      Tracks
    [track] = DeleteTrack -- записываем в таблицу ключ track и его значение (false или trueв каждом цикле
    end

    for trdel_track in pairs(Tracks) do -- форма цикла прохода по таблицам с ключами переменными (не простыми индексами)
      if 
    del_track then -- если значение ключа track true (== true можно не писать)
        
    reaper.DeleteTrack(tr) -- удаляем такой трек вписывая этот ключ как Медиа Трек
      end
    end

    -- del_track это переменная с теми значениямикоторые мы брали в предидушем цикле из DeleteTrack
    -- tr это ключ который записан как Медиа Трек из пред цикла и брали его из track
     
    Последнее редактирование: 1 янв 2018
  38. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Ну да. Но, в принципе, если рассматривать как конечную цель именно удаление треков по заполненному в первом проходе списку, то тут можно было, я так думаю, сильно упростить процесс, если в этот список добавлять только те треки, которые подлежат удалению и потом обходиться без анализа del_track. Но в качестве именно примера работы с таблицами - вполне годится.

    Собственно, это пример является в некотором роде вариацией на тему того, что изначально было написано @Archchie, но там в качестве маркера для удаления было свойство трека I_SELECTED.
     
    Aleksandr Oleynik нравится это.
  39. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    Подскажите, а то не могу вкурить. Получил выделенный трек ( reaper.GetSelectedTrack(0,0) ) и как выделить следующий трек ?
     
  40. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Нужен скрипт - SetSelectedNextTrack?

    PHP:
    for i=1reaper.CountTracks(0) do
      if 
    reaper.GetMediaTrackInfo_Value(reaper.GetTrack(0,i-1), "I_SELECTED") == and reaper.CountTracks(0then
        reaper
    .SetMediaTrackInfo_Value(reaper.GetTrack(0,i-1), "I_SELECTED")
        
    reaper.SetMediaTrackInfo_Value(reaper.GetTrack(0,i), "I_SELECTED")
        break
      
    end
    end
     
    Последнее редактирование: 2 янв 2018
    Archchie нравится это.
  41. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    @Aleksandr Oleynik,
    Этот код не работает с несколькими треками, может переделаете?И если можно с описанием,
    а то смотрю на вторую строку и не понимаю что, как и почему.
     
    Последнее редактирование: 3 янв 2018
  42. @Michael

    @Michael Well-Known Member

    Регистрация:
    14 дек 2010
    Сообщения:
    840
    Симпатии:
    1.264
    Пол:
    Мужской
    Адрес:
    Орёл / Москва
    PHP:
    tr reaper.GetSelectedTrack(0,0) -- взять указатель первого выделенного трека
    if tr then -- если существует первый выделенный трек
      nexttrack_ID 
    reaper.CSurf_TrackToIDtrfalse ) + 1-- найти его порядковый номер единицу для номера следующего
      tr2 
    reaper.CSurf_TrackFromIDnexttrack_IDfalse) --взять указатель следующего трека исходя из его порядкого номера
    end
    if tr2 then -- если следующий за выделенным трек найденвыделить только следующий трек
      reaper
    .SetOnlyTrackSelected(  tr2 ,false )
    end
     
    Archchie и Aleksandr Oleynik нравится это.
  43. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    @@Michael, Этот код тоже не работает с несколькими треками
     
  44. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    А как вы хотите чтоб работал при двух выделенных треках, если они выделены через один?
    Опишите.
     
  45. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    351
    Симпатии:
    174
    Пол:
    Мужской
    222.gif
     
  46. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    @Archchie, примерно так:

    Код:
    PrevTrack = nil
    
    for i = reaper.CountTracks( 0 )-1, 0, -1 do
      local track = reaper.GetTrack(0,i)
      if reaper.GetMediaTrackInfo_Value(track, "I_SELECTED") == 1 and PrevTrack ~= nil then
        reaper.SetMediaTrackInfo_Value(PrevTrack, "I_SELECTED", 1)
      end
      reaper.SetMediaTrackInfo_Value(track, "I_SELECTED", 0)
      PrevTrack = track
    end
    
     
    Archchie и Aleksandr Oleynik нравится это.
  47. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Не могу найти простого примера интеграции png картинки в GUI, чтоб понять синтаксис.
    PS: Как просто нарисовать картинку в GUI я уже разобрался, нужно теперь научиться нарисовать картинку имеющую ни один фрэйм :(
    И тут у меня уже котелок задымился по примерам разбираться, потому как в них все данные по таблицам собирают, а уже потом достают - и я поплыл,,,,,,,,,
    Мне бы структуру формирования и использования ОДНОЙ картинки с тремя фрэймами понять - а уж потом это всё по таблицам....
     
    Последнее редактирование: 4 янв 2018
  48. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    А где можно вообще примеров посмотреть?

    Но мне вообще странно наблюдать, что Reaper, предоставляя достаточно богатый API, ничего не делает для стандартизации скриптового GUI.
     
  49. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    16.898
    Симпатии:
    9.158
    Пол:
    Мужской
    Адрес:
    Киев
    Поскольку написать нормальный GUI раза в три сложнее, чем саму рабочую часть скрипта, и тем более с подгружаемыми png-шками, то скриптов подобных раз-два и обчёлся...
    Самый крутой наверное это Женин FXRack (по функционалу так вообще круть неимоверная) -
    https://forum.cockos.com/showthread.php?t=195417
    Собственно Женя в этой теме отметился тоже -
    http://rmmedia.ru/threads/130417/#post-2191678
    но думаю, что кроме Миши и меня о чём он, мало кто что понял.
    начинать нужно всё-же обучение с простейших примеров, а потом уже нюансы с функциями мыши и прочее разбирать.
    Что такое стандартизации скриптового GUI? Все стандартные элементы есть и встроенны в API и с ними я более-менее разобрался.
    Да и у Жени есть удобный скрипт -
    https://github.com/EUGEN27771/ReaScripts/tree/master/Templates/GUI
    2018-01-05_141508.png
    Пока у меня проблема с внешними подгружаемыми пногофрэймовыми png-шками.
     
    Последнее редактирование: 5 янв 2018
  50. Alex_V

    Alex_V Active Member

    Регистрация:
    12 апр 2017
    Сообщения:
    337
    Симпатии:
    138
    Пол:
    Мужской
    Ну вот чтобы не нужно было ваять на Lua библиотеки для реализации гуя.

    Пока я вижу, что если кто хочет хоть какой-то гуй в скрипте, он его рисует сам, как может. Либо какую-то готовую библиотеку на Lua (разной степени убогости) использует. Это означает только одно - никаких стандартных элементов нет. И поэтому, в частности, приходится разбираться, как с подгружаемыми png-шками работать.
     

Поделиться этой страницей