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

Так в вашем же примере первом вы кол-во элементов задали с нуля (ноль у вас тоже был еденицей измерения) - иначе ваш цикл с нуля и не заработал бы.
Т.е. в цикле с i=0 при ОДНОМ треке в проекте counttrack = 0, иначе это не заработает.
Я нигде не задавал количество элементов. Я запрашивал количество элементов и делал цикл по их индексам. И при одном треке CountTracks конечно же вернет единицу.

Им бы в общем до таблиц дойти и познакомится с их разновидностями, а уж потом разбиратся с индексами, ключами и пр...
Знаете, мне кажется, что для новичка полезнее понимание, того, как оно на самом деле сразу, а не потом, чтобы после когнитивный диссонанс не наступал.
 
Я нигде не задавал количество элементов. Я запрашивал количество элементов и делал цикл по их индексам. И при одном треке CountTracks конечно же вернет единицу.
Вообще то вы задали кол-во элементов. Вы запросили кол-во треков, в проекте из двух треков (например) получили значение 1, и потом задали кол-во как 1-1, т.е. ноль.
А если бы вы единицу поставите как кол-во треков в цикл их опроса, где i=0, то получите вместо одного цикла (что было бы логично) - два. Вот и неувязочка...
Знаете, мне кажется, что для новичка полезнее понимание, того, как оно на самом деле сразу, а не потом, чтобы после когнитивный диссонанс не наступал.
Согласен, я же только за, если кто-то, с реальными знаниями програмирования, будет следить за этой темой и указывать на ошибки.
Но не дойдя в обучении до таблиц разбираться с индексами и ключами на мой взгляд ошибка.
Хотя..., может и нормально. Вот про nil мы уже практически все разобрали.
 
Последнее редактирование:
Вообще то вы задали кол-во элементов. Вы запросили кол-во треков, в проекте из двух треков (например) получили значение 1, и потом задали кол-во как 1-1, т.е. ноль.
А если бы вы единицу поставите как кол-во треков в цикл их опроса, где i=0, то получите вместо одного цикла (что было бы логично) - два. Вот и неувязочка...
Нет. Я запросил количество элементов (треков в проекте). В проекте из двух треков их будет, сюрпрайз, два. Это значение и возвращается. Затем создается цикл который проходит по индексам от нуля до 1 (количество треков - 1). То есть цикл выполнится два раза - для индекса 0 и для индекса 1. Если в проекте 1 трек то цикл выполняется один раз - для индекса 0. Если в проекте треков нет то второй параметр цикла равен минус единице и он не выполняется ни разу. У меня никаких неувязок.
 
  • Like
Реакции: Aleksandr Oleynik
PHP:
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)
Разобрался как ваш скрипт сделан,но вот возник вопрос!
Если цикл от количества до 0 то скрипт работает, а от 0 до количества не работает,почему?
 
Если цикл от количества до 0 то скрипт работает, а от 0 до количества не работает,почему?
Так объяснил @Alex_V почему в первом же посте по этому скрипту -
4. Цикл по трекам - в обратную сторону, от последнего к первому, для того, чтобы не получалось так, что обращаемся по индексу к треку, который уже удалили
Если цикл от 0 до кол-ва, значит движемся по трекам от первого к последнему. Как только дойдём до трека без айтема - мы его удалим и треков станет на один меньше и их индексы сдвинутся на один и цикл сломается.
А когда движемся от последнего по индексу трека (который собственно и равен кол-ву треков в проекте минус 1 (ну вот нумерация в Рипере не с 1, а с 0) - тогда мы удаляем трек, который в цикле дальнейшем уже не участвует.
 
  • Like
Реакции: Archie's
Если цикл от количества до 0 то скрипт работает, а от 0 до количества не работает,почему?
Потому, что при удалении происходит смещение индексов треков, которые до удаления имели индекс, больше, чем удаляемый.
Попробую разобрать на примере.
Допустим у нас есть пять треков (с индексами от 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 и цикл благополучно завершит работу.
[DOUBLEPOST=1514835323][/DOUBLEPOST]
в обратную сторону, от последнего к первому, для того, чтобы не получалось так, что обращаемся по индексу к треку, который уже удалили
На самом деле это данное мною описание немного неверное. Там возникает не только эта проблема. Еще будут пропускаться элементы, пример выше.
 
На самом деле это данное мною описание немного неверное. Там возникает не только эта проблема.
Я не стал свои сомнения описывать, но вы уточнили - и это круто! Проблема, что мы обращаемся по индексу к треку которого нет, возникает не после первого удалённого трека, а в конце - как вы и уточнили (СПАСИБО за уточнение, хорошо когда голова полностью ясная!), ну и пропуски треков из-за смещения индекса на удалённый трек...
И мой пример вот этот -
http://rmmedia.ru/threads/130417/#post-2191941
как раз и устранял не соответствие заданного изначально кол-ва циклов и номеров индексов, и по ходу и в конце.
Но вы описали в примере круто!
[DOUBLEPOST=1514836832][/DOUBLEPOST]
Кстати, вот на этой же задаче простой, можно рассмотреть работу с таблицами.
Вот скрипт, который делает тоже самое и первоначальный цикл мы можем использовать прямой (а не в обратную сторону).
Пример чисто для начала изучения таблиц (без которых более-менее сложные скрипты писать не получиться), и понятно, что пример ниже ни в какое сравнение с простым скриптом с обратным циклом не идёт.

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

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

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

-- del_track это переменная с теми значениями, которые мы брали в предидушем цикле из DeleteTrack
-- tr это ключ который записан как Медиа Трек из пред цикла и брали его из track
 
Последнее редактирование:
Кстати, вот на этой же задаче простой, можно рассмотреть работу с таблицами.
Ну да. Но, в принципе, если рассматривать как конечную цель именно удаление треков по заполненному в первом проходе списку, то тут можно было, я так думаю, сильно упростить процесс, если в этот список добавлять только те треки, которые подлежат удалению и потом обходиться без анализа del_track. Но в качестве именно примера работы с таблицами - вполне годится.

Собственно, это пример является в некотором роде вариацией на тему того, что изначально было написано @Archchie, но там в качестве маркера для удаления было свойство трека I_SELECTED.
 
  • Like
Реакции: Aleksandr Oleynik
Подскажите, а то не могу вкурить. Получил выделенный трек ( reaper.GetSelectedTrack(0,0) ) и как выделить следующий трек ?
 
как выделить следующий трек ?
Нужен скрипт - SetSelectedNextTrack?

PHP:
for i=1, reaper.CountTracks(0) do
  if reaper.GetMediaTrackInfo_Value(reaper.GetTrack(0,i-1), "I_SELECTED") == 1 and i < reaper.CountTracks(0) then
    reaper.SetMediaTrackInfo_Value(reaper.GetTrack(0,i-1), "I_SELECTED", 0 )
    reaper.SetMediaTrackInfo_Value(reaper.GetTrack(0,i), "I_SELECTED", 1 )
    break
  end
end
 
Последнее редактирование:
  • Like
Реакции: Archie's
@Aleksandr Oleynik,

Этот код не работает с несколькими треками, может переделаете?И если можно с описанием,
а то смотрю на вторую строку и не понимаю что, как и почему.
 
Последнее редактирование:
Этот код не работает с несколькими треками

PHP:
tr = reaper.GetSelectedTrack(0,0) -- взять указатель первого выделенного трека
if tr then -- если существует первый выделенный трек
  nexttrack_ID = reaper.CSurf_TrackToID( tr, false ) + 1-- найти его порядковый номер + единицу для номера следующего
  tr2 = reaper.CSurf_TrackFromID( nexttrack_ID, false) --взять указатель следующего трека исходя из его порядкого номера
end
if tr2 then -- если следующий за выделенным трек найден, выделить только следующий трек
  reaper.SetOnlyTrackSelected(  tr2 ,false )
end
 
А как вы хотите чтоб работал при двух выделенных треках, если они выделены через один?
Опишите.
222.gif
 
@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
 
Не могу найти простого примера интеграции png картинки в GUI, чтоб понять синтаксис.
PS: Как просто нарисовать картинку в GUI я уже разобрался, нужно теперь научиться нарисовать картинку имеющую ни один фрэйм :(
И тут у меня уже котелок задымился по примерам разбираться, потому как в них все данные по таблицам собирают, а уже потом достают - и я поплыл,,,,,,,,,
Мне бы структуру формирования и использования ОДНОЙ картинки с тремя фрэймами понять - а уж потом это всё по таблицам....
 
Последнее редактирование:
И тут у меня уже котелок задымился по примерам разбираться
А где можно вообще примеров посмотреть?

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

Все стандартные элементы есть и встроенны в API и с ними я более-менее разобрался.
Пока я вижу, что если кто хочет хоть какой-то гуй в скрипте, он его рисует сам, как может. Либо какую-то готовую библиотеку на Lua (разной степени убогости) использует. Это означает только одно - никаких стандартных элементов нет. И поэтому, в частности, приходится разбираться, как с подгружаемыми png-шками работать.
 
Ну так это значит, что место и фанфары - не заняты.
Зная, как устроены некоторые GUI фреймворки, пожалуй откажусь. У меня нет столько лишнего времени. ;) Понимаете, в том же, например, ctrlr, чтобы получить крутилку с фреймами из png, программирования надо ровно ноль. Но там да, под капотом помимо Lua еще и JUCE.


Что же касается, отрисовки в рипере готовых фреймов из картинок, то, насколько я понимаю, там особо сложного ничего нет. Вычисляются координаты фрейма внутри png и потом это всё через blit выводится.
 
там особо сложного ничего нет. Вычисляются координаты фрейма внутри png и потом это всё через blit выводится.
В общих чертах и я понял, а вот чтоб работающий скрипт сделать - так ни фига не выходит.
 
Вроде же как-то так:
Да, так, но у меня почему-то выводит полную картинку на все тре фрэйма :(
Сейчас доделаю простинький скрипт для эксперементов и выложу.

PS: Таааак, @Alex_V спасибо!
Начал чистить скрипт: чтоб выложить: и нашлась ошибка :)

Дооформлю действием мыши (чтоб нажатие мышью переключало изображение) и выложу.
 
Последнее редактирование:
Пример скрипта - GUI с подгруженной трёх фрэймовой картинкой -
GUI TEST 11.gif

PHP:
----------------------------------------------------------------------------------------------------
local msg = function(M) reaper.ShowConsoleMsg(tostring(M).."\n") end
----------------------------------------------------------------------------------------------------
function get_script_path() -- script_path and name from reaper function
  local filename = select(2, reaper.get_action_context())
  local script_path, script_name = filename:match("^(.*)[\\/](.+)")
  return script_path, script_name
end
local script_path, script_name = get_script_path()

----------------------------------------
function SetRGB(RGB, a) -- функция задания цвета прям копированием из фотошопа
 gfx.r = (RGB & 0xFF0000) / 16711680 -- 256*256*255
 gfx.g = (RGB & 0x00FF00) / 65280 -- 256*255
 gfx.b = (RGB & 0x0000FF) / 255 -- 255
 gfx.a = a or 1
end

function InitMouse()
  mouse_last_cap = 0
  mouse_down_x, mouse_down_y = 0, 0
  mouse_last_x, mouse_last_y = 0, 0
  mouse_captimer = 0
end

function Init()
  gfx.init("GUI", 120, 120, 0, 600, 200)
  SetRGB(0x0f0f0f, 0.7) -- 0f0f0f можно копи пастить из фотошопа
  gfx.rect(x, y, w, h, 1)  -- зарисовываем прямоугольник под мышкой
  img_fn = gfx.loadimg(0, script_path .. "/Images/PlayStop_60x60x3.png")
  InitMouse()
  mainloop () -- основная функция дефера
end

function GetMouse()
  -- mouse state -----------------------
  mouse_down = gfx.mouse_cap&1==1 and mouse_last_cap&1==0
  mouse_up = gfx.mouse_cap&1==0 and mouse_last_cap&1==1

  if mouse_down then mouse_down_x, mouse_down_y = gfx.mouse_x, gfx.mouse_y end
  if mouse_up then mouse_up_x, mouse_up_y = gfx.mouse_x, gfx.mouse_y end

  mouse_move = (mouse_last_x ~= gfx.mouse_x) or (mouse_last_y ~= gfx.mouse_y)
end

function UpdateMouse()
  -- update mouse last state -----------
  mouse_last_cap = gfx.mouse_cap
  mouse_last_x = gfx.mouse_x
  mouse_last_y = gfx.mouse_y
  gfx.mouse_wheel = 0
  gfx.mouse_hwheel = 0
end

----------------------------------------------------------------------------------------------------

function pointIN(px, py, x,y,w,h)
  return px >= x and px <= x + w and py >= y and py <= y + h
end
----------------------------------------
function mouseIN(x,y,w,h)
  return pointIN(gfx.mouse_x, gfx.mouse_y, x,y,w,h)
end
----------------------------------------
function mouseDown(x,y,w,h)
  return mouse_down and mouseIN(x,y,w,h)
end
----------------------------------------
function mouseUp(x,y,w,h)
  return mouse_up and mouseIN(x,y,w,h)
end
----------------------------------------
function mouseClick(x,y,w,h)
  return mouseUp(x,y,w,h) and pointIN(mouse_down_x,mouse_down_y, x,y,w,h)
end


----------------------------------------------------------------------------------------------------

curfrm = 0
function Draw ()
  x, y, w, h = 30, 30, 60, 60
  frmw, frmh, nfrms = w, h, 3

  if mouseClick(x,y,w,h) then
    curfrm = curfrm + 1
    if curfrm == 3 then
      curfrm = 0
    end
  end
  gfx.blit(img_fn, 1, 0, 0, curfrm * frmh, frmw, frmh, x,y,w,h)
end



function mainloop ()
  GetMouse()
  Draw()
  UpdateMouse()

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

----------------------------------------------------------------------------------------------------

Init() -- Инициализируем окно
В скрипте куча функций сделанных Женей.
 

Вложения

  • PlayStop_60x60x3.png
    PlayStop_60x60x3.png
    3,8 KB · Просмотры: 112
Последнее редактирование:
кто нибудь писал скрипты на питоне? какие ограничения у питона перед луа?
 
какие ограничения у питона перед луа?
Как я все это дело вижу с точки зрения новичка в рипере.
1. Питон требует установки своей среды исполнения, для Lua все встроено в рипер.
2. На питоне можно написать что-то с более продвинутым GUI. Но, в отличие от Lua не получится интегрировать этот GUI в рипер.

В остальном все работает через API рипера. Вопросы быстродействия каки-то тоже, наверное, имеют место быть, но это я не знаю. Такие вещи мерять надо.
 
@Aleksandr Oleynik, по RGB там ошибочка - недавно говорил
PHP:
----------------------------------------
function SetRGB(RGB, a)
  gfx.r = (RGB & 0xFF0000) / 16711680 -- 256*256*255
  gfx.g = (RGB & 0x00FF00) / 65280 -- 256*255
  gfx.b = (RGB & 0x0000FF) / 255 -- 255
  gfx.a = a or 1
end
----
У меня нет столько лишнего времени
Это точно. Но мы его все же сделаем. Причем в виде конструктора.
У меня есть кнопки, чекбоксы, слайдеры, кнобы, спинбоксы и менюшки в готовом виде. Все достаточно продумано.
Но разбросано там-сям - на eel, lua. Все это нужно разгрести, собрать в кучу основное, допилить, привести в порядок.
 
  • Like
Реакции: a-up

Сейчас просматривают